perf(portscan): AF_XDP plan Phase 2 PR 1 — io_engine dispatch refactor + scanner fork#67
Merged
skullcrushercmd merged 1 commit intomainfrom Apr 27, 2026
Merged
Conversation
Phase 2 PR 1 of 4 of the AF_XDP integration plan (PR #65 §9.1) ships a refactor of the scanner C source (engine.c dispatch table + --io-engine CLI flag + PF_RING ZC dispatch fix) which lives in a fork of the third-party upstream scanner repository: - Upstream: github.com/Lorikazzzz/VulnScanner-zmap-alternative- - Fork: github.com/AnyVM-Tech/anyscan-engine-c - Phase 2 PR 1 commit on the fork: AnyVM-Tech/anyscan-engine-c@998c66b on branch perf/portscan-afxdp-phase2-pr1 Why fork: the plan §9.1 calls out that the upstream scanner is third-party and proposes a fork under AnyVM-Tech as the resting place for the integration patches (AF_XDP send/receive paths in PRs 2 + 3, build integration in PR 4, and follow-on PF_RING ZC cluster init). This commit only updates the AnyScan-side scripts to resolve from the new fork: - install-external-deps.sh:11-12 — clone URL and local checkout dir now default to the AnyVM-Tech fork. Both can still be overridden via the existing ANYSCAN_VULNSCANNER_REPO_URL / ANYSCAN_VULNSCANNER_REPO_DIR environment variables (no behaviour change for callers that set them). - package-worker-bundle.sh:519-525 — preferred lookup order is now `anyscan-engine-c/scanner` first, the legacy `VulnScanner-zmap-alternative-/scanner` directory second (kept for transitional dev checkouts), and `/opt/anyscan/bin/scanner` last. What is NOT in this PR: - The actual AF_XDP send/receive paths (PR 2 + 3 of Phase 2). - The Makefile / install-external-deps.sh `USE_AF_XDP=1` build flag plumbing (PR 4 of Phase 2). - Live c6in.metal benchmarks (PR 5 of Phase 2). - AnyGPT submodule pointer bump. - Any change to runtime.env or to the AIMD rate controller. Test plan: - `cargo build --workspace` (release) — clean. - `cargo test --workspace --no-fail-fast` — 437 tests pass (matches post-#66 baseline: 371 + 31 + 2 + 33). - `python3 -m py_compile vulnscanner-zmap-adapter.py` — clean. - On the scanner fork: - `make` (default AF_PACKET) — builds. - `make test` — 11 dispatch smoke tests pass. - `gcc -fsyntax-only -DUSE_PFRING_ZC ...` — compiles, dispatch reaches the ZC thread bodies. - `./scanner --io-engine=af_xdp` exits 1 with a clear "USE_AF_XDP=1 not set; AF_XDP send/receive paths land in PRs 2 + 3" message. - `./scanner --io-engine=pfring_zc` (without USE_PFRING_ZC) exits 1 with the equivalent compile-flag error. - `./scanner --io-engine=bogus` exits 1 with "Unknown --io-engine". Refs: AnyVM-Tech/AnyScan PR #65, plan §3.1 + §3.3 + §9.1.
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 2 PR 1 of 4 of the AF_XDP integration plan (#65). This PR ships:
AnyVM-Tech/anyscan-engine-cso wecan carry the AF_XDP integration patches without depending on third-party
upstream cooperation. The fork is initialized from
Lorikazzzz/VulnScanner-zmap-alternative-per plan docs(plans): AF_XDP integration plan for higher pps (Phase 1) #65 §9.1.io_enginedispatch refactor in the scanner'ssrc/engine.c, replacing the hardcodedpthread_create(..., sender_thread, ...)with a small indirection thatresolves
--io-engine={af_packet,pfring_zc,af_xdp}to the rightper-thread init + tx/rx thread bodies.
--io-engineCLI flag insrc/conf.c(defaultaf_packet,backwards-compatible).
in plan §2.3: with this PR, when the scanner is built with
USE_PFRING_ZC=1, dispatch finally reachespfring_zc_sender_thread/pfring_zc_receiver_thread(it never did before — the ZC code paths werecompiled but unreachable due to the hardcoded dispatch).
install-external-deps.shandpackage-worker-bundle.shresolve the scanner from the fork.The scanner-fork commit is at:
perf/portscan-afxdp-phase2-pr1998c66bAnyVM-Tech/anyscan-engine-c@main...perf/portscan-afxdp-phase2-pr1
Why a fork (per plan §9.1)
The plan documented three options for where AF_XDP changes should live:
upstream PR, AnyVM-Tech fork, or a patch carried in
install-external-deps.sh. Recommendation in the plan was fork atAnyVM-Tech/anyscan-engine-c, and that is what this PR adopts. The fork is
the canonical location going forward for:
USE_AF_XDP(PR 4 of Phase 2).upstream(Lorikazzzz/VulnScanner-zmap-alternative-) is preserved as aremote on the fork so we can rebase against future upstream commits if/when
that becomes useful.
Dispatch refactor — the change in pictures
Before (
src/engine.c:165, hardcoded):(PF_RING ZC sender exists in
src/send-pfring.cbut is never invoked.)After:
The vtable shape mirrors plan §3.3:
CLI behaviour
--io-engine=af_packet--io-engine=pfring_zc--io-engine=af_xdpUSE_PFRING_ZC=1Unknown values (e.g.
--io-engine=bogus) exit 1 with a clear "Unknown--io-engine" error before any setup runs. All errors land at parse time, so
none of these tests need
CAP_NET_RAW.Files in this PR (AnyScan side)
install-external-deps.sh— default URL and local-checkout dir now pointat the AnyVM-Tech fork (
anyscan-engine-c). Both stay overridable viaANYSCAN_VULNSCANNER_REPO_URL/ANYSCAN_VULNSCANNER_REPO_DIR.package-worker-bundle.sh:519-525— bundle lookup order is nowanyscan-engine-c/scannerfirst, then the legacyVulnScanner-zmap-alternative-/scanner(transitional, for dev checkoutsthat still have the old directory name), then
/opt/anyscan/bin/scanner.Files in the companion fork commit
include/scanner_defs.h—IO_ENGINE_*enum andint io_enginefield.include/scanner.h—io_engine_vtable_t,pick_io_engine(),io_engine_from_string(),io_engine_name()declarations.src/conf.c—--io-engineparsing, compile-flag gates, help text.src/engine.c— vtable definitions for AF_PACKET (and PF_RING ZC under#ifdef USE_PFRING_ZC); dispatch refactor inrun_scan. ICMP prescanhelpers continue to use their own raw PF_PACKET sockets independently of
the chosen TX engine.
Makefile—make testtarget.tests/io_engine_dispatch.sh— 11 smoke tests covering the CLI + dispatchmatrix above.
Test plan
AnyScan repo (this PR):
cargo build --workspace --release— clean (1m04s, 2 pre-existingdead_codewarnings only).cargo test --workspace --no-fail-fast— 437 tests pass, matchesthe post-perf(portscan): AIMD CPU-vs-network slip + subprocess cap + per-instance defaults + partial-window calibration #66 baseline (371 + 31 + 2 + 33, plus 0 doc-tests, with 4
pre-existing
ignored).python3 -m py_compile vulnscanner-zmap-adapter.py— clean.Scanner fork (
AnyVM-Tech/anyscan-engine-c):make(default AF_PACKET build) — builds clean (pre-existingstrncpywarnings unchanged).make test— 11/11 dispatch smoke tests pass.gcc -fsyntax-only -DUSE_PFRING_ZC -I<stub> -Iinclude src/engine.c src/conf.c src/send-pfring.c src/recv-pfring.c— clean. (Theenvironment here doesn't have libpfring-dev to do a full link, but the
syntax check confirms the dispatch wiring compiles under
USE_PFRING_ZC=1; the dispatch fix is a one-line indirection that
reviewers can verify by inspection.)
./scanner --io-engine=af_xdp -p 80exits 1 with the expected"USE_AF_XDP=1 not set" message.
./scanner --io-engine=pfring_zc -p 80exits 1 with the expected"USE_PFRING_ZC=1 not set" message (when not built with that flag).
./scanner --io-engine=bogus -p 80exits 1 with the "Unknown--io-engine" error.
./scanner --io-engine=af_packet --helpworks.Backwards compatibility
--io-engine, the binary runsthe same AF_PACKET path it always did. The inline
socket(PF_PACKET, ...)bind(...)from the previousrun_scanis moved intoaf_packet_init_per_threadso the dispatch can stay symmetric acrossengines. (Side effect:
bind()'s return value is now checked, wherepreviously it was ignored — a small robustness improvement.)
defaults only affect new clones via
install-external-deps.sh.VulnScanner-zmap-alternative-/scannerlookup path is kept inpackage-worker-bundle.shas a transitional fallback for dev checkoutsthat still have the old directory.
What is NOT in this PR
These ship in subsequent Phase 2 PRs:
src/send-afxdp.c(XSK setup, UMEM alloc, TX ring batching,completion-ring drain, kick path) per plan §3.4.
src/recv-afxdp.c+ the matchingio_engine_af_xdpvtableregistration on the fork.
USE_AF_XDP=1block,install-external-deps.shbuild-flag plumbing, libxdp-dev / libbpf-dev dependency lines, ENA
channel-half / SKB-mode fallback runtime probes, and systemd-unit
CAP_BPFambient capability per plan §3.5–§4.4.with anygpt-33.
Out-of-scope for this and all subsequent worker tasks (per plan §9 and
coordination notes):
anyscan_rate_controller.pyand the AIMD adapter — owned by anygpt-33(just merged in perf(portscan): AIMD CPU-vs-network slip + subprocess cap + per-instance defaults + partial-window calibration #66, kept untouched here).
/etc/anyscan/runtime.envon prod — owned by ops.Refs
docs(plans): AF_XDP integration plan for higher pps (Phase 1)).plans/2026-04-27-portscan-afxdp-plan-v1.md§3.1, §3.3, §9.1.Lorikazzzz/VulnScanner-zmap-alternative-'ssrc/engine.c:165,src/send-pfring.c:4,src/recv-pfring.c:4.🤖 Generated with Claude Code