ndn_faces/l2/
multicast_ether.rs1use std::os::unix::io::AsRawFd;
7use std::sync::atomic::{AtomicU64, Ordering};
8
9use bytes::Bytes;
10use ndn_transport::{Face, FaceAddr, FaceError, FaceId, FaceKind, LinkType};
11use tokio::io::unix::AsyncFd;
12
13use super::af_packet::{
14 MacAddr, PacketRing, get_ifindex, make_sockaddr_ll, open_packet_socket, setsockopt_val,
15 setup_packet_ring,
16};
17use crate::NDN_ETHERTYPE;
18
19pub const NDN_ETHER_MCAST_MAC: MacAddr = MacAddr([0x01, 0x00, 0x5E, 0x00, 0x17, 0xAA]);
24
25pub struct MulticastEtherFace {
36 id: FaceId,
37 iface: String,
38 ifindex: i32,
39 socket: AsyncFd<std::os::unix::io::OwnedFd>,
40 ring: PacketRing,
41 seq: AtomicU64,
43}
44
45impl MulticastEtherFace {
46 pub fn new(id: FaceId, iface: impl Into<String>) -> std::io::Result<Self> {
51 let iface = iface.into();
52
53 let probe_fd = unsafe {
55 libc::socket(
56 libc::AF_PACKET,
57 libc::SOCK_DGRAM | libc::SOCK_CLOEXEC,
58 NDN_ETHERTYPE.to_be() as i32,
59 )
60 };
61 if probe_fd == -1 {
62 return Err(std::io::Error::last_os_error());
63 }
64 let ifindex = {
65 let idx = get_ifindex(probe_fd, &iface);
66 unsafe {
67 libc::close(probe_fd);
68 }
69 idx?
70 };
71
72 let fd = open_packet_socket(ifindex, NDN_ETHERTYPE)?;
73
74 let mreq = libc::packet_mreq {
76 mr_ifindex: ifindex,
77 mr_type: libc::PACKET_MR_MULTICAST as u16,
78 mr_alen: 6,
79 mr_address: {
80 let mut addr = [0u8; 8];
81 addr[..6].copy_from_slice(NDN_ETHER_MCAST_MAC.as_bytes());
82 addr
83 },
84 };
85 setsockopt_val(
86 fd.as_raw_fd(),
87 libc::SOL_PACKET,
88 libc::PACKET_ADD_MEMBERSHIP,
89 &mreq,
90 )?;
91
92 let ring = setup_packet_ring(fd.as_raw_fd())?;
94 let socket = AsyncFd::new(fd)?;
95
96 Ok(Self {
97 id,
98 iface,
99 ifindex,
100 socket,
101 ring,
102 seq: AtomicU64::new(0),
103 })
104 }
105
106 pub fn iface(&self) -> &str {
108 &self.iface
109 }
110
111 pub async fn recv_with_source(&self) -> Result<(Bytes, MacAddr), ndn_transport::FaceError> {
118 loop {
119 if let Some(result) = self.ring.try_pop_rx_with_source() {
120 return Ok(result);
121 }
122 let mut guard = self.socket.readable().await?;
123 guard.clear_ready();
124 }
125 }
126}
127
128impl Face for MulticastEtherFace {
129 fn id(&self) -> FaceId {
130 self.id
131 }
132 fn kind(&self) -> FaceKind {
133 FaceKind::EtherMulticast
134 }
135
136 fn link_type(&self) -> LinkType {
137 LinkType::MultiAccess
138 }
139
140 fn remote_uri(&self) -> Option<String> {
141 Some(format!("ether://[{}]/{}", NDN_ETHER_MCAST_MAC, self.iface))
142 }
143
144 fn local_uri(&self) -> Option<String> {
145 Some(format!("dev://{}", self.iface))
146 }
147
148 async fn recv(&self) -> Result<Bytes, FaceError> {
149 loop {
150 if let Some(pkt) = self.ring.try_pop_rx() {
151 return Ok(pkt);
152 }
153 let mut guard = self.socket.readable().await?;
154 guard.clear_ready();
155 }
156 }
157
158 async fn recv_with_addr(&self) -> Result<(Bytes, Option<FaceAddr>), FaceError> {
159 let (pkt, src_mac) = self.recv_with_source().await?;
160 Ok((pkt, Some(FaceAddr::Ether(src_mac.0))))
161 }
162
163 async fn send(&self, pkt: Bytes) -> Result<(), FaceError> {
164 let wire = ndn_packet::lp::encode_lp_packet(&pkt);
165
166 let frames = if wire.len() > 1500 {
168 let seq = self.seq.fetch_add(1, Ordering::Relaxed);
169 ndn_packet::fragment::fragment_packet(&wire, 1500, seq)
170 } else {
171 vec![wire]
172 };
173
174 for frame in &frames {
175 loop {
177 if self.ring.try_push_tx(frame) {
178 break;
179 }
180 let mut guard = self.socket.writable().await?;
181 guard.clear_ready();
182 }
183
184 let dst = make_sockaddr_ll(self.ifindex, &NDN_ETHER_MCAST_MAC, NDN_ETHERTYPE);
186 let fd = self.socket.get_ref().as_raw_fd();
187 let ret = unsafe {
188 libc::sendto(
189 fd,
190 std::ptr::null(),
191 0,
192 0,
193 &dst as *const libc::sockaddr_ll as *const libc::sockaddr,
194 std::mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t,
195 )
196 };
197 if ret == -1 {
198 let err = std::io::Error::last_os_error();
199 if err.kind() != std::io::ErrorKind::WouldBlock {
200 return Err(FaceError::Io(err));
201 }
202 }
203 }
204 Ok(())
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211
212 #[test]
213 fn mcast_mac_is_multicast() {
214 assert_eq!(NDN_ETHER_MCAST_MAC.as_bytes()[0] & 0x01, 0x01);
216 }
217
218 #[tokio::test]
220 async fn new_fails_without_cap_net_raw() {
221 let result = MulticastEtherFace::new(FaceId(1), "lo");
222 if let Err(e) = result {
223 let raw = e.raw_os_error().unwrap_or(0);
224 assert!(
225 raw == libc::EPERM || raw == libc::EACCES,
226 "expected EPERM or EACCES, got: {e}"
227 );
228 }
229 }
230}