1use core::fmt::Debug;
8use core::num::NonZeroU32;
9use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
10
11use log::{debug, trace};
12use net_types::ethernet::Mac;
13use net_types::ip::{GenericOverIp, Ip, IpMarked, Ipv4, Ipv6, Mtu};
14use net_types::{MulticastAddr, UnicastAddr, Witness};
15use netstack3_base::ref_counted_hash_map::{InsertResult, RefCountedHashSet, RemoveResult};
16use netstack3_base::sync::{Mutex, RwLock};
17use netstack3_base::{
18 BroadcastIpExt, ChecksumOffloadSpec, CoreTimerContext, Device, DeviceIdContext, EventContext,
19 FrameDestination, GsoInfo, HandleableTimer, LinkDevice, NestedIntoCoreTimerCtx,
20 NetworkParsingContext, NetworkSerializer, ReceivableFrameMeta, RecvFrameContext,
21 RecvIpFrameMeta, ResourceCounterContext, RngContext, SendFrameError, SendFrameErrorReason,
22 SendableFrameMeta, TimerContext, TimerHandler, TxMetadataBindingsTypes, WeakDeviceIdentifier,
23 WrapBroadcastMarker,
24};
25use netstack3_ip::nud::{LinkResolutionContext, NudHandler, NudState, NudTimerId, NudUserConfig};
26use netstack3_ip::{DeviceIpLayerMetadata, IpCounters, IpPacketDestination};
27use netstack3_trace::trace_duration;
28use packet::{BufferMut, NestablePacketBuilder as _, NestableSerializer as _};
29use packet_formats::arp::{ArpHardwareType, ArpNetworkType, peek_arp_types};
30use packet_formats::ethernet::{
31 ETHERNET_HDR_LEN_NO_TAG, EtherType, EthernetFrame, EthernetFrameBuilder,
32 EthernetFrameLengthCheck, EthernetIpExt,
33};
34
35use crate::internal::arp::{ArpFrameMetadata, ArpPacketHandler, ArpState, ArpTimerId};
36use crate::internal::base::{
37 DeviceBufferBindingsTypes, DeviceCounters, DeviceLayerTypes, DeviceReceiveFrameSpec,
38 EthernetDeviceCounters,
39};
40use crate::internal::id::{DeviceId, EthernetDeviceId};
41use crate::internal::queue::tx::{TransmitQueue, TransmitQueueHandler, TransmitQueueState};
42use crate::internal::queue::{DequeueState, DeviceBufferSpec, TransmitQueueFrameError};
43use crate::internal::socket::{
44 DeviceSocketHandler, DeviceSocketMetadata, DeviceSocketSendTypes, EthernetHeaderParams,
45 ReceivedFrame,
46};
47use crate::internal::state::{DeviceStateSpec, IpLinkDeviceState};
48
49const ETHERNET_HDR_LEN_NO_TAG_U32: u32 = ETHERNET_HDR_LEN_NO_TAG as u32;
50
51pub trait EthernetIpLinkDeviceBindingsContext:
53 RngContext + TimerContext + DeviceLayerTypes + TxMetadataBindingsTypes
54{
55}
56impl<BC: RngContext + TimerContext + DeviceLayerTypes + TxMetadataBindingsTypes>
57 EthernetIpLinkDeviceBindingsContext for BC
58{
59}
60
61pub trait EthernetDeviceEventBindingsContext<DeviceId>:
66 EventContext<EthernetDeviceEvent<DeviceId>>
67{
68}
69impl<BC: EventContext<EthernetDeviceEvent<DeviceId>>, DeviceId>
70 EthernetDeviceEventBindingsContext<DeviceId> for BC
71{
72}
73
74pub trait EthernetIpLinkDeviceStaticStateContext: DeviceIdContext<EthernetLinkDevice> {
76 fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
79 &mut self,
80 device_id: &Self::DeviceId,
81 cb: F,
82 ) -> O;
83}
84
85pub trait EthernetIpLinkDeviceDynamicStateContext<BC: EthernetIpLinkDeviceBindingsContext>:
87 EthernetIpLinkDeviceStaticStateContext
88{
89 fn with_ethernet_state<
92 O,
93 F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
94 >(
95 &mut self,
96 device_id: &Self::DeviceId,
97 cb: F,
98 ) -> O;
99
100 fn with_ethernet_state_mut<
103 O,
104 F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
105 >(
106 &mut self,
107 device_id: &Self::DeviceId,
108 cb: F,
109 ) -> O;
110}
111
112#[derive(Debug, PartialEq, Eq, Hash)]
114pub enum EthernetDeviceEvent<D> {
115 MulticastJoin {
117 device: D,
119 addr: MulticastAddr<Mac>,
121 },
122
123 MulticastLeave {
125 device: D,
127 addr: MulticastAddr<Mac>,
129 },
130}
131
132impl<D> EthernetDeviceEvent<D> {
133 pub fn map_device<N, F: FnOnce(D) -> N>(self, map: F) -> EthernetDeviceEvent<N> {
135 match self {
136 Self::MulticastJoin { device, addr } => {
137 EthernetDeviceEvent::MulticastJoin { device: map(device), addr }
138 }
139 Self::MulticastLeave { device, addr } => {
140 EthernetDeviceEvent::MulticastLeave { device: map(device), addr }
141 }
142 }
143 }
144}
145
146pub fn send_as_ethernet_frame_to_dst<S, BC, CC>(
148 core_ctx: &mut CC,
149 bindings_ctx: &mut BC,
150 device_id: &CC::DeviceId,
151 dst_mac: Mac,
152 body: S,
153 ether_type: EtherType,
154 meta: BC::TxMetadata,
155) -> Result<(), SendFrameError<S>>
156where
157 S: NetworkSerializer,
158 S::Buffer: BufferMut,
159 BC: EthernetIpLinkDeviceBindingsContext,
160 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
161 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
162 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
163{
164 const MIN_BODY_LEN: usize = 0;
170
171 let local_mac = get_mac(core_ctx, device_id);
172 let max_frame_size = get_max_frame_size(core_ctx, device_id);
173 let frame = EthernetFrameBuilder::new(local_mac.get(), dst_mac, ether_type, MIN_BODY_LEN)
174 .wrap_body(body)
175 .with_size_limit(max_frame_size.into());
176 send_ethernet_frame(core_ctx, bindings_ctx, device_id, frame, meta)
177 .map_err(|err| err.into_inner().into_inner())
178}
179
180fn send_ethernet_frame<S, BC, CC>(
181 core_ctx: &mut CC,
182 bindings_ctx: &mut BC,
183 device_id: &CC::DeviceId,
184 frame: S,
185 meta: BC::TxMetadata,
186) -> Result<(), SendFrameError<S>>
187where
188 S: NetworkSerializer,
189 S::Buffer: BufferMut,
190 BC: EthernetIpLinkDeviceBindingsContext,
191 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
192 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
193 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
194{
195 core_ctx.increment_both(device_id, |counters| &counters.send_total_frames);
196 match TransmitQueueHandler::<EthernetLinkDevice, _>::queue_tx_frame(
197 core_ctx,
198 bindings_ctx,
199 device_id,
200 meta,
201 frame,
202 ) {
203 Ok(len) => {
204 core_ctx.add_both_usize(device_id, len, |counters| &counters.send_bytes);
205 core_ctx.increment_both(device_id, |counters| &counters.send_frame);
206 Ok(())
207 }
208 Err(TransmitQueueFrameError::NoQueue(err)) => {
209 core_ctx.increment_both(device_id, |counters| &counters.send_dropped_no_queue);
210 debug!("device {device_id:?} failed to send frame: {err:?}.");
211 Ok(())
212 }
213 Err(TransmitQueueFrameError::QueueFull(serializer)) => {
214 core_ctx.increment_both(device_id, |counters| &counters.send_queue_full);
215 Err(SendFrameError { serializer, error: SendFrameErrorReason::QueueFull })
216 }
217 Err(TransmitQueueFrameError::SerializeError(err)) => {
218 core_ctx.increment_both(device_id, |counters| &counters.send_serialize_error);
219 Err(err.err_into())
220 }
221 }
222}
223
224#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
230pub struct MaxEthernetFrameSize(NonZeroU32);
231
232impl MaxEthernetFrameSize {
233 pub const MIN: MaxEthernetFrameSize = MaxEthernetFrameSize(NonZeroU32::new(60).unwrap());
237
238 pub const fn new(frame_size: u32) -> Option<Self> {
241 if frame_size < Self::MIN.get().get() {
242 return None;
243 }
244 Some(Self(NonZeroU32::new(frame_size).unwrap()))
245 }
246
247 const fn get(&self) -> NonZeroU32 {
248 let Self(frame_size) = *self;
249 frame_size
250 }
251
252 pub const fn as_mtu(&self) -> Mtu {
254 Mtu::new(self.get().get().saturating_sub(ETHERNET_HDR_LEN_NO_TAG_U32))
256 }
257
258 pub const fn from_mtu(mtu: Mtu) -> Option<MaxEthernetFrameSize> {
260 let frame_size = mtu.get().saturating_add(ETHERNET_HDR_LEN_NO_TAG_U32);
261 Self::new(frame_size)
262 }
263}
264
265impl From<MaxEthernetFrameSize> for usize {
266 fn from(MaxEthernetFrameSize(v): MaxEthernetFrameSize) -> Self {
267 v.get().try_into().expect("u32 doesn't fit in usize")
268 }
269}
270
271#[derive(Debug)]
273pub struct EthernetCreationProperties {
274 pub mac: UnicastAddr<Mac>,
276 pub max_frame_size: MaxEthernetFrameSize,
287 pub tx_offload_spec: netstack3_base::ChecksumOffloadSpec,
289}
290
291pub struct DynamicEthernetDeviceState {
293 max_frame_size: MaxEthernetFrameSize,
295
296 link_multicast_groups: RefCountedHashSet<MulticastAddr<Mac>>,
298}
299
300impl DynamicEthernetDeviceState {
301 fn new(max_frame_size: MaxEthernetFrameSize) -> Self {
302 Self { max_frame_size, link_multicast_groups: Default::default() }
303 }
304}
305
306pub struct StaticEthernetDeviceState {
308 mac: UnicastAddr<Mac>,
310
311 max_frame_size: MaxEthernetFrameSize,
313}
314
315pub struct EthernetDeviceState<BT: DeviceLayerTypes> {
317 pub counters: EthernetDeviceCounters,
319 pub static_state: StaticEthernetDeviceState,
321 pub tx_queue: TransmitQueue<
323 BT::TxMetadata,
324 <EthernetLinkDevice as DeviceBufferSpec<BT>>::TxBuffer,
325 <EthernetLinkDevice as DeviceBufferSpec<BT>>::TxAllocator,
326 >,
327 ipv4_arp: Mutex<ArpState<EthernetLinkDevice, BT>>,
328 ipv6_nud: Mutex<NudState<Ipv6, EthernetLinkDevice, BT>>,
329 ipv4_nud_config: RwLock<IpMarked<Ipv4, NudUserConfig>>,
330 ipv6_nud_config: RwLock<IpMarked<Ipv6, NudUserConfig>>,
331 dynamic_state: RwLock<DynamicEthernetDeviceState>,
332}
333
334impl<BT: DeviceLayerTypes, I: Ip> OrderedLockAccess<IpMarked<I, NudUserConfig>>
335 for IpLinkDeviceState<EthernetLinkDevice, BT>
336{
337 type Lock = RwLock<IpMarked<I, NudUserConfig>>;
338 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
339 OrderedLockRef::new(I::map_ip(
340 (),
341 |()| &self.link.ipv4_nud_config,
342 |()| &self.link.ipv6_nud_config,
343 ))
344 }
345}
346
347impl<BT: DeviceLayerTypes> OrderedLockAccess<DynamicEthernetDeviceState>
348 for IpLinkDeviceState<EthernetLinkDevice, BT>
349{
350 type Lock = RwLock<DynamicEthernetDeviceState>;
351 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
352 OrderedLockRef::new(&self.link.dynamic_state)
353 }
354}
355
356impl<BT: DeviceLayerTypes> OrderedLockAccess<NudState<Ipv6, EthernetLinkDevice, BT>>
357 for IpLinkDeviceState<EthernetLinkDevice, BT>
358{
359 type Lock = Mutex<NudState<Ipv6, EthernetLinkDevice, BT>>;
360 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
361 OrderedLockRef::new(&self.link.ipv6_nud)
362 }
363}
364
365impl<BT: DeviceLayerTypes> OrderedLockAccess<ArpState<EthernetLinkDevice, BT>>
366 for IpLinkDeviceState<EthernetLinkDevice, BT>
367{
368 type Lock = Mutex<ArpState<EthernetLinkDevice, BT>>;
369 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
370 OrderedLockRef::new(&self.link.ipv4_arp)
371 }
372}
373
374impl<BT: DeviceLayerTypes>
375 OrderedLockAccess<TransmitQueueState<BT::TxMetadata, BT::TxBuffer, BT::TxAllocator>>
376 for IpLinkDeviceState<EthernetLinkDevice, BT>
377{
378 type Lock = Mutex<TransmitQueueState<BT::TxMetadata, BT::TxBuffer, BT::TxAllocator>>;
379 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
380 OrderedLockRef::new(&self.link.tx_queue.queue)
381 }
382}
383
384impl<BT: DeviceLayerTypes> OrderedLockAccess<DequeueState<BT::TxMetadata, BT::TxBuffer>>
385 for IpLinkDeviceState<EthernetLinkDevice, BT>
386{
387 type Lock = Mutex<DequeueState<BT::TxMetadata, BT::TxBuffer>>;
388 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
389 OrderedLockRef::new(&self.link.tx_queue.deque)
390 }
391}
392
393#[derive(Clone, Eq, PartialEq, Debug, Hash, GenericOverIp)]
397#[generic_over_ip()]
398#[allow(missing_docs)]
399pub enum EthernetTimerId<D: WeakDeviceIdentifier> {
400 Arp(ArpTimerId<EthernetLinkDevice, D>),
401 Nudv6(NudTimerId<Ipv6, EthernetLinkDevice, D>),
402}
403
404impl<I: Ip, D: WeakDeviceIdentifier> From<NudTimerId<I, EthernetLinkDevice, D>>
405 for EthernetTimerId<D>
406{
407 fn from(id: NudTimerId<I, EthernetLinkDevice, D>) -> EthernetTimerId<D> {
408 I::map_ip(id, EthernetTimerId::Arp, EthernetTimerId::Nudv6)
409 }
410}
411
412impl<CC, BC> HandleableTimer<CC, BC> for EthernetTimerId<CC::WeakDeviceId>
413where
414 BC: EthernetIpLinkDeviceBindingsContext,
415 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
416 + TimerHandler<BC, NudTimerId<Ipv6, EthernetLinkDevice, CC::WeakDeviceId>>
417 + TimerHandler<BC, ArpTimerId<EthernetLinkDevice, CC::WeakDeviceId>>,
418{
419 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
420 match self {
421 EthernetTimerId::Arp(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
422 EthernetTimerId::Nudv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
423 }
424 }
425}
426
427pub fn send_ip_frame<BC, CC, I, S>(
434 core_ctx: &mut CC,
435 bindings_ctx: &mut BC,
436 device_id: &CC::DeviceId,
437 destination: IpPacketDestination<I, &DeviceId<BC>>,
438 body: S,
439 meta: BC::TxMetadata,
440) -> Result<(), SendFrameError<S>>
441where
442 BC: EthernetIpLinkDeviceBindingsContext + LinkResolutionContext<EthernetLinkDevice>,
443 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
444 + NudHandler<I, EthernetLinkDevice, BC>
445 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
446 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
447 I: EthernetIpExt + BroadcastIpExt,
448 S: NetworkSerializer,
449 S::Buffer: BufferMut,
450{
451 core_ctx.increment_both(device_id, DeviceCounters::send_frame::<I>);
452
453 trace!("ethernet::send_ip_frame: destination = {:?}; device = {:?}", destination, device_id);
454
455 match destination {
456 IpPacketDestination::Broadcast(marker) => {
457 I::map_ip::<_, ()>(
458 WrapBroadcastMarker(marker),
459 |WrapBroadcastMarker(())| (),
460 |WrapBroadcastMarker(never)| match never {},
461 );
462 send_as_ethernet_frame_to_dst(
463 core_ctx,
464 bindings_ctx,
465 device_id,
466 Mac::BROADCAST,
467 body,
468 I::ETHER_TYPE,
469 meta,
470 )
471 }
472 IpPacketDestination::Multicast(multicast_ip) => send_as_ethernet_frame_to_dst(
473 core_ctx,
474 bindings_ctx,
475 device_id,
476 Mac::from(&multicast_ip),
477 body,
478 I::ETHER_TYPE,
479 meta,
480 ),
481 IpPacketDestination::Neighbor(ip) => NudHandler::<I, _, _>::send_ip_packet_to_neighbor(
482 core_ctx,
483 bindings_ctx,
484 device_id,
485 ip,
486 body,
487 meta,
488 ),
489 IpPacketDestination::Loopback(_) => {
490 unreachable!("Loopback packets must be delivered through the loopback device")
491 }
492 }
493}
494
495pub struct RecvEthernetFrameMeta<D> {
497 pub device_id: D,
499 pub parsing_context: NetworkParsingContext,
501 pub gso_info: Option<GsoInfo>,
503}
504
505impl DeviceReceiveFrameSpec for EthernetLinkDevice {
506 type FrameMetadata<D> = RecvEthernetFrameMeta<D>;
507}
508
509impl<CC, BC> ReceivableFrameMeta<CC, BC> for RecvEthernetFrameMeta<CC::DeviceId>
510where
511 BC: EthernetIpLinkDeviceBindingsContext,
512 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
513 + RecvFrameContext<RecvIpFrameMeta<CC::DeviceId, DeviceIpLayerMetadata<BC>, Ipv4>, BC>
514 + RecvFrameContext<RecvIpFrameMeta<CC::DeviceId, DeviceIpLayerMetadata<BC>, Ipv6>, BC>
515 + ArpPacketHandler<EthernetLinkDevice, BC>
516 + DeviceSocketHandler<EthernetLinkDevice, BC>
517 + ResourceCounterContext<CC::DeviceId, DeviceCounters>
518 + ResourceCounterContext<CC::DeviceId, EthernetDeviceCounters>
519 + ResourceCounterContext<CC::DeviceId, IpCounters<Ipv4>>
520 + ResourceCounterContext<CC::DeviceId, IpCounters<Ipv6>>,
521{
522 fn receive_meta<B: BufferMut + Debug>(
523 self,
524 core_ctx: &mut CC,
525 bindings_ctx: &mut BC,
526 mut buffer: B,
527 ) {
528 trace_duration!("device::ethernet::receive_frame");
529 let Self { device_id, parsing_context, gso_info } = self;
530 trace!("ethernet::receive_frame: device_id = {:?}", device_id);
531 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| &counters.recv_frame);
532 core_ctx.add_both_usize(&device_id, buffer.len(), |counters: &DeviceCounters| {
533 &counters.recv_bytes
534 });
535 let (ethernet, whole_frame) = if let Ok(frame) =
544 buffer.parse_with_view::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::NoCheck)
545 {
546 frame
547 } else {
548 core_ctx
549 .increment_both(&device_id, |counters: &DeviceCounters| &counters.recv_parse_error);
550 trace!("ethernet::receive_frame: failed to parse ethernet frame");
551 return;
552 };
553
554 let src = ethernet.src_mac();
555 let dst = ethernet.dst_mac();
556
557 let frame_dst = core_ctx.with_static_ethernet_device_state(&device_id, |static_state| {
558 FrameDestination::from_dest(dst, static_state.mac.get())
559 });
560
561 let ethertype = ethernet.ethertype();
562
563 core_ctx.handle_frame(
564 bindings_ctx,
565 &device_id,
566 ReceivedFrame::from_ethernet(ethernet, frame_dst).into(),
567 whole_frame,
568 );
569
570 match ethertype {
571 Some(EtherType::Arp) => {
572 let types = if let Ok(types) = peek_arp_types(buffer.as_ref()) {
573 types
574 } else {
575 return;
576 };
577 match types {
578 (ArpHardwareType::Ethernet, ArpNetworkType::Ipv4) => {
579 ArpPacketHandler::handle_packet(
580 core_ctx,
581 bindings_ctx,
582 device_id,
583 src,
584 frame_dst,
585 buffer,
586 )
587 }
588 }
589 }
590 Some(EtherType::Ipv4) => {
591 let local_frame_dst = match frame_dst.check_local() {
592 Some(dst) => dst,
593 None => {
594 core_ctx.increment_both(&device_id, |counters: &IpCounters<Ipv4>| {
595 &counters.drop_ip_packet_other_host
596 });
597 return;
598 }
599 };
600 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
601 &counters.recv_ipv4_delivered
602 });
603 core_ctx.receive_frame(
604 bindings_ctx,
605 RecvIpFrameMeta::<_, _, Ipv4>::new(
606 device_id,
607 Some(local_frame_dst),
608 DeviceIpLayerMetadata::default(),
609 parsing_context,
610 gso_info,
611 ),
612 buffer,
613 )
614 }
615 Some(EtherType::Ipv6) => {
616 let local_frame_dst = match frame_dst.check_local() {
617 Some(dst) => dst,
618 None => {
619 core_ctx.increment_both(&device_id, |counters: &IpCounters<Ipv6>| {
620 &counters.drop_ip_packet_other_host
621 });
622 return;
623 }
624 };
625 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
626 &counters.recv_ipv6_delivered
627 });
628 core_ctx.receive_frame(
629 bindings_ctx,
630 RecvIpFrameMeta::<_, _, Ipv6>::new(
631 device_id,
632 Some(local_frame_dst),
633 DeviceIpLayerMetadata::default(),
634 parsing_context,
635 gso_info,
636 ),
637 buffer,
638 )
639 }
640 Some(EtherType::Other(_)) => {
641 core_ctx.increment_both(&device_id, |counters: &EthernetDeviceCounters| {
642 &counters.recv_unsupported_ethertype
643 });
644 }
645 None => {
646 core_ctx.increment_both(&device_id, |counters: &EthernetDeviceCounters| {
647 &counters.recv_no_ethertype
648 });
649 }
650 }
651 }
652}
653
654pub fn join_link_multicast<
670 BC: EthernetIpLinkDeviceBindingsContext + EthernetDeviceEventBindingsContext<CC::DeviceId>,
671 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
672>(
673 core_ctx: &mut CC,
674 bindings_ctx: &mut BC,
675 device_id: &CC::DeviceId,
676 multicast_addr: MulticastAddr<Mac>,
677) {
678 core_ctx.with_ethernet_state_mut(device_id, |_static_state, dynamic_state| {
679 let groups = &mut dynamic_state.link_multicast_groups;
680
681 match groups.insert(multicast_addr) {
682 InsertResult::Inserted(()) => {
683 trace!(
684 "ethernet::join_link_multicast: joining link multicast {:?}",
685 multicast_addr
686 );
687 bindings_ctx.on_event(EthernetDeviceEvent::MulticastJoin {
688 device: device_id.clone(),
689 addr: multicast_addr,
690 });
691 }
692 InsertResult::AlreadyPresent => {
693 trace!(
694 "ethernet::join_link_multicast: already joined link multicast {:?}",
695 multicast_addr,
696 );
697 }
698 }
699 })
700}
701
702pub fn leave_link_multicast<
721 BC: EthernetIpLinkDeviceBindingsContext + EthernetDeviceEventBindingsContext<CC::DeviceId>,
722 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
723>(
724 core_ctx: &mut CC,
725 bindings_ctx: &mut BC,
726 device_id: &CC::DeviceId,
727 multicast_addr: MulticastAddr<Mac>,
728) {
729 core_ctx.with_ethernet_state_mut(device_id, |_static_state, dynamic_state| {
730 let groups = &mut dynamic_state.link_multicast_groups;
731
732 match groups.remove(multicast_addr) {
733 RemoveResult::Removed(()) => {
734 trace!(
735 "ethernet::leave_link_multicast: \
736 leaving link multicast {:?}",
737 multicast_addr
738 );
739 bindings_ctx.on_event(EthernetDeviceEvent::MulticastLeave {
740 device: device_id.clone(),
741 addr: multicast_addr,
742 });
743 }
744 RemoveResult::StillPresent => {
745 trace!(
746 "ethernet::leave_link_multicast: not leaving link multicast \
747 {:?} as there are still listeners for it",
748 multicast_addr,
749 );
750 }
751 RemoveResult::NotPresent => {
752 panic!(
753 "ethernet::leave_link_multicast: device {:?} has not yet \
754 joined link multicast {:?}",
755 device_id, multicast_addr,
756 );
757 }
758 }
759 })
760}
761
762pub fn get_max_frame_size<
763 BC: EthernetIpLinkDeviceBindingsContext,
764 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
765>(
766 core_ctx: &mut CC,
767 device_id: &CC::DeviceId,
768) -> MaxEthernetFrameSize {
769 core_ctx
770 .with_ethernet_state(device_id, |_static_state, dynamic_state| dynamic_state.max_frame_size)
771}
772
773pub fn get_mtu<
775 BC: EthernetIpLinkDeviceBindingsContext,
776 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
777>(
778 core_ctx: &mut CC,
779 device_id: &CC::DeviceId,
780) -> Mtu {
781 get_max_frame_size(core_ctx, device_id).as_mtu()
782}
783
784pub trait UseArpFrameMetadataBlanket {}
790
791impl<
792 BC: EthernetIpLinkDeviceBindingsContext,
793 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
794 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
795 + ResourceCounterContext<CC::DeviceId, DeviceCounters>
796 + UseArpFrameMetadataBlanket,
797> SendableFrameMeta<CC, BC> for ArpFrameMetadata<EthernetLinkDevice, CC::DeviceId>
798{
799 fn send_meta<S>(
800 self,
801 core_ctx: &mut CC,
802 bindings_ctx: &mut BC,
803 body: S,
804 ) -> Result<(), SendFrameError<S>>
805 where
806 S: NetworkSerializer,
807 S::Buffer: BufferMut,
808 {
809 let Self { device_id, dst_addr } = self;
810 let meta: BC::TxMetadata = Default::default();
811 send_as_ethernet_frame_to_dst(
812 core_ctx,
813 bindings_ctx,
814 &device_id,
815 dst_addr.get(),
816 body,
817 EtherType::Arp,
818 meta,
819 )
820 }
821}
822
823impl DeviceSocketSendTypes for EthernetLinkDevice {
824 type Metadata = Option<EthernetHeaderParams>;
827}
828
829impl<
830 BC: EthernetIpLinkDeviceBindingsContext,
831 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
832 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
833 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
834> SendableFrameMeta<CC, BC> for DeviceSocketMetadata<EthernetLinkDevice, EthernetDeviceId<BC>>
835where
836 CC: DeviceIdContext<EthernetLinkDevice, DeviceId = EthernetDeviceId<BC>>,
837{
838 fn send_meta<S>(
839 self,
840 core_ctx: &mut CC,
841 bindings_ctx: &mut BC,
842 body: S,
843 ) -> Result<(), SendFrameError<S>>
844 where
845 S: NetworkSerializer,
846 S::Buffer: BufferMut,
847 {
848 let Self { device_id, metadata } = self;
849 let tx_meta: BC::TxMetadata = Default::default();
852 match metadata {
853 Some(EthernetHeaderParams { dest_addr, protocol }) => send_as_ethernet_frame_to_dst(
854 core_ctx,
855 bindings_ctx,
856 &device_id,
857 dest_addr,
858 body,
859 protocol,
860 tx_meta,
861 ),
862 None => send_ethernet_frame(core_ctx, bindings_ctx, &device_id, body, tx_meta),
863 }
864 }
865}
866
867pub fn get_mac<
869 'a,
870 BC: EthernetIpLinkDeviceBindingsContext,
871 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
872>(
873 core_ctx: &'a mut CC,
874 device_id: &CC::DeviceId,
875) -> UnicastAddr<Mac> {
876 core_ctx.with_static_ethernet_device_state(device_id, |state| state.mac)
877}
878
879pub fn set_mtu<
881 BC: EthernetIpLinkDeviceBindingsContext,
882 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
883>(
884 core_ctx: &mut CC,
885 device_id: &CC::DeviceId,
886 mtu: Mtu,
887) {
888 core_ctx.with_ethernet_state_mut(device_id, |static_state, dynamic_state| {
889 if let Some(mut frame_size ) = MaxEthernetFrameSize::from_mtu(mtu) {
890 if frame_size > static_state.max_frame_size {
893 trace!("ethernet::ndp_device::set_mtu: MTU of {:?} is greater than the device {:?}'s max MTU of {:?}, using device's max MTU instead", mtu, device_id, static_state.max_frame_size.as_mtu());
894 frame_size = static_state.max_frame_size;
895 }
896 trace!("ethernet::ndp_device::set_mtu: setting link MTU to {:?}", mtu);
897 dynamic_state.max_frame_size = frame_size;
898 }
899 })
900}
901
902#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
904pub enum EthernetLinkDevice {}
905
906impl Device for EthernetLinkDevice {}
907
908impl LinkDevice for EthernetLinkDevice {
909 type Address = Mac;
910}
911
912impl<BT: DeviceBufferBindingsTypes> DeviceBufferSpec<BT> for EthernetLinkDevice {
913 type TxBuffer = BT::TxBuffer;
914 type TxAllocator = BT::TxAllocator;
915}
916
917impl DeviceStateSpec for EthernetLinkDevice {
918 type State<BT: DeviceLayerTypes> = EthernetDeviceState<BT>;
919 type External<BT: DeviceLayerTypes> = BT::EthernetDeviceState;
920 type CreationProperties = EthernetCreationProperties;
921 type Counters = EthernetDeviceCounters;
922 type TimerId<D: WeakDeviceIdentifier> = EthernetTimerId<D>;
923
924 fn new_device_state<
925 CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
926 BC: DeviceLayerTypes + TimerContext,
927 >(
928 bindings_ctx: &mut BC,
929 self_id: CC::WeakDeviceId,
930 EthernetCreationProperties { mac, max_frame_size, tx_offload_spec }: Self::CreationProperties,
931 tx_allocator: <Self as DeviceBufferSpec<BC>>::TxAllocator,
932 ) -> Self::State<BC>
933 where
934 Self: DeviceBufferSpec<BC>,
935 {
936 let ipv4_arp = Mutex::new(ArpState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
937 bindings_ctx,
938 self_id.clone(),
939 ));
940 let ipv6_nud =
941 Mutex::new(NudState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx, self_id));
942 EthernetDeviceState {
943 counters: Default::default(),
944 ipv4_arp,
945 ipv6_nud,
946 ipv4_nud_config: Default::default(),
947 ipv6_nud_config: Default::default(),
948 static_state: StaticEthernetDeviceState { mac, max_frame_size },
949 dynamic_state: RwLock::new(DynamicEthernetDeviceState::new(max_frame_size)),
950 tx_queue: TransmitQueue::new(tx_allocator, tx_offload_spec),
951 }
952 }
953 const IS_LOOPBACK: bool = false;
954 const DEBUG_TYPE: &'static str = "Ethernet";
955
956 fn tx_offload_spec<BT: DeviceLayerTypes>(
957 state: &Self::State<BT>,
958 ) -> Option<ChecksumOffloadSpec> {
959 Some(state.tx_queue.tx_offload_spec())
960 }
961}
962
963#[cfg(any(test, feature = "testutils"))]
964pub(crate) mod testutil {
965 use super::*;
966
967 pub const IPV6_MIN_IMPLIED_MAX_FRAME_SIZE: MaxEthernetFrameSize =
969 MaxEthernetFrameSize::from_mtu(Ipv6::MINIMUM_LINK_MTU).unwrap();
970}
971
972#[cfg(test)]
973mod tests {
974 use alloc::vec;
975 use alloc::vec::Vec;
976 use netstack3_hashmap::HashSet;
977
978 use net_types::SpecifiedAddr;
979 use net_types::ip::{Ipv4Addr, Ipv6Addr};
980 use netstack3_base::testutil::{
981 FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId, TEST_ADDRS_V4,
982 };
983 use netstack3_base::{CounterContext, CtxPair, IntoCoreTimerCtx};
984 use netstack3_ip::nud::{
985 self, DelegateNudContext, DynamicNeighborUpdateSource, NeighborApi, UseDelegateNudContext,
986 };
987 use packet::Buf;
988 use packet_formats::testutil::parse_ethernet_frame;
989
990 use super::*;
991 use crate::internal::arp::{
992 ArpConfigContext, ArpContext, ArpCounters, ArpNudCtx, ArpSenderContext,
993 };
994 use crate::internal::base::{DeviceBufferBindingsTypes, DeviceSendFrameError};
995 use crate::internal::ethernet::testutil::IPV6_MIN_IMPLIED_MAX_FRAME_SIZE;
996 use crate::internal::queue::tx::{
997 BufVecU8Allocator, TransmitQueueBindingsContext, TransmitQueueCommon, TransmitQueueContext,
998 };
999 use crate::internal::socket::{Frame, ParseSentFrameError, SentFrame};
1000
1001 struct FakeEthernetCtx {
1002 static_state: StaticEthernetDeviceState,
1003 dynamic_state: DynamicEthernetDeviceState,
1004 tx_queue: TransmitQueueState<FakeTxMetadata, Buf<Vec<u8>>, BufVecU8Allocator>,
1005 counters: DeviceCounters,
1006 per_device_counters: DeviceCounters,
1007 ethernet_counters: EthernetDeviceCounters,
1008 arp_counters: ArpCounters,
1009 }
1010
1011 impl FakeEthernetCtx {
1012 fn new(mac: UnicastAddr<Mac>, max_frame_size: MaxEthernetFrameSize) -> FakeEthernetCtx {
1013 FakeEthernetCtx {
1014 static_state: StaticEthernetDeviceState { max_frame_size, mac },
1015 dynamic_state: DynamicEthernetDeviceState::new(max_frame_size),
1016 tx_queue: Default::default(),
1017 counters: Default::default(),
1018 per_device_counters: Default::default(),
1019 ethernet_counters: Default::default(),
1020 arp_counters: Default::default(),
1021 }
1022 }
1023 }
1024
1025 type FakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<
1026 EthernetTimerId<FakeWeakDeviceId<FakeDeviceId>>,
1027 nud::Event<Mac, FakeDeviceId, Ipv4, FakeInstant>,
1028 FakeBindingsState,
1029 (),
1030 >;
1031
1032 #[derive(Default)]
1033 struct FakeBindingsState {
1034 link_multicast_group_memberships: HashSet<(FakeDeviceId, MulticastAddr<Mac>)>,
1035 }
1036
1037 type FakeInnerCtx =
1038 netstack3_base::testutil::FakeCoreCtx<FakeEthernetCtx, FakeDeviceId, FakeDeviceId>;
1039
1040 struct FakeCoreCtx {
1041 arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1042 inner: FakeInnerCtx,
1043 }
1044
1045 fn new_context() -> CtxPair<FakeCoreCtx, FakeBindingsCtx> {
1046 CtxPair::with_default_bindings_ctx(|bindings_ctx| FakeCoreCtx {
1047 arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
1048 bindings_ctx,
1049 FakeWeakDeviceId(FakeDeviceId),
1050 ),
1051 inner: FakeInnerCtx::with_state(FakeEthernetCtx::new(
1052 TEST_ADDRS_V4.local_mac,
1053 IPV6_MIN_IMPLIED_MAX_FRAME_SIZE,
1054 )),
1055 })
1056 }
1057
1058 impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1059 fn handle_frame(
1060 &mut self,
1061 bindings_ctx: &mut FakeBindingsCtx,
1062 device: &Self::DeviceId,
1063 frame: Frame<&[u8]>,
1064 whole_frame: &[u8],
1065 ) {
1066 self.inner.handle_frame(bindings_ctx, device, frame, whole_frame)
1067 }
1068 }
1069
1070 impl CounterContext<DeviceCounters> for FakeCoreCtx {
1071 fn counters(&self) -> &DeviceCounters {
1072 &self.inner.state.counters
1073 }
1074 }
1075
1076 impl CounterContext<DeviceCounters> for FakeInnerCtx {
1077 fn counters(&self) -> &DeviceCounters {
1078 &self.state.counters
1079 }
1080 }
1081
1082 impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeCoreCtx {
1083 fn per_resource_counters<'a>(
1084 &'a self,
1085 &FakeDeviceId: &'a FakeDeviceId,
1086 ) -> &'a DeviceCounters {
1087 &self.inner.state.per_device_counters
1088 }
1089 }
1090
1091 impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeInnerCtx {
1092 fn per_resource_counters<'a>(
1093 &'a self,
1094 &FakeDeviceId: &'a FakeDeviceId,
1095 ) -> &'a DeviceCounters {
1096 &self.state.per_device_counters
1097 }
1098 }
1099
1100 impl CounterContext<EthernetDeviceCounters> for FakeCoreCtx {
1101 fn counters(&self) -> &EthernetDeviceCounters {
1102 &self.inner.state.ethernet_counters
1103 }
1104 }
1105
1106 impl CounterContext<EthernetDeviceCounters> for FakeInnerCtx {
1107 fn counters(&self) -> &EthernetDeviceCounters {
1108 &self.state.ethernet_counters
1109 }
1110 }
1111
1112 impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1113 fn handle_frame(
1114 &mut self,
1115 _bindings_ctx: &mut FakeBindingsCtx,
1116 _device: &Self::DeviceId,
1117 _frame: Frame<&[u8]>,
1118 _whole_frame: &[u8],
1119 ) {
1120 }
1122 }
1123
1124 impl EthernetIpLinkDeviceStaticStateContext for FakeCoreCtx {
1125 fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1126 &mut self,
1127 device_id: &FakeDeviceId,
1128 cb: F,
1129 ) -> O {
1130 self.inner.with_static_ethernet_device_state(device_id, cb)
1131 }
1132 }
1133
1134 impl EthernetIpLinkDeviceStaticStateContext for FakeInnerCtx {
1135 fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1136 &mut self,
1137 &FakeDeviceId: &FakeDeviceId,
1138 cb: F,
1139 ) -> O {
1140 cb(&self.state.static_state)
1141 }
1142 }
1143
1144 impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeCoreCtx {
1145 fn with_ethernet_state<
1146 O,
1147 F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1148 >(
1149 &mut self,
1150 device_id: &FakeDeviceId,
1151 cb: F,
1152 ) -> O {
1153 self.inner.with_ethernet_state(device_id, cb)
1154 }
1155
1156 fn with_ethernet_state_mut<
1157 O,
1158 F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1159 >(
1160 &mut self,
1161 device_id: &FakeDeviceId,
1162 cb: F,
1163 ) -> O {
1164 self.inner.with_ethernet_state_mut(device_id, cb)
1165 }
1166 }
1167
1168 impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeInnerCtx {
1169 fn with_ethernet_state<
1170 O,
1171 F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1172 >(
1173 &mut self,
1174 &FakeDeviceId: &FakeDeviceId,
1175 cb: F,
1176 ) -> O {
1177 let FakeEthernetCtx { static_state, dynamic_state, .. } = &self.state;
1178 cb(static_state, dynamic_state)
1179 }
1180
1181 fn with_ethernet_state_mut<
1182 O,
1183 F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1184 >(
1185 &mut self,
1186 &FakeDeviceId: &FakeDeviceId,
1187 cb: F,
1188 ) -> O {
1189 let FakeEthernetCtx { static_state, dynamic_state, .. } = &mut self.state;
1190 cb(static_state, dynamic_state)
1191 }
1192 }
1193
1194 impl NudHandler<Ipv6, EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1195 fn handle_neighbor_update(
1196 &mut self,
1197 _bindings_ctx: &mut FakeBindingsCtx,
1198 _device_id: &Self::DeviceId,
1199 _neighbor: SpecifiedAddr<Ipv6Addr>,
1200 _source: DynamicNeighborUpdateSource<Mac>,
1201 ) {
1202 unimplemented!()
1203 }
1204
1205 fn flush(&mut self, _bindings_ctx: &mut FakeBindingsCtx, _device_id: &Self::DeviceId) {
1206 unimplemented!()
1207 }
1208
1209 fn send_ip_packet_to_neighbor<S>(
1210 &mut self,
1211 _bindings_ctx: &mut FakeBindingsCtx,
1212 _device_id: &Self::DeviceId,
1213 _neighbor: SpecifiedAddr<Ipv6Addr>,
1214 _body: S,
1215 _tx_meta: FakeTxMetadata,
1216 ) -> Result<(), SendFrameError<S>> {
1217 unimplemented!()
1218 }
1219 }
1220
1221 struct FakeCoreCtxWithDeviceId<'a> {
1222 core_ctx: &'a mut FakeInnerCtx,
1223 device_id: &'a FakeDeviceId,
1224 }
1225
1226 impl<'a> DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxWithDeviceId<'a> {
1227 type DeviceId = FakeDeviceId;
1228 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1229 }
1230
1231 impl<'a> ArpConfigContext for FakeCoreCtxWithDeviceId<'a> {
1232 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1233 cb(&NudUserConfig::default())
1234 }
1235 }
1236
1237 impl UseArpFrameMetadataBlanket for FakeCoreCtx {}
1238
1239 impl ArpContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1240 type ConfigCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1241
1242 type ArpSenderCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1243
1244 fn with_arp_state_mut_and_sender_ctx<
1245 O,
1246 F: FnOnce(
1247 &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1248 &mut Self::ArpSenderCtx<'_>,
1249 ) -> O,
1250 >(
1251 &mut self,
1252 device_id: &Self::DeviceId,
1253 cb: F,
1254 ) -> O {
1255 let Self { arp_state, inner } = self;
1256 cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1257 }
1258
1259 fn get_protocol_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Ipv4Addr> {
1260 unimplemented!()
1261 }
1262
1263 fn get_hardware_addr(
1264 &mut self,
1265 _bindings_ctx: &mut FakeBindingsCtx,
1266 _device_id: &Self::DeviceId,
1267 ) -> UnicastAddr<Mac> {
1268 self.inner.state.static_state.mac
1269 }
1270
1271 fn with_arp_state_mut<
1272 O,
1273 F: FnOnce(
1274 &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1275 &mut Self::ConfigCtx<'_>,
1276 ) -> O,
1277 >(
1278 &mut self,
1279 device_id: &Self::DeviceId,
1280 cb: F,
1281 ) -> O {
1282 let Self { arp_state, inner } = self;
1283 cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1284 }
1285
1286 fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtx>) -> O>(
1287 &mut self,
1288 FakeDeviceId: &Self::DeviceId,
1289 cb: F,
1290 ) -> O {
1291 cb(&mut self.arp_state)
1292 }
1293 }
1294
1295 impl UseDelegateNudContext for FakeCoreCtx {}
1296 impl DelegateNudContext<Ipv4> for FakeCoreCtx {
1297 type Delegate<T> = ArpNudCtx<T>;
1298 }
1299
1300 impl ArpConfigContext for FakeInnerCtx {
1301 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1302 cb(&NudUserConfig::default())
1303 }
1304 }
1305
1306 impl<'a> ArpSenderContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtxWithDeviceId<'a> {
1307 fn send_ip_packet_to_neighbor_link_addr<S>(
1308 &mut self,
1309 bindings_ctx: &mut FakeBindingsCtx,
1310 link_addr: UnicastAddr<Mac>,
1311 body: S,
1312 tx_meta: FakeTxMetadata,
1313 ) -> Result<(), SendFrameError<S>>
1314 where
1315 S: NetworkSerializer,
1316 S::Buffer: BufferMut,
1317 {
1318 let Self { core_ctx, device_id } = self;
1319 send_as_ethernet_frame_to_dst(
1320 *core_ctx,
1321 bindings_ctx,
1322 device_id,
1323 link_addr.get(),
1324 body,
1325 EtherType::Ipv4,
1326 tx_meta,
1327 )
1328 }
1329 }
1330
1331 impl TransmitQueueBindingsContext<FakeDeviceId> for FakeBindingsCtx {
1332 fn wake_tx_task(&mut self, FakeDeviceId: &FakeDeviceId) {
1333 unimplemented!("unused by tests")
1334 }
1335 }
1336
1337 impl EventContext<EthernetDeviceEvent<FakeDeviceId>> for FakeBindingsCtx {
1338 fn on_event(&mut self, event: EthernetDeviceEvent<FakeDeviceId>) {
1339 match event {
1341 EthernetDeviceEvent::MulticastJoin { device, addr } => {
1342 assert!(
1343 self.state.link_multicast_group_memberships.insert((device, addr)),
1344 "membership should not be present"
1345 );
1346 }
1347 EthernetDeviceEvent::MulticastLeave { device, addr } => {
1348 assert!(
1349 self.state.link_multicast_group_memberships.remove(&(device, addr)),
1350 "membership should be present"
1351 );
1352 }
1353 }
1354 }
1355 }
1356
1357 impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1358 type Meta = FakeTxMetadata;
1359
1360 type DequeueContext = !;
1361
1362 fn parse_outgoing_frame<'a>(
1363 buf: &'a [u8],
1364 meta: &'a Self::Meta,
1365 ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1366 FakeInnerCtx::parse_outgoing_frame(buf, meta)
1367 }
1368 }
1369
1370 impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1371 type Meta = FakeTxMetadata;
1372
1373 type DequeueContext = !;
1374
1375 fn parse_outgoing_frame<'a, 'b>(
1376 buf: &'a [u8],
1377 _tx_meta: &'b Self::Meta,
1378 ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1379 SentFrame::try_parse_as_ethernet(buf)
1380 }
1381 }
1382
1383 impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1384 fn with_transmit_queue_mut<
1385 O,
1386 F: FnOnce(
1387 &mut TransmitQueueState<Self::Meta, packet::Buf<Vec<u8>>, BufVecU8Allocator>,
1388 ) -> O,
1389 >(
1390 &mut self,
1391 device_id: &Self::DeviceId,
1392 cb: F,
1393 ) -> O {
1394 self.inner.with_transmit_queue_mut(device_id, cb)
1395 }
1396
1397 fn with_transmit_queue<
1398 O,
1399 F: FnOnce(&TransmitQueueState<Self::Meta, packet::Buf<Vec<u8>>, BufVecU8Allocator>) -> O,
1400 >(
1401 &mut self,
1402 device_id: &Self::DeviceId,
1403 cb: F,
1404 ) -> O {
1405 self.inner.with_transmit_queue(device_id, cb)
1406 }
1407
1408 fn send_frame(
1409 &mut self,
1410 bindings_ctx: &mut FakeBindingsCtx,
1411 device_id: &Self::DeviceId,
1412 dequeue_context: Option<&mut !>,
1413 tx_meta: Self::Meta,
1414 buf: packet::Buf<Vec<u8>>,
1415 ) -> Result<(), DeviceSendFrameError> {
1416 TransmitQueueContext::send_frame(
1417 &mut self.inner,
1418 bindings_ctx,
1419 device_id,
1420 dequeue_context,
1421 tx_meta,
1422 buf,
1423 )
1424 }
1425 }
1426
1427 impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx
1428 where
1429 Self: TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx, Meta = FakeTxMetadata>,
1430 {
1431 fn with_transmit_queue_mut<
1432 O,
1433 F: FnOnce(
1434 &mut TransmitQueueState<
1435 Self::Meta,
1436 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxBuffer,
1437 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxAllocator,
1438 >,
1439 ) -> O,
1440 >(
1441 &mut self,
1442 _device_id: &Self::DeviceId,
1443 cb: F,
1444 ) -> O {
1445 cb(&mut self.state.tx_queue)
1446 }
1447
1448 fn with_transmit_queue<
1449 O,
1450 F: FnOnce(
1451 &TransmitQueueState<
1452 Self::Meta,
1453 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxBuffer,
1454 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxAllocator,
1455 >,
1456 ) -> O,
1457 >(
1458 &mut self,
1459 _device_id: &Self::DeviceId,
1460 cb: F,
1461 ) -> O {
1462 cb(&self.state.tx_queue)
1463 }
1464
1465 fn send_frame(
1466 &mut self,
1467 _bindings_ctx: &mut FakeBindingsCtx,
1468 device_id: &Self::DeviceId,
1469 dequeue_context: Option<&mut !>,
1470 _tx_meta: Self::Meta,
1471 buf: packet::Buf<Vec<u8>>,
1472 ) -> Result<(), DeviceSendFrameError> {
1473 match dequeue_context {
1474 Some(never) => match *never {},
1475 None => (),
1476 }
1477 self.frames.push(device_id.clone(), buf.as_ref().to_vec());
1478 Ok(())
1479 }
1480 }
1481
1482 impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtx {
1483 type DeviceId = FakeDeviceId;
1484 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1485 }
1486
1487 impl DeviceIdContext<EthernetLinkDevice> for FakeInnerCtx {
1488 type DeviceId = FakeDeviceId;
1489 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1490 }
1491
1492 impl CounterContext<ArpCounters> for FakeCoreCtx {
1493 fn counters(&self) -> &ArpCounters {
1494 &self.inner.state.arp_counters
1495 }
1496 }
1497
1498 #[test]
1499 fn test_mtu() {
1500 fn test(size: usize, expect_frames_sent: bool) {
1504 let mut ctx = new_context();
1505 NeighborApi::<Ipv4, EthernetLinkDevice, _>::new(ctx.as_mut())
1506 .insert_static_entry(
1507 &FakeDeviceId,
1508 TEST_ADDRS_V4.remote_ip.get(),
1509 TEST_ADDRS_V4.remote_mac,
1510 )
1511 .unwrap();
1512 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1513 let result = send_ip_frame::<FakeBindingsCtx, FakeCoreCtx, Ipv4, _>(
1514 core_ctx,
1515 bindings_ctx,
1516 &FakeDeviceId,
1517 IpPacketDestination::<Ipv4, _>::Neighbor(TEST_ADDRS_V4.remote_ip),
1518 Buf::new(&mut vec![0; size], ..),
1519 FakeTxMetadata::default(),
1520 )
1521 .map_err(|_serializer| ());
1522 let sent_frames = core_ctx.inner.frames().len();
1523 if expect_frames_sent {
1524 assert_eq!(sent_frames, 1);
1525 result.expect("should succeed");
1526 } else {
1527 assert_eq!(sent_frames, 0);
1528 result.expect_err("should fail");
1529 }
1530 }
1531
1532 test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap(), true);
1533 test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap() + 1, false);
1534 }
1535
1536 #[test]
1537 fn broadcast() {
1538 let mut ctx = new_context();
1539 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1540 send_ip_frame::<FakeBindingsCtx, FakeCoreCtx, Ipv4, _>(
1541 core_ctx,
1542 bindings_ctx,
1543 &FakeDeviceId,
1544 IpPacketDestination::<Ipv4, _>::Broadcast(()),
1545 Buf::new(&mut vec![0; 100], ..),
1546 FakeTxMetadata::default(),
1547 )
1548 .map_err(|_serializer| ())
1549 .expect("send_ip_frame should succeed");
1550 let sent_frames = core_ctx.inner.frames().len();
1551 assert_eq!(sent_frames, 1);
1552 let (FakeDeviceId, frame) = core_ctx.inner.frames()[0].clone();
1553 let (_body, _src_mac, dst_mac, _ether_type) =
1554 parse_ethernet_frame(&frame, EthernetFrameLengthCheck::NoCheck).unwrap();
1555 assert_eq!(dst_mac, Mac::BROADCAST);
1556 }
1557
1558 #[test]
1559 fn test_join_link_multicast() {
1560 let mut ctx = new_context();
1561 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1562
1563 let address1: MulticastAddr<Mac> =
1564 MulticastAddr::new(Ipv4Addr::new([224, 0, 0, 200])).unwrap().into();
1565 let address2: MulticastAddr<Mac> =
1566 MulticastAddr::new(Ipv4Addr::new([224, 0, 10, 30])).unwrap().into();
1567
1568 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1569 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1570 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1571
1572 assert_eq!(
1573 bindings_ctx.state.link_multicast_group_memberships,
1574 HashSet::from_iter([(FakeDeviceId, address1), (FakeDeviceId, address2)])
1575 );
1576
1577 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1578
1579 assert_eq!(
1580 bindings_ctx.state.link_multicast_group_memberships,
1581 HashSet::from_iter([(FakeDeviceId, address2)])
1582 );
1583
1584 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1586
1587 assert_eq!(
1588 bindings_ctx.state.link_multicast_group_memberships,
1589 HashSet::from_iter([(FakeDeviceId, address2)])
1590 );
1591
1592 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1593
1594 assert_eq!(bindings_ctx.state.link_multicast_group_memberships, HashSet::new());
1595 }
1596}