feat(net): implement AF_PACKET fanout#2143
Open
fslongjin wants to merge 6 commits into
Open
Conversation
Implement PACKET_FANOUT (setsockopt SOL_PACKET option 18) for AF_PACKET sockets, distributing ingress frames across group members instead of broadcasting a full copy to every socket. Supported fanout modes: HASH (flow hash), LB (round-robin), CPU, ROLLOVER, RND. Supported flags: FLAG_ROLLOVER (backup fallback), FLAG_UNIQUEID (kernel-assigned group id). Unsupported modes (QM/CBPF/EBPF) and flags (DEFRAG/IGNORE_OUTGOING) return EINVAL. Architecture: FanoutGroup registry in NetNamespace using RCU copy-on-write (RcuArcSlot), mirroring the existing packet_sockets broadcast registry. deliver_to_packet_sockets skips fanout members in the broadcast loop and dispatches one copy per group via group.deliver(). join/leave TOCTOU closed under fanout_groups_writer lock. Per-packet deliver path is zero-allocation (two-pass member selection). AtomicBool fanout_active mirror avoids RwSem on the broadcast hot path. Closes DragonOS-Community#2032 Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com>
…_TIMESTAMP Fix three P1 issues found in adversarial review: 1. ABBA deadlock: join acquired fanout_groups_writer → fanout.write() while leave acquired fanout.write() → fanout_groups_writer. Unified lock order to always fanout_groups_writer → fanout.write() by moving the socket's fanout field clear into the netns leave path under the writer lock. 2. TOCTOU race in join_fanout: the EBUSY check (fanout.read().is_some()) ran outside the writer lock, allowing concurrent setsockopt on the same socket to bypass it and leak the socket into two groups simultaneously. Moved the check inside fanout_group_join after acquiring the writer lock. 3. PACKET_TIMESTAMP constant (value 17) was inadvertently removed from the packet_option module. Restored. Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com>
Bundle the 7 fanout join parameters (id_req, unique, mode, flags, sock_type, bound_ifindex, bound_protocol) into a FanoutJoinParams struct, reducing fanout_group_join's argument count from 9 to 3 and clearing the clippy::too_many_arguments error under #![deny(clippy::all)]. Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com>
Reduce FanoutGroup::new from 6 positional args to (id, params) by reusing the existing FanoutJoinParams bundle (a Copy struct), eliminating the duplicated argument lists at both join call sites. Extract publish_fanout_groups() helper for the registry Vec rebuild + RCU snapshot publish pattern that was triplicated across join, leave, and cleanup. Net -20 lines; behavior unchanged. Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com>
Rework fanout registration and delivery around one immutable per-netns RCU topology so plain sockets and fanout groups cannot observe split registry state. Make join, leave, close, and orphan cleanup construct replacement snapshots before publication and preserve allocator and membership invariants on allocation failure. Align the data path with Linux semantics for HASH, LB, CPU, RND, and ROLLOVER modes, including per-primary rollover state, fragment-safe flow hashing, nested VLAN protocol discovery, PACKET_FANOUT_FLAG_UNIQUEID, IGNORE_OUTGOING, and the 8-byte fanout_args max_num_members ABI. Keep protocol and flow parsing lazy and frame-local, preserve the existing cBPF/VLAN ingress path, and avoid allocations or locks in packet delivery. Add control-plane and end-to-end coverage for option validation, group capacity, lifecycle rules, and exactly-once balanced delivery. The new LB regression sends 16 frames and requires a total of 16 deliveries split 8/8 across two sockets. Validation: make kernel; af_packet_sockopt_test (38/38); af_packet_e2e_test (14/14). Signed-off-by: longjin <longjin@dragonos.org>
Wake the network-namespace poller when a fallible AF_PACKET topology unregister leaves stale entries behind. Keep cleanup and network wake reasons separate so cleanup-only work does not spuriously schedule interface NAPI. Retry failed immutable-topology rebuilds with a bounded exponential delay and an absolute deadline. Treat inactive plain and fanout members as stale immediately so closed sockets cannot receive frames while deferred cleanup is pending. Add a regression test covering the rebased PACKET_MR_PROMISC and PACKET_FANOUT close path, including restoration of the interface promiscuity reference count. Tested with make kernel and DragonOS QEMU dunitest suites: af_packet_sockopt_test (38/38), af_packet_e2e_test (14/14), and af_packet_mcast_test (14/14). Signed-off-by: longjin <longjin@dragonos.org>
Member
Author
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 38846e2225
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Comment on lines
+172
to
+176
| pub(crate) fn matches(&self, params: FanoutJoinParams) -> bool { | ||
| self.mode == params.mode | ||
| && self.flags == params.flags | ||
| && self.bound_ifindex == params.bound_ifindex | ||
| && self.bound_protocol == params.bound_protocol |
There was a problem hiding this comment.
Comment on lines
+193
to
+197
| let mut members = Vec::new(); | ||
| members | ||
| .try_reserve_exact(self.members.len().saturating_add(1)) | ||
| .map_err(|_| SystemError::ENOMEM)?; | ||
| members.extend(self.members.iter().cloned()); |
| // sets FLOW_DIS_IS_FRAGMENT and suppresses port extraction. | ||
| return (next, offset, false); | ||
| } | ||
| _ => return (next, offset, true), |
There was a problem hiding this comment.
| .by_id | ||
| .try_reserve(1) | ||
| .map_err(|_| SystemError::ENOMEM)?; | ||
| let new_id = writer.id_alloc.alloc().ok_or(SystemError::ENOMEM)? as u16; |
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.
Closes #2032.
Supersedes #2119 with the same AF_PACKET fanout implementation rebased onto the current
master, including the merged PACKET_ADD_MEMBERSHIP / PACKET_DROP_MEMBERSHIP support.What changed
Validation
make all -j 8make kernelaf_packet_sockopt_test(38/38 passed)af_packet_e2e_test(14/14 passed)af_packet_mcast_test(14/14 passed)The implementation and rebase were independently reviewed for concurrency, lifecycle safety, Linux semantics, performance, security, and regression risk.