Skip to content

nix: add static analysis infrastructure#1

Open
randomizedcoder wants to merge 1 commit into
pr/nix-bpf-compat-samplesfrom
pr/nix-static-analysis
Open

nix: add static analysis infrastructure#1
randomizedcoder wants to merge 1 commit into
pr/nix-bpf-compat-samplesfrom
pr/nix-static-analysis

Conversation

@randomizedcoder

Copy link
Copy Markdown
Owner

Summary

  • Port static analysis framework from the reference Nix implementation, adapted for XDP2's C codebase and Make-based build system
  • 8 analysis tools at 3 levels: quick (clang-tidy + cppcheck), standard (+ flawfinder, clang-analyzer, gcc-warnings), deep (+ gcc-analyzer, semgrep, sanitizers)
  • Compilation database generated by parsing make V=1 VERBOSE=1 output (bear's LD_PRELOAD and compiledb both fail in Nix sandbox)
  • Python triage system with exemptions for cppcheck tool limitations and idiomatic C patterns (documented in EXEMPTIONS.md)

Results (analysis-quick): 18,108 raw clang-tidy + 202 cppcheck → 14 high-confidence findings after triage.

Stacks on top of PR xdp2-dev#13 (pr/nix-bpf-compat-samplesxdp2-dev:num_args).

Test plan

  • nix eval passes for all 11 analysis targets
  • nix build .#analysis-quick — clang-tidy (18,108) + cppcheck (202), 14 high-confidence
  • nix build .#analysis-standard — + flawfinder (305), clang-analyzer (141), gcc-warnings (111)
  • nix build .#analysis-flawfinder — 305 findings
  • nix build .#analysis-semgrep — 56 findings
  • nix build .#analysis-sanitizers — builds with ASan+UBSan
  • Existing targets (xdp2, xdp2-debug, tests.all) unaffected
  • make analysis convenience target

🤖 Generated with Claude Code

Port static analysis framework from the reference Nix implementation,
adapted for XDP2's C codebase and Make-based build system.

8 analysis tools at 3 levels:
- quick: clang-tidy + cppcheck
- standard: + flawfinder, clang-analyzer, gcc-warnings
- deep: + gcc-analyzer, semgrep, sanitizers

Compilation database generated by parsing `make V=1 VERBOSE=1` output
with a custom Python script, since bear's LD_PRELOAD fails in the Nix
sandbox and compiledb doesn't recognize Nix wrapper compiler paths.

Python triage system aggregates, deduplicates, and prioritizes findings
across all tools. Exemptions documented in EXEMPTIONS.md cover cppcheck
tool limitations (macro parsing, void pointer arithmetic, container_of
patterns) and high-volume style checks (narrowing conversions, reserved
identifiers, assignment-in-if) that are intentional in C networking code.

Results (analysis-quick):
  clang-tidy:  18,108 raw → 3,653 after triage
  cppcheck:    202 raw
  triage:      14 high-confidence findings

Usage:
  nix build .#analysis-quick
  nix build .#analysis-standard
  nix build .#analysis-deep
  make analysis

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
randomizedcoder added a commit that referenced this pull request Apr 20, 2026
After three sample-level workaround experiments (LOOP_COUNT={3,4} caps and
a Makefile sed-clamp on the generated `len`) all failed to verify the
IPv6 extension-header path -- each one shifted the rejection deeper into
generated/library code without converging -- record the architectural
finding and the deferred fix plan before pushing the 5/6 matrix state.

Findings:
- Two distinct unbounded-scalar patterns block verification:
  1. `len = hdr_end - hdr` in generated check_pkt_len
     (src/templates/xdp2/xdp_def.template.c:53-76)
  2. `hdr - ctrl->pkt.start` in xdp2_parse_hdr_offset
     (src/include/xdp2/parser.h:353-356)
- Sample-level patches are whack-a-mole: fixing #1 via sed regresses the
  IPv4 path by exposing #2. The fix has to live where each scalar is
  born (template + helper), not where it is consumed.

Doc updates:
- super-flow-dissector-implementation.md: expanded S9g with both
  patterns, the experiment trace (insn 142 -> 9230 -> 5065 -> 6421),
  and a sequenced next-step plan (header helper first, template
  mirror second across both C++/Pyrate and Rust/Tera, SSA cleanup
  third). Added a "Decision recorded" paragraph below the matrix
  scoreboard explaining why we ship 5/6 rather than block on S9g.
- challenges.md: new section 15 as the user-facing entry point --
  status, symptom, root cause, workaround already in flow_dissector.bpf.c,
  what was tried and rejected, and where the real fix lives.

No code changes; experiments were reverted to the c2eadcd state
(IPv4 verifies, IPv6-EH falls back to the kernel dissector via
BPF_FLOW_DISSECTOR_CONTINUE).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
randomizedcoder added a commit that referenced this pull request May 27, 2026
Bring iperf2 to parity with iperf3 across all four protocol
arms, on both NIC pairs.

Phase 4 macro matrix grows from 10 cells to 16 cells:
  - iperf3 IPv4/IPv6 TCP/UDP on each pair (8 cells unchanged)
  - iperf2 IPv4/IPv6 TCP/UDP on each pair (8 cells — 6 new)

Both tools exercise the same fast-path arms (patch 2 for IPv4,
patch 3 for IPv6) but stress the kernel differently:
  - iperf3 single-threaded server; TCP stack + socket lock
    contention
  - iperf2 thread-per-stream server; scheduler + SMP
    cache-coherency

A bug visible only under one tool implies a multithreading or
scheduler interaction — worth N=2 tools for that reason. The
B.2 readiness doc captured the iperf2 server lifecycle pattern
(held-open ssh, not -D) and IPv6 invocation notes; both
referenced from Phase 4.2 commands.

Phase 5 (30-min sustained) doubles to two rounds:
  - Round 1: 30 min iperf3 on both pairs in parallel
  - Round 2: 30 min iperf2 on both pairs in parallel
Total Phase 5 wall clock: 70 min.

Phase 6 (24h soak) splits the two tools across the two pairs
to cover both in one 24h wall-clock window:
  - Pair #1 (i40e): 24h iperf3 — new (B.1 was mlx5)
  - Pair #2 (mlx5): 24h iperf2 — new (B.2 was prep only)
Pairs run in parallel; both new data points complete in 24h.

Active hands-on bumps from 10-15h to 12-18h. Wall clock from
36-40h to 38-42h.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
randomizedcoder added a commit that referenced this pull request Jun 1, 2026
Final test phase for series 3. Two 24 h soaks in parallel,
both ran cleanly to completion on 2026-05-29.

Pair #1: i40e 10 GbE hp2->hp5, 24 h iperf3 rolling sessions
  - 279 runs (23.25 h of continuous traffic)
  - mean 9.4114 Gbit/s, stdev 0.0010, CV 0.011 %
  - drift first 30 vs last 30: -0.000 % (below printed precision)
  - 0 cake drops over 23 h
  - This is the tightest throughput stability we have ever
    measured. The patched-kernel + i40e + cake path is
    effectively deterministic at this load.

Pair #2: mlx5 25 GbE hp1->hp3, 24 h iperf2 rolling sessions
  - 284 runs (24 h)
  - mean 16.258 Gbit/s, stdev 0.273, CV 1.68 %
  - drift first 30 vs last 30: -0.504 % (well within CV)
  - 7 cake drops total over 24 h (single-digit; negligible)
  - RSS drift +11 MB (3686 -> 3697 MB peak); no leak
  - 0 new dmesg WARN/BUG/oops over 24 h

Both pass the same pass-criteria as series 1+2's B.1 soak.
The patched kernel is at least as stable as the unpatched
baseline under sustained load.

Cover letter updated: 24 h soak and 30-min sustained moved
from "TODO" to "done". Remaining TODOs trimmed to:
  - kernel selftest (v2 follow-up)
  - VLAN fast-path (v2 follow-up)

Both genuine v2 work; v1 RFC is now feature-complete on the
test side and ready to send to netdev.

Files in this commit:
  - perf-results/2026-05-28-series3-phase6/results.md
  - perf-results/2026-05-28-series3-phase6/soak-hp{2-hp5,1-hp3}-*.log
  - kernel-patches/series3-flowdis-fastpath/v1/0000-cover-letter.patch
    (updated soak + sustained sections)
  - kernel-patches/series3-flowdis-fastpath/v1/STATUS.md
    (test plan status now all-done except v2 follow-ups)

Per-run iperf3 JSONs on hp2's /tmp not committed (700 MB
combined; recoverable via scp; covered by .gitignore rule for
soak_iperf_*.json artifacts).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant