Skip to content

build(afxdp): apt-get deps + systemd CAP_BPF + install-time probe — Phase 2 PR C#69

Merged
skullcrushercmd merged 1 commit into
mainfrom
perf/portscan-afxdp-deps-prc
Apr 28, 2026
Merged

build(afxdp): apt-get deps + systemd CAP_BPF + install-time probe — Phase 2 PR C#69
skullcrushercmd merged 1 commit into
mainfrom
perf/portscan-afxdp-deps-prc

Conversation

@skullcrushercmd
Copy link
Copy Markdown
Contributor

Summary

Companion to AnyVM-Tech/anyscan-engine-c#3 (Makefile USE_AF_XDP=1 conditional). With both PRs landed, a worker bundle built with the fork's USE_AF_XDP=1 toggle has the kernel capabilities and runtime metadata it needs to run --io-engine=af_xdp. Phase 2 PR D will follow with the runtime opt-in env var that the adapter passes through to the scanner subprocess.

This is Phase 2 PR C of plans/2026-04-27-portscan-afxdp-plan-v1.md, per §3.5 (ENA / AWS specifics), §4.1 (build-time deps), §4.3 (kernel feature checks), and §4.4 (capabilities).

What changed

install-external-deps.shinstall_afxdp_build_deps()

Best-effort apt-get install for libxdp-dev libbpf-dev libelf-dev so the dev-machine bootstrap path can build the scanner with USE_AF_XDP=1. Skips cleanly when:

  • apt-get is not on PATH (non-Debian host),
  • the script runs non-root and sudo is unavailable / would prompt,
  • ANYSCAN_INSTALL_AFXDP_DEPS=false (operator opt-out).

On skip, prints the manual install command. The default make build path does not need these packages, so a failure here is non-fatal — make USE_AF_XDP=1 would fail loudly later, which is the right escalation.

anyscan-worker.service / anyscan-worker-only.serviceCAP_BPF

Adds CAP_BPF to AmbientCapabilities and CapabilityBoundingSet on both worker units. The scanner only uses bpf() when invoked with --io-engine=af_xdp (XSK socket open + libxdp default redirect program attach); the AF_PACKET default path does not need CAP_BPF, so this grant is purely a runtime gate that lets workers opt in via ANYSCAN_SCANNER_IO_ENGINE (PR D) without another unit-file refresh.

CAP_BPF is the narrow capability introduced in 5.8; on older kernels it collapses into CAP_SYS_ADMIN and the bit we set here is ignored — the install-time probe below keeps af_xdp disabled on those hosts so the unit-file grant has no effect there either.

install-worker-bundle.shprobe_afxdp_runtime_available + apply_afxdp_availability

At install time, probe (a) uname -r ≥ 5.10 and (b) ldconfig -p shows libxdp.so. Write ANYSCAN_AF_XDP_AVAILABLE=true|false to /etc/agentd/runtime.env unconditionally so the value is explicit and a partial upgrade cannot leave a stale true behind after a kernel downgrade.

The flag is consumed by Phase 2 PR D (adapter-level opt-in); this PR only writes it. ANYSCAN_AF_XDP_AVAILABLE=true is necessary but not sufficient: the bundled scanner also has to be built with USE_AF_XDP=1 for af_xdp to work — that's a worker-bundle build-pipeline change tracked separately.

Test status

  • bash -n on both edited scripts: OK.
  • Probe function unit-tested against this host (kernel 6.12, libxdp 1.5.4 present): returns true.
    • Forced-fake k=5.4: returns false (kernel-version gate works).
    • Forced-fake k=6.1 with libxdp present: returns true.
  • End-to-end smoke test of apply_afxdp_availability against a temp runtime.env: writes ANYSCAN_AF_XDP_AVAILABLE=true (this host has libxdp).
  • systemd-analyze verify on both unit files: clean (only reports the expected missing /opt/{anyscan,agentd}/bin because this dev sandbox doesn't have the worker installed).
  • cargo build --workspace: clean. Two pre-existing dead_code warnings, unchanged.
  • cargo test --workspace --no-fail-fast: 437 passed, 0 failed, 4 ignored — unchanged from main.

Out of scope (deferred to Phase 2 PR D)

  • ANYSCAN_SCANNER_IO_ENGINE env var in runtime.worker.env.template.
  • vulnscanner-zmap-adapter.py reading the env and passing --io-engine through to the scanner subprocess.
  • install-worker-bundle.sh writing ANYSCAN_SCANNER_IO_ENGINE=af_packet on fresh installs.
  • Worker-bundle build pipeline switching to make USE_AF_XDP=1 for the bundled scanner binary.
  • Live c6in.metal bench — Phase 2 PR E.

Plan reference

plans/2026-04-27-portscan-afxdp-plan-v1.md: §3.5 (ENA / AWS specifics), §4.1 (build-time deps), §4.3 (kernel feature checks), §4.4 (capabilities).

…hase 2 PR C

Companion to AnyVM-Tech/anyscan-engine-c PR #3 (Makefile USE_AF_XDP=1
conditional). With both PRs landed, a worker bundle built with the fork's
USE_AF_XDP=1 toggle has the kernel capabilities and runtime metadata to
run --io-engine=af_xdp; PR D will add the runtime opt-in env var that
the adapter passes through to the scanner subprocess.

