Skip to content

Commit 37a5f06

Browse files
sparkzkyfslongjin
andauthored
feat(net): implement PACKET_ADD_MEMBERSHIP / PACKET_DROP_MEMBERSHIP (#2132)
* feat(net): implement PACKET_ADD_MEMBERSHIP / PACKET_DROP_MEMBERSHIP Implement multicast membership management for AF_PACKET sockets, supporting all four mr_type values: PACKET_MR_PROMISC, PACKET_MR_ALLMULTI, PACKET_MR_MULTICAST, PACKET_MR_UNICAST. Changes: - New module kernel/src/net/socket/packet/mreq.rs: per-socket membership list with add/drop/revert-on-close - IfaceCommon: promiscuity/allmulti AtomicI32 refcounts with atomic fetch_or/fetch_and flag transitions (IFF_PROMISC/IFF_ALLMULTI) - PacketSocket: mreq_list field - sockopt.rs: replace no-op stub with real handlers - close_binding: revert all memberships before unregistering socket - Tests: EINVAL for invalid mr_type, ENODEV for unknown ifindex Refs #2033 Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com> * fix(net): align packet memberships with Linux Signed-off-by: longjin <longjin@dragonos.org> --------- Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com> Signed-off-by: longjin <longjin@dragonos.org> Co-authored-by: longjin <longjin@dragonos.org>
1 parent b1824fc commit 37a5f06

10 files changed

Lines changed: 703 additions & 29 deletions

File tree

kernel/src/driver/net/mod.rs

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,20 @@ fn register_netdevice(dev: Arc<dyn Iface>) -> Result<(), SystemError> {
251251
return Ok(());
252252
}
253253

254+
#[derive(Debug)]
255+
struct ReceiveModeState {
256+
configured_flags: u32,
257+
packet_promiscuity: u32,
258+
packet_allmulti: u32,
259+
}
260+
261+
#[derive(Debug, Clone, Copy)]
262+
pub struct LinkFlagsSnapshot {
263+
pub configured: InterfaceFlags,
264+
pub promiscuity: u32,
265+
pub allmulti: u32,
266+
}
267+
254268
pub struct IfaceCommon {
255269
iface_id: usize,
256270
name: RwLock<String>,
@@ -279,6 +293,8 @@ pub struct IfaceCommon {
279293
/// TCP listener/backlog 语义辅助(Linux-like 丢 SYN 等)。
280294
tcp_listener_backlog: crate::net::tcp_listener_backlog::TcpListenerBacklog,
281295
ipv4_multicast_refcnt: Mutex<Vec<(smoltcp::wire::Ipv4Address, usize)>>,
296+
/// Serializes configured receive-mode flags with AF_PACKET references.
297+
receive_mode: Mutex<ReceiveModeState>,
282298
}
283299

284300
impl fmt::Debug for IfaceCommon {
@@ -323,6 +339,11 @@ impl IfaceCommon {
323339
tcp_close_defer: crate::net::tcp_close_defer::TcpCloseDefer::new(),
324340
tcp_listener_backlog: crate::net::tcp_listener_backlog::TcpListenerBacklog::new(),
325341
ipv4_multicast_refcnt: Mutex::new(Vec::new()),
342+
receive_mode: Mutex::new(ReceiveModeState {
343+
configured_flags: flags.bits(),
344+
packet_promiscuity: 0,
345+
packet_allmulti: 0,
346+
}),
326347
}
327348
}
328349

@@ -668,11 +689,46 @@ impl IfaceCommon {
668689
}
669690

670691
pub fn flags(&self) -> InterfaceFlags {
671-
InterfaceFlags::from_bits_truncate(self.flags.load(Ordering::Relaxed))
692+
InterfaceFlags::from_bits_truncate(self.flags.load(Ordering::Acquire))
672693
}
673694

674-
pub fn set_flags(&self, flags: InterfaceFlags) {
675-
self.flags.store(flags.bits(), Ordering::Relaxed);
695+
pub fn update_configured_flags(
696+
&self,
697+
requested: InterfaceFlags,
698+
change_mask: InterfaceFlags,
699+
) -> Result<InterfaceFlags, SystemError> {
700+
let mut state = self.receive_mode.lock();
701+
let configured = (state.configured_flags & !change_mask.bits())
702+
| (requested.bits() & change_mask.bits());
703+
704+
Self::total_receive_mode_count(
705+
state.packet_promiscuity,
706+
configured & InterfaceFlags::PROMISC.bits() != 0,
707+
)?;
708+
Self::total_receive_mode_count(
709+
state.packet_allmulti,
710+
configured & InterfaceFlags::ALLMULTI.bits() != 0,
711+
)?;
712+
713+
state.configured_flags = configured;
714+
self.publish_effective_flags(&state);
715+
Ok(InterfaceFlags::from_bits_truncate(configured))
716+
}
717+
718+
pub fn link_flags_snapshot(&self) -> Result<LinkFlagsSnapshot, SystemError> {
719+
let state = self.receive_mode.lock();
720+
let configured = InterfaceFlags::from_bits_truncate(state.configured_flags);
721+
Ok(LinkFlagsSnapshot {
722+
configured,
723+
promiscuity: Self::total_receive_mode_count(
724+
state.packet_promiscuity,
725+
configured.contains(InterfaceFlags::PROMISC),
726+
)?,
727+
allmulti: Self::total_receive_mode_count(
728+
state.packet_allmulti,
729+
configured.contains(InterfaceFlags::ALLMULTI),
730+
)?,
731+
})
676732
}
677733

678734
pub fn type_(&self) -> InterfaceType {
@@ -755,4 +811,55 @@ impl IfaceCommon {
755811
neighbors.retain(|existing| existing.ip_addr != ip_addr);
756812
neighbors.len() != before
757813
}
814+
815+
pub fn adjust_promiscuity(&self, inc: i32) -> Result<(), SystemError> {
816+
self.adjust_receive_mode(InterfaceFlags::PROMISC, inc)
817+
}
818+
819+
pub fn adjust_allmulti(&self, inc: i32) -> Result<(), SystemError> {
820+
self.adjust_receive_mode(InterfaceFlags::ALLMULTI, inc)
821+
}
822+
823+
fn adjust_receive_mode(&self, flag: InterfaceFlags, inc: i32) -> Result<(), SystemError> {
824+
let mut state = self.receive_mode.lock();
825+
let old = if flag == InterfaceFlags::PROMISC {
826+
state.packet_promiscuity
827+
} else if flag == InterfaceFlags::ALLMULTI {
828+
state.packet_allmulti
829+
} else {
830+
return Err(SystemError::EINVAL);
831+
};
832+
let new = match inc {
833+
1 => old.checked_add(1).ok_or(SystemError::EOVERFLOW)?,
834+
-1 => old.checked_sub(1).ok_or(SystemError::EINVAL)?,
835+
_ => return Err(SystemError::EINVAL),
836+
};
837+
let configured = state.configured_flags & flag.bits() != 0;
838+
Self::total_receive_mode_count(new, configured)?;
839+
840+
if flag == InterfaceFlags::PROMISC {
841+
state.packet_promiscuity = new;
842+
} else {
843+
state.packet_allmulti = new;
844+
}
845+
self.publish_effective_flags(&state);
846+
Ok(())
847+
}
848+
849+
fn total_receive_mode_count(packet: u32, configured: bool) -> Result<u32, SystemError> {
850+
packet
851+
.checked_add(u32::from(configured))
852+
.ok_or(SystemError::EOVERFLOW)
853+
}
854+
855+
fn publish_effective_flags(&self, state: &ReceiveModeState) {
856+
let mut effective = state.configured_flags;
857+
if state.packet_promiscuity != 0 {
858+
effective |= InterfaceFlags::PROMISC.bits();
859+
}
860+
if state.packet_allmulti != 0 {
861+
effective |= InterfaceFlags::ALLMULTI.bits();
862+
}
863+
self.flags.store(effective, Ordering::Release);
864+
}
758865
}

kernel/src/net/socket/netlink/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,7 @@ pub fn create_netlink_socket(
5353

5454
Ok(inode)
5555
}
56+
57+
pub(crate) fn notify_link_change(iface: &Arc<dyn crate::driver::net::Iface>) {
58+
route::kern::notify_link_change(iface);
59+
}

kernel/src/net/socket/netlink/route/kern/link.rs

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ fn iface_to_link_message(
134134
msg_type: CSegmentType,
135135
iface: &Arc<dyn Iface>,
136136
) -> Result<LinkSegment, SystemError> {
137+
let flags = iface.common().link_flags_snapshot()?;
137138
let header = CMsgSegHdr {
138139
len: 0,
139140
type_: msg_type as _,
@@ -146,7 +147,7 @@ fn iface_to_link_message(
146147
family: AddressFamily::Unspecified,
147148
type_: iface.type_(),
148149
index: NonZero::new(iface.nic_id() as u32),
149-
flags: iface.flags(),
150+
flags: flags.configured,
150151
change: LinkMessageFlags::empty(),
151152
pad: None,
152153
};
@@ -155,11 +156,31 @@ fn iface_to_link_message(
155156
LinkAttr::Address(iface.mac().as_bytes().to_vec()),
156157
LinkAttr::Name(CString::new(iface.name()).map_err(|_| SystemError::EINVAL)?),
157158
LinkAttr::Mtu(iface.mtu() as u32),
159+
LinkAttr::Promiscuity(flags.promiscuity),
160+
LinkAttr::Allmulti(flags.allmulti),
158161
];
159162

160163
Ok(LinkSegment::new(header, link_message, attrs))
161164
}
162165

166+
pub(crate) fn notify_link_change(iface: &Arc<dyn Iface>) {
167+
let Some(netns) = iface.net_namespace() else {
168+
return;
169+
};
170+
let segment = iface_to_link_message(
171+
&kernel_notify_header(CSegmentType::NEWLINK),
172+
CSegmentType::NEWLINK,
173+
iface,
174+
);
175+
match segment {
176+
Ok(segment) => multicast_notify(netns, RTMGRP_LINK, RouteNlSegment::NewLink(segment)),
177+
Err(err) => log::warn!(
178+
"netlink route: failed to build link notification: {:?}",
179+
err
180+
),
181+
}
182+
}
183+
163184
pub(super) fn do_del_link(
164185
request_segment: &LinkSegment,
165186
netns: Arc<NetNamespace>,
@@ -188,15 +209,11 @@ pub(super) fn do_set_link(
188209
}
189210
}
190211

191-
let current_flags = iface.flags();
192212
let change_mask = InterfaceFlags::from_bits_truncate(request_segment.body().change.bits());
193213
let requested_flags = InterfaceFlags::from_bits_truncate(request_segment.body().flags.bits());
194-
let new_flags = InterfaceFlags::from_bits_truncate(
195-
(current_flags.bits() & !change_mask.bits())
196-
| (requested_flags.bits() & change_mask.bits()),
197-
);
198-
199-
iface.common().set_flags(new_flags);
214+
let new_flags = iface
215+
.common()
216+
.update_configured_flags(requested_flags, change_mask)?;
200217

201218
if change_mask.contains(InterfaceFlags::UP) {
202219
let operstate = if new_flags.contains(InterfaceFlags::UP) {
@@ -215,15 +232,7 @@ pub(super) fn do_set_link(
215232
iface.common().set_mtu(mtu as usize);
216233
}
217234

218-
multicast_notify(
219-
netns,
220-
RTMGRP_LINK,
221-
RouteNlSegment::NewLink(iface_to_link_message(
222-
&kernel_notify_header(CSegmentType::NEWLINK),
223-
CSegmentType::NEWLINK,
224-
&iface,
225-
)?),
226-
);
235+
notify_link_change(&iface);
227236

228237
Ok(Vec::new())
229238
}
@@ -298,7 +307,11 @@ fn validate_setlink_request(
298307
updates.mtu = Some(*mtu);
299308
}
300309
}
301-
LinkAttr::TxqLen(_) | LinkAttr::LinkMode(_) | LinkAttr::ExtMask(_) => {}
310+
LinkAttr::Allmulti(_) => return Err(SystemError::EINVAL),
311+
LinkAttr::Promiscuity(_)
312+
| LinkAttr::TxqLen(_)
313+
| LinkAttr::LinkMode(_)
314+
| LinkAttr::ExtMask(_) => {}
302315
_ => return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP),
303316
}
304317
}

kernel/src/net/socket/netlink/route/kern/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ mod neigh;
2525
mod route;
2626
mod utils;
2727

28+
pub(crate) use link::notify_link_change;
29+
2830
/// 负责处理 Netlink 路由相关的内核模块
2931
/// 每个 net namespace 都有一个独立的 NetlinkRouteKernelSocket
3032
#[derive(Debug)]

kernel/src/net/socket/netlink/route/message/attr/link.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ enum LinkAttrClass {
7777
PROTO_DOWN_REASON = 55,
7878
PARENT_DEV_NAME = 56,
7979
PARENT_DEV_BUS_NAME = 57,
80+
GRO_MAX_SIZE = 58,
81+
TSO_MAX_SIZE = 59,
82+
TSO_MAX_SEGS = 60,
83+
/// All-multicast count: > 0 means acts ALLMULTI.
84+
ALLMULTI = 61,
8085
}
8186

8287
impl TryFrom<u16> for LinkAttrClass {
@@ -92,6 +97,8 @@ pub enum LinkAttr {
9297
Address(Vec<u8>),
9398
Name(CString),
9499
Mtu(u32),
100+
Promiscuity(u32),
101+
Allmulti(u32),
95102
TxqLen(u32),
96103
LinkMode(u8),
97104
ExtMask(RtExtFilter),
@@ -103,6 +110,8 @@ impl LinkAttr {
103110
LinkAttr::Address(_) => LinkAttrClass::ADDRESS,
104111
LinkAttr::Name(_) => LinkAttrClass::IFNAME,
105112
LinkAttr::Mtu(_) => LinkAttrClass::MTU,
113+
LinkAttr::Promiscuity(_) => LinkAttrClass::PROMISCUITY,
114+
LinkAttr::Allmulti(_) => LinkAttrClass::ALLMULTI,
106115
LinkAttr::TxqLen(_) => LinkAttrClass::TXQLEN,
107116
LinkAttr::LinkMode(_) => LinkAttrClass::LINKMODE,
108117
LinkAttr::ExtMask(_) => LinkAttrClass::EXT_MASK,
@@ -134,6 +143,9 @@ impl Attribute for LinkAttr {
134143
LinkAttr::Mtu(mtu) => unsafe {
135144
core::slice::from_raw_parts(mtu as *const u32 as *const u8, 4)
136145
},
146+
LinkAttr::Promiscuity(count) | LinkAttr::Allmulti(count) => unsafe {
147+
core::slice::from_raw_parts(count as *const u32 as *const u8, 4)
148+
},
137149
LinkAttr::TxqLen(txq_len) => unsafe {
138150
core::slice::from_raw_parts(txq_len as *const u32 as *const u8, 4)
139151
},
@@ -169,6 +181,14 @@ impl Attribute for LinkAttr {
169181
let data = convert_one_from_raw_buf::<u32>(buf)?;
170182
Self::Mtu(*data)
171183
}
184+
(LinkAttrClass::PROMISCUITY, 4) => {
185+
let data = convert_one_from_raw_buf::<u32>(buf)?;
186+
Self::Promiscuity(*data)
187+
}
188+
(LinkAttrClass::ALLMULTI, 4) => {
189+
let data = convert_one_from_raw_buf::<u32>(buf)?;
190+
Self::Allmulti(*data)
191+
}
172192
(LinkAttrClass::TXQLEN, 4) => {
173193
let data = convert_one_from_raw_buf::<u32>(buf)?;
174194
Self::TxqLen(*data)
@@ -185,6 +205,8 @@ impl Attribute for LinkAttr {
185205
(
186206
LinkAttrClass::IFNAME
187207
| LinkAttrClass::MTU
208+
| LinkAttrClass::PROMISCUITY
209+
| LinkAttrClass::ALLMULTI
188210
| LinkAttrClass::TXQLEN
189211
| LinkAttrClass::LINKMODE
190212
| LinkAttrClass::EXT_MASK,

kernel/src/net/socket/packet/binding.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ impl PacketSocket {
7878

7979
pub(super) fn close_binding(&self) -> Result<(), SystemError> {
8080
let _guard = self.bind_lock.lock();
81+
self.revert_all_memberships();
8182
self.netns.unregister_packet_socket(&self.self_ref);
8283
*self.bound_iface.write() = None;
8384
self.binding.store(0, 0);

kernel/src/net/socket/packet/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! AF_PACKET sockets.
22
33
mod binding;
4+
mod mreq;
45
mod rx;
56
mod sockopt;
67
mod tx;
@@ -109,6 +110,7 @@ pub struct PacketSocket {
109110
pub(super) send_timeout_ticks: AtomicU64,
110111
pub(super) recv_timeout_ticks: AtomicU64,
111112
pub(super) wait_queue: WaitQueue,
113+
memberships: Mutex<mreq::PacketMembershipState>,
112114
inode_id: InodeId,
113115
open_files: AtomicUsize,
114116
pub(super) self_ref: Weak<Self>,
@@ -151,6 +153,7 @@ impl PacketSocket {
151153
send_timeout_ticks: AtomicU64::new(crate::net::socket::common::INFINITE_TIMEOUT_TICKS),
152154
recv_timeout_ticks: AtomicU64::new(crate::net::socket::common::INFINITE_TIMEOUT_TICKS),
153155
wait_queue: WaitQueue::default(),
156+
memberships: Mutex::new(mreq::PacketMembershipState::default()),
154157
inode_id: generate_inode_id(),
155158
open_files: AtomicUsize::new(0),
156159
self_ref: me.clone(),

0 commit comments

Comments
 (0)