What this adds (per plan §3.5, §4.1, §4.3, §4.4):

1. install-external-deps.sh — install_afxdp_build_deps()

   Best-effort apt-get install for libxdp-dev libbpf-dev libelf-dev so
   the dev-machine bootstrap path can build the scanner with
   USE_AF_XDP=1. Skips cleanly when:
     - apt-get is not on PATH (non-Debian host),
     - the script runs non-root and sudo is unavailable / would prompt,
     - ANYSCAN_INSTALL_AFXDP_DEPS=false (operator opt-out).
   When it skips, it prints the manual command. The default `make` build
   path does not need these packages, so failure here is non-fatal.

2. anyscan-worker.service / anyscan-worker-only.service — CAP_BPF

   Adds CAP_BPF to AmbientCapabilities and CapabilityBoundingSet on
   both worker units. The scanner only uses the bpf() syscall when
   invoked with --io-engine=af_xdp (XSK socket open + libxdp default
   redirect program attach); the AF_PACKET default path does not need
   CAP_BPF, so this grant is purely a runtime gate that lets workers
   opt in via ANYSCAN_SCANNER_IO_ENGINE without a unit-file refresh.

   CAP_BPF is the narrow capability introduced in 5.8; on older
   kernels it collapses into CAP_SYS_ADMIN and the bit we set here is
   ignored — the install-time probe (next bullet) keeps af_xdp
   disabled on those hosts so the unit-file grant has no effect there
   either.

3. install-worker-bundle.sh — probe_afxdp_runtime_available + apply

   At install time, probe (a) `uname -r` >= 5.10 and (b) `ldconfig -p`
   shows libxdp.so. Write ANYSCAN_AF_XDP_AVAILABLE=true|false to
   /etc/agentd/runtime.env unconditionally so the value is explicit
   and a partial upgrade cannot leave a stale "true" behind after
   a kernel downgrade.

   The flag is consumed by Phase 2 PR D (adapter-level opt-in) — this
   PR only writes it. ANYSCAN_AF_XDP_AVAILABLE=true is necessary but
   not sufficient: the bundled scanner also has to be built with
   USE_AF_XDP=1 (worker-bundle build pipeline change, separate work).

Test status:

- bash -n on both edited scripts: OK.
- Probe function unit-tested against this host (kernel 6.12, libxdp
  1.5.4 present): returns "true". Forced-fake k=5.4: returns "false".
  Forced-fake k=6.1 with libxdp present: returns "true".
- End-to-end smoke test of apply_afxdp_availability against a tmp
  runtime.env: writes ANYSCAN_AF_XDP_AVAILABLE=true (this host).
- systemd-analyze verify on both unit files: clean (the only
  reported errors are missing /opt/{anyscan,agentd}/bin in this
  dev sandbox, which is expected).
- cargo build --workspace: clean, two pre-existing dead_code
  warnings unchanged.
- cargo test --workspace --no-fail-fast: 437 passed, 0 failed,
  4 ignored (unchanged from main).

Out of scope (deferred to Phase 2 PR D):

- ANYSCAN_SCANNER_IO_ENGINE env var in runtime.worker.env.template.
- vulnscanner-zmap-adapter.py reading the env and passing
  --io-engine through to the scanner subprocess.
- install-worker-bundle.sh writing ANYSCAN_SCANNER_IO_ENGINE=af_packet
  on fresh installs.

Plan: plans/2026-04-27-portscan-afxdp-plan-v1.md §3.5, §4.1, §4.3, §4.4.
@skullcrushercmd skullcrushercmd merged commit 69a1431 into main Apr 28, 2026
@skullcrushercmd skullcrushercmd deleted the perf/portscan-afxdp-deps-prc branch April 28, 2026 02:48
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