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, PacketType, 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 let packet_type = PacketType::from(frame_dst);
564 core_ctx.handle_frame(
565 bindings_ctx,
566 &device_id,
567 ReceivedFrame::from_ethernet(ethernet, frame_dst, packet_type, gso_info).into(),
568 whole_frame,
569 );
570
571 match ethertype {
572 Some(EtherType::Arp) => {
573 let types = if let Ok(types) = peek_arp_types(buffer.as_ref()) {
574 types
575 } else {
576 return;
577 };
578 match types {
579 (ArpHardwareType::Ethernet, ArpNetworkType::Ipv4) => {
580 ArpPacketHandler::handle_packet(
581 core_ctx,
582 bindings_ctx,
583 device_id,
584 src,
585 frame_dst,
586 buffer,
587 )
588 }
589 }
590 }
591 Some(EtherType::Ipv4) => {
592 let local_frame_dst = match frame_dst.check_local() {
593 Some(dst) => dst,
594 None => {
595 core_ctx.increment_both(&device_id, |counters: &IpCounters<Ipv4>| {
596 &counters.drop_ip_packet_other_host
597 });
598 return;
599 }
600 };
601 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
602 &counters.recv_ipv4_delivered
603 });
604 core_ctx.receive_frame(
605 bindings_ctx,
606 RecvIpFrameMeta::<_, _, Ipv4>::new(
607 device_id,
608 Some(local_frame_dst),
609 DeviceIpLayerMetadata::new_for_rx_packet(packet_type),
610 parsing_context,
611 gso_info,
612 ),
613 buffer,
614 )
615 }
616 Some(EtherType::Ipv6) => {
617 let local_frame_dst = match frame_dst.check_local() {
618 Some(dst) => dst,
619 None => {
620 core_ctx.increment_both(&device_id, |counters: &IpCounters<Ipv6>| {
621 &counters.drop_ip_packet_other_host
622 });
623 return;
624 }
625 };
626 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
627 &counters.recv_ipv6_delivered
628 });
629 core_ctx.receive_frame(
630 bindings_ctx,
631 RecvIpFrameMeta::<_, _, Ipv6>::new(
632 device_id,
633 Some(local_frame_dst),
634 DeviceIpLayerMetadata::new_for_rx_packet(packet_type),
635 parsing_context,
636 gso_info,
637 ),
638 buffer,
639 )
640 }
641 Some(EtherType::Other(_)) => {
642 core_ctx.increment_both(&device_id, |counters: &EthernetDeviceCounters| {
643 &counters.recv_unsupported_ethertype
644 });
645 }
646 None => {
647 core_ctx.increment_both(&device_id, |counters: &EthernetDeviceCounters| {
648 &counters.recv_no_ethertype
649 });
650 }
651 }
652 }
653}
654
655pub fn join_link_multicast<
671 BC: EthernetIpLinkDeviceBindingsContext + EthernetDeviceEventBindingsContext<CC::DeviceId>,
672 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
673>(
674 core_ctx: &mut CC,
675 bindings_ctx: &mut BC,
676 device_id: &CC::DeviceId,
677 multicast_addr: MulticastAddr<Mac>,
678) {
679 core_ctx.with_ethernet_state_mut(device_id, |_static_state, dynamic_state| {
680 let groups = &mut dynamic_state.link_multicast_groups;
681
682 match groups.insert(multicast_addr) {
683 InsertResult::Inserted(()) => {
684 trace!(
685 "ethernet::join_link_multicast: joining link multicast {:?}",
686 multicast_addr
687 );
688 bindings_ctx.on_event(EthernetDeviceEvent::MulticastJoin {
689 device: device_id.clone(),
690 addr: multicast_addr,
691 });
692 }
693 InsertResult::AlreadyPresent => {
694 trace!(
695 "ethernet::join_link_multicast: already joined link multicast {:?}",
696 multicast_addr,
697 );
698 }
699 }
700 })
701}
702
703pub fn leave_link_multicast<
722 BC: EthernetIpLinkDeviceBindingsContext + EthernetDeviceEventBindingsContext<CC::DeviceId>,
723 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
724>(
725 core_ctx: &mut CC,
726 bindings_ctx: &mut BC,
727 device_id: &CC::DeviceId,
728 multicast_addr: MulticastAddr<Mac>,
729) {
730 core_ctx.with_ethernet_state_mut(device_id, |_static_state, dynamic_state| {
731 let groups = &mut dynamic_state.link_multicast_groups;
732
733 match groups.remove(multicast_addr) {
734 RemoveResult::Removed(()) => {
735 trace!(
736 "ethernet::leave_link_multicast: \
737 leaving link multicast {:?}",
738 multicast_addr
739 );
740 bindings_ctx.on_event(EthernetDeviceEvent::MulticastLeave {
741 device: device_id.clone(),
742 addr: multicast_addr,
743 });
744 }
745 RemoveResult::StillPresent => {
746 trace!(
747 "ethernet::leave_link_multicast: not leaving link multicast \
748 {:?} as there are still listeners for it",
749 multicast_addr,
750 );
751 }
752 RemoveResult::NotPresent => {
753 panic!(
754 "ethernet::leave_link_multicast: device {:?} has not yet \
755 joined link multicast {:?}",
756 device_id, multicast_addr,
757 );
758 }
759 }
760 })
761}
762
763pub fn get_max_frame_size<
764 BC: EthernetIpLinkDeviceBindingsContext,
765 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
766>(
767 core_ctx: &mut CC,
768 device_id: &CC::DeviceId,
769) -> MaxEthernetFrameSize {
770 core_ctx
771 .with_ethernet_state(device_id, |_static_state, dynamic_state| dynamic_state.max_frame_size)
772}
773
774pub fn get_mtu<
776 BC: EthernetIpLinkDeviceBindingsContext,
777 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
778>(
779 core_ctx: &mut CC,
780 device_id: &CC::DeviceId,
781) -> Mtu {
782 get_max_frame_size(core_ctx, device_id).as_mtu()
783}
784
785pub trait UseArpFrameMetadataBlanket {}
791
792impl<
793 BC: EthernetIpLinkDeviceBindingsContext,
794 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
795 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
796 + ResourceCounterContext<CC::DeviceId, DeviceCounters>
797 + UseArpFrameMetadataBlanket,
798> SendableFrameMeta<CC, BC> for ArpFrameMetadata<EthernetLinkDevice, CC::DeviceId>
799{
800 fn send_meta<S>(
801 self,
802 core_ctx: &mut CC,
803 bindings_ctx: &mut BC,
804 body: S,
805 ) -> Result<(), SendFrameError<S>>
806 where
807 S: NetworkSerializer,
808 S::Buffer: BufferMut,
809 {
810 let Self { device_id, dst_addr } = self;
811 let meta: BC::TxMetadata = Default::default();
812 send_as_ethernet_frame_to_dst(
813 core_ctx,
814 bindings_ctx,
815 &device_id,
816 dst_addr.get(),
817 body,
818 EtherType::Arp,
819 meta,
820 )
821 }
822}
823
824impl DeviceSocketSendTypes for EthernetLinkDevice {
825 type Metadata = Option<EthernetHeaderParams>;
828}
829
830impl<BC, CC> SendableFrameMeta<CC, BC> for DeviceSocketMetadata<EthernetLinkDevice, CC, BC>
831where
832 BC: EthernetIpLinkDeviceBindingsContext,
833 CC: DeviceIdContext<EthernetLinkDevice, DeviceId = EthernetDeviceId<BC>>
834 + EthernetIpLinkDeviceDynamicStateContext<BC>
835 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
836 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
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, ip_layer_metadata } = self;
849 let tx_meta = ip_layer_metadata.into_tx_metadata();
850 match metadata {
851 Some(EthernetHeaderParams { dest_addr, protocol }) => send_as_ethernet_frame_to_dst(
852 core_ctx,
853 bindings_ctx,
854 &device_id,
855 dest_addr,
856 body,
857 protocol,
858 tx_meta,
859 ),
860 None => send_ethernet_frame(core_ctx, bindings_ctx, &device_id, body, tx_meta),
861 }
862 }
863}
864
865pub fn get_mac<
867 'a,
868 BC: EthernetIpLinkDeviceBindingsContext,
869 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
870>(
871 core_ctx: &'a mut CC,
872 device_id: &CC::DeviceId,
873) -> UnicastAddr<Mac> {
874 core_ctx.with_static_ethernet_device_state(device_id, |state| state.mac)
875}
876
877pub fn set_mtu<
879 BC: EthernetIpLinkDeviceBindingsContext,
880 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
881>(
882 core_ctx: &mut CC,
883 device_id: &CC::DeviceId,
884 mtu: Mtu,
885) {
886 core_ctx.with_ethernet_state_mut(device_id, |static_state, dynamic_state| {
887 if let Some(mut frame_size ) = MaxEthernetFrameSize::from_mtu(mtu) {
888 if frame_size > static_state.max_frame_size {
891 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());
892 frame_size = static_state.max_frame_size;
893 }
894 trace!("ethernet::ndp_device::set_mtu: setting link MTU to {:?}", mtu);
895 dynamic_state.max_frame_size = frame_size;
896 }
897 })
898}
899
900#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
902pub enum EthernetLinkDevice {}
903
904impl Device for EthernetLinkDevice {}
905
906impl LinkDevice for EthernetLinkDevice {
907 type Address = Mac;
908}
909
910impl<BT: DeviceBufferBindingsTypes> DeviceBufferSpec<BT> for EthernetLinkDevice {
911 type TxBuffer = BT::TxBuffer;
912 type TxAllocator = BT::TxAllocator;
913}
914
915impl DeviceStateSpec for EthernetLinkDevice {
916 type State<BT: DeviceLayerTypes> = EthernetDeviceState<BT>;
917 type External<BT: DeviceLayerTypes> = BT::EthernetDeviceState;
918 type CreationProperties = EthernetCreationProperties;
919 type Counters = EthernetDeviceCounters;
920 type TimerId<D: WeakDeviceIdentifier> = EthernetTimerId<D>;
921
922 fn new_device_state<
923 CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
924 BC: DeviceLayerTypes + TimerContext,
925 >(
926 bindings_ctx: &mut BC,
927 self_id: CC::WeakDeviceId,
928 EthernetCreationProperties { mac, max_frame_size, tx_offload_spec }: Self::CreationProperties,
929 tx_allocator: <Self as DeviceBufferSpec<BC>>::TxAllocator,
930 ) -> Self::State<BC>
931 where
932 Self: DeviceBufferSpec<BC>,
933 {
934 let ipv4_arp = Mutex::new(ArpState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
935 bindings_ctx,
936 self_id.clone(),
937 ));
938 let ipv6_nud =
939 Mutex::new(NudState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx, self_id));
940 EthernetDeviceState {
941 counters: Default::default(),
942 ipv4_arp,
943 ipv6_nud,
944 ipv4_nud_config: Default::default(),
945 ipv6_nud_config: Default::default(),
946 static_state: StaticEthernetDeviceState { mac, max_frame_size },
947 dynamic_state: RwLock::new(DynamicEthernetDeviceState::new(max_frame_size)),
948 tx_queue: TransmitQueue::new(tx_allocator, tx_offload_spec),
949 }
950 }
951 const IS_LOOPBACK: bool = false;
952 const DEBUG_TYPE: &'static str = "Ethernet";
953
954 fn tx_offload_spec<BT: DeviceLayerTypes>(
955 state: &Self::State<BT>,
956 ) -> Option<ChecksumOffloadSpec> {
957 Some(state.tx_queue.tx_offload_spec())
958 }
959}
960
961#[cfg(any(test, feature = "testutils"))]
962pub(crate) mod testutil {
963 use super::*;
964
965 pub const IPV6_MIN_IMPLIED_MAX_FRAME_SIZE: MaxEthernetFrameSize =
967 MaxEthernetFrameSize::from_mtu(Ipv6::MINIMUM_LINK_MTU).unwrap();
968}
969
970#[cfg(test)]
971mod tests {
972 use alloc::vec;
973 use alloc::vec::Vec;
974 use netstack3_hashmap::HashSet;
975
976 use net_types::SpecifiedAddr;
977 use net_types::ip::{Ipv4Addr, Ipv6Addr};
978 use netstack3_base::testutil::{
979 FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId, TEST_ADDRS_V4,
980 };
981 use netstack3_base::{CounterContext, CtxPair, IntoCoreTimerCtx};
982 use netstack3_ip::nud::{
983 self, DelegateNudContext, DynamicNeighborUpdateSource, NeighborApi, UseDelegateNudContext,
984 };
985 use packet::Buf;
986 use packet_formats::testutil::parse_ethernet_frame;
987
988 use super::*;
989 use crate::internal::arp::{
990 ArpConfigContext, ArpContext, ArpCounters, ArpNudCtx, ArpSenderContext,
991 };
992 use crate::internal::base::{DeviceBufferBindingsTypes, DeviceSendFrameError};
993 use crate::internal::ethernet::testutil::IPV6_MIN_IMPLIED_MAX_FRAME_SIZE;
994 use crate::internal::queue::tx::{
995 BufVecU8Allocator, TransmitQueueBindingsContext, TransmitQueueCommon, TransmitQueueContext,
996 };
997 use crate::internal::socket::{Frame, ParseSentFrameError, SentFrame};
998
999 struct FakeEthernetCtx {
1000 static_state: StaticEthernetDeviceState,
1001 dynamic_state: DynamicEthernetDeviceState,
1002 tx_queue: TransmitQueueState<FakeTxMetadata, Buf<Vec<u8>>, BufVecU8Allocator>,
1003 counters: DeviceCounters,
1004 per_device_counters: DeviceCounters,
1005 ethernet_counters: EthernetDeviceCounters,
1006 arp_counters: ArpCounters,
1007 }
1008
1009 impl FakeEthernetCtx {
1010 fn new(mac: UnicastAddr<Mac>, max_frame_size: MaxEthernetFrameSize) -> FakeEthernetCtx {
1011 FakeEthernetCtx {
1012 static_state: StaticEthernetDeviceState { max_frame_size, mac },
1013 dynamic_state: DynamicEthernetDeviceState::new(max_frame_size),
1014 tx_queue: Default::default(),
1015 counters: Default::default(),
1016 per_device_counters: Default::default(),
1017 ethernet_counters: Default::default(),
1018 arp_counters: Default::default(),
1019 }
1020 }
1021 }
1022
1023 type FakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<
1024 EthernetTimerId<FakeWeakDeviceId<FakeDeviceId>>,
1025 nud::Event<Mac, FakeDeviceId, Ipv4, FakeInstant>,
1026 FakeBindingsState,
1027 (),
1028 >;
1029
1030 #[derive(Default)]
1031 struct FakeBindingsState {
1032 link_multicast_group_memberships: HashSet<(FakeDeviceId, MulticastAddr<Mac>)>,
1033 }
1034
1035 type FakeInnerCtx =
1036 netstack3_base::testutil::FakeCoreCtx<FakeEthernetCtx, FakeDeviceId, FakeDeviceId>;
1037
1038 struct FakeCoreCtx {
1039 arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1040 inner: FakeInnerCtx,
1041 }
1042
1043 fn new_context() -> CtxPair<FakeCoreCtx, FakeBindingsCtx> {
1044 CtxPair::with_default_bindings_ctx(|bindings_ctx| FakeCoreCtx {
1045 arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
1046 bindings_ctx,
1047 FakeWeakDeviceId(FakeDeviceId),
1048 ),
1049 inner: FakeInnerCtx::with_state(FakeEthernetCtx::new(
1050 TEST_ADDRS_V4.local_mac,
1051 IPV6_MIN_IMPLIED_MAX_FRAME_SIZE,
1052 )),
1053 })
1054 }
1055
1056 impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1057 fn handle_frame(
1058 &mut self,
1059 bindings_ctx: &mut FakeBindingsCtx,
1060 device: &Self::DeviceId,
1061 frame: Frame<&[u8]>,
1062 whole_frame: &[u8],
1063 ) {
1064 self.inner.handle_frame(bindings_ctx, device, frame, whole_frame)
1065 }
1066 }
1067
1068 impl CounterContext<DeviceCounters> for FakeCoreCtx {
1069 fn counters(&self) -> &DeviceCounters {
1070 &self.inner.state.counters
1071 }
1072 }
1073
1074 impl CounterContext<DeviceCounters> for FakeInnerCtx {
1075 fn counters(&self) -> &DeviceCounters {
1076 &self.state.counters
1077 }
1078 }
1079
1080 impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeCoreCtx {
1081 fn per_resource_counters<'a>(
1082 &'a self,
1083 &FakeDeviceId: &'a FakeDeviceId,
1084 ) -> &'a DeviceCounters {
1085 &self.inner.state.per_device_counters
1086 }
1087 }
1088
1089 impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeInnerCtx {
1090 fn per_resource_counters<'a>(
1091 &'a self,
1092 &FakeDeviceId: &'a FakeDeviceId,
1093 ) -> &'a DeviceCounters {
1094 &self.state.per_device_counters
1095 }
1096 }
1097
1098 impl CounterContext<EthernetDeviceCounters> for FakeCoreCtx {
1099 fn counters(&self) -> &EthernetDeviceCounters {
1100 &self.inner.state.ethernet_counters
1101 }
1102 }
1103
1104 impl CounterContext<EthernetDeviceCounters> for FakeInnerCtx {
1105 fn counters(&self) -> &EthernetDeviceCounters {
1106 &self.state.ethernet_counters
1107 }
1108 }
1109
1110 impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1111 fn handle_frame(
1112 &mut self,
1113 _bindings_ctx: &mut FakeBindingsCtx,
1114 _device: &Self::DeviceId,
1115 _frame: Frame<&[u8]>,
1116 _whole_frame: &[u8],
1117 ) {
1118 }
1120 }
1121
1122 impl EthernetIpLinkDeviceStaticStateContext for FakeCoreCtx {
1123 fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1124 &mut self,
1125 device_id: &FakeDeviceId,
1126 cb: F,
1127 ) -> O {
1128 self.inner.with_static_ethernet_device_state(device_id, cb)
1129 }
1130 }
1131
1132 impl EthernetIpLinkDeviceStaticStateContext for FakeInnerCtx {
1133 fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1134 &mut self,
1135 &FakeDeviceId: &FakeDeviceId,
1136 cb: F,
1137 ) -> O {
1138 cb(&self.state.static_state)
1139 }
1140 }
1141
1142 impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeCoreCtx {
1143 fn with_ethernet_state<
1144 O,
1145 F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1146 >(
1147 &mut self,
1148 device_id: &FakeDeviceId,
1149 cb: F,
1150 ) -> O {
1151 self.inner.with_ethernet_state(device_id, cb)
1152 }
1153
1154 fn with_ethernet_state_mut<
1155 O,
1156 F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1157 >(
1158 &mut self,
1159 device_id: &FakeDeviceId,
1160 cb: F,
1161 ) -> O {
1162 self.inner.with_ethernet_state_mut(device_id, cb)
1163 }
1164 }
1165
1166 impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeInnerCtx {
1167 fn with_ethernet_state<
1168 O,
1169 F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1170 >(
1171 &mut self,
1172 &FakeDeviceId: &FakeDeviceId,
1173 cb: F,
1174 ) -> O {
1175 let FakeEthernetCtx { static_state, dynamic_state, .. } = &self.state;
1176 cb(static_state, dynamic_state)
1177 }
1178
1179 fn with_ethernet_state_mut<
1180 O,
1181 F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1182 >(
1183 &mut self,
1184 &FakeDeviceId: &FakeDeviceId,
1185 cb: F,
1186 ) -> O {
1187 let FakeEthernetCtx { static_state, dynamic_state, .. } = &mut self.state;
1188 cb(static_state, dynamic_state)
1189 }
1190 }
1191
1192 impl NudHandler<Ipv6, EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1193 fn handle_neighbor_update(
1194 &mut self,
1195 _bindings_ctx: &mut FakeBindingsCtx,
1196 _device_id: &Self::DeviceId,
1197 _neighbor: SpecifiedAddr<Ipv6Addr>,
1198 _source: DynamicNeighborUpdateSource<Mac>,
1199 ) {
1200 unimplemented!()
1201 }
1202
1203 fn flush(&mut self, _bindings_ctx: &mut FakeBindingsCtx, _device_id: &Self::DeviceId) {
1204 unimplemented!()
1205 }
1206
1207 fn send_ip_packet_to_neighbor<S>(
1208 &mut self,
1209 _bindings_ctx: &mut FakeBindingsCtx,
1210 _device_id: &Self::DeviceId,
1211 _neighbor: SpecifiedAddr<Ipv6Addr>,
1212 _body: S,
1213 _tx_meta: FakeTxMetadata,
1214 ) -> Result<(), SendFrameError<S>> {
1215 unimplemented!()
1216 }
1217 }
1218
1219 struct FakeCoreCtxWithDeviceId<'a> {
1220 core_ctx: &'a mut FakeInnerCtx,
1221 device_id: &'a FakeDeviceId,
1222 }
1223
1224 impl<'a> DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxWithDeviceId<'a> {
1225 type DeviceId = FakeDeviceId;
1226 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1227 }
1228
1229 impl<'a> ArpConfigContext for FakeCoreCtxWithDeviceId<'a> {
1230 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1231 cb(&NudUserConfig::default())
1232 }
1233 }
1234
1235 impl UseArpFrameMetadataBlanket for FakeCoreCtx {}
1236
1237 impl ArpContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1238 type ConfigCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1239
1240 type ArpSenderCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1241
1242 fn with_arp_state_mut_and_sender_ctx<
1243 O,
1244 F: FnOnce(
1245 &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1246 &mut Self::ArpSenderCtx<'_>,
1247 ) -> O,
1248 >(
1249 &mut self,
1250 device_id: &Self::DeviceId,
1251 cb: F,
1252 ) -> O {
1253 let Self { arp_state, inner } = self;
1254 cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1255 }
1256
1257 fn get_protocol_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Ipv4Addr> {
1258 unimplemented!()
1259 }
1260
1261 fn get_hardware_addr(
1262 &mut self,
1263 _bindings_ctx: &mut FakeBindingsCtx,
1264 _device_id: &Self::DeviceId,
1265 ) -> UnicastAddr<Mac> {
1266 self.inner.state.static_state.mac
1267 }
1268
1269 fn with_arp_state_mut<
1270 O,
1271 F: FnOnce(
1272 &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1273 &mut Self::ConfigCtx<'_>,
1274 ) -> O,
1275 >(
1276 &mut self,
1277 device_id: &Self::DeviceId,
1278 cb: F,
1279 ) -> O {
1280 let Self { arp_state, inner } = self;
1281 cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1282 }
1283
1284 fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtx>) -> O>(
1285 &mut self,
1286 FakeDeviceId: &Self::DeviceId,
1287 cb: F,
1288 ) -> O {
1289 cb(&mut self.arp_state)
1290 }
1291 }
1292
1293 impl UseDelegateNudContext for FakeCoreCtx {}
1294 impl DelegateNudContext<Ipv4> for FakeCoreCtx {
1295 type Delegate<T> = ArpNudCtx<T>;
1296 }
1297
1298 impl ArpConfigContext for FakeInnerCtx {
1299 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1300 cb(&NudUserConfig::default())
1301 }
1302 }
1303
1304 impl<'a> ArpSenderContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtxWithDeviceId<'a> {
1305 fn send_ip_packet_to_neighbor_link_addr<S>(
1306 &mut self,
1307 bindings_ctx: &mut FakeBindingsCtx,
1308 link_addr: UnicastAddr<Mac>,
1309 body: S,
1310 tx_meta: FakeTxMetadata,
1311 ) -> Result<(), SendFrameError<S>>
1312 where
1313 S: NetworkSerializer,
1314 S::Buffer: BufferMut,
1315 {
1316 let Self { core_ctx, device_id } = self;
1317 send_as_ethernet_frame_to_dst(
1318 *core_ctx,
1319 bindings_ctx,
1320 device_id,
1321 link_addr.get(),
1322 body,
1323 EtherType::Ipv4,
1324 tx_meta,
1325 )
1326 }
1327 }
1328
1329 impl TransmitQueueBindingsContext<FakeDeviceId> for FakeBindingsCtx {
1330 fn wake_tx_task(&mut self, FakeDeviceId: &FakeDeviceId) {
1331 unimplemented!("unused by tests")
1332 }
1333 }
1334
1335 impl EventContext<EthernetDeviceEvent<FakeDeviceId>> for FakeBindingsCtx {
1336 fn on_event(&mut self, event: EthernetDeviceEvent<FakeDeviceId>) {
1337 match event {
1339 EthernetDeviceEvent::MulticastJoin { device, addr } => {
1340 assert!(
1341 self.state.link_multicast_group_memberships.insert((device, addr)),
1342 "membership should not be present"
1343 );
1344 }
1345 EthernetDeviceEvent::MulticastLeave { device, addr } => {
1346 assert!(
1347 self.state.link_multicast_group_memberships.remove(&(device, addr)),
1348 "membership should be present"
1349 );
1350 }
1351 }
1352 }
1353 }
1354
1355 impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1356 type Meta = FakeTxMetadata;
1357
1358 type DequeueContext = !;
1359
1360 fn parse_outgoing_frame<'a>(
1361 buf: &'a [u8],
1362 meta: &'a Self::Meta,
1363 ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1364 FakeInnerCtx::parse_outgoing_frame(buf, meta)
1365 }
1366 }
1367
1368 impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1369 type Meta = FakeTxMetadata;
1370
1371 type DequeueContext = !;
1372
1373 fn parse_outgoing_frame<'a, 'b>(
1374 buf: &'a [u8],
1375 _tx_meta: &'b Self::Meta,
1376 ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1377 SentFrame::try_parse_as_ethernet(buf)
1378 }
1379 }
1380
1381 impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1382 fn with_transmit_queue_mut<
1383 O,
1384 F: FnOnce(
1385 &mut TransmitQueueState<Self::Meta, packet::Buf<Vec<u8>>, BufVecU8Allocator>,
1386 ) -> O,
1387 >(
1388 &mut self,
1389 device_id: &Self::DeviceId,
1390 cb: F,
1391 ) -> O {
1392 self.inner.with_transmit_queue_mut(device_id, cb)
1393 }
1394
1395 fn with_transmit_queue<
1396 O,
1397 F: FnOnce(&TransmitQueueState<Self::Meta, packet::Buf<Vec<u8>>, BufVecU8Allocator>) -> O,
1398 >(
1399 &mut self,
1400 device_id: &Self::DeviceId,
1401 cb: F,
1402 ) -> O {
1403 self.inner.with_transmit_queue(device_id, cb)
1404 }
1405
1406 fn send_frame(
1407 &mut self,
1408 bindings_ctx: &mut FakeBindingsCtx,
1409 device_id: &Self::DeviceId,
1410 dequeue_context: Option<&mut !>,
1411 tx_meta: Self::Meta,
1412 buf: packet::Buf<Vec<u8>>,
1413 ) -> Result<(), DeviceSendFrameError> {
1414 TransmitQueueContext::send_frame(
1415 &mut self.inner,
1416 bindings_ctx,
1417 device_id,
1418 dequeue_context,
1419 tx_meta,
1420 buf,
1421 )
1422 }
1423 }
1424
1425 impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx
1426 where
1427 Self: TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx, Meta = FakeTxMetadata>,
1428 {
1429 fn with_transmit_queue_mut<
1430 O,
1431 F: FnOnce(
1432 &mut TransmitQueueState<
1433 Self::Meta,
1434 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxBuffer,
1435 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxAllocator,
1436 >,
1437 ) -> O,
1438 >(
1439 &mut self,
1440 _device_id: &Self::DeviceId,
1441 cb: F,
1442 ) -> O {
1443 cb(&mut self.state.tx_queue)
1444 }
1445
1446 fn with_transmit_queue<
1447 O,
1448 F: FnOnce(
1449 &TransmitQueueState<
1450 Self::Meta,
1451 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxBuffer,
1452 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxAllocator,
1453 >,
1454 ) -> O,
1455 >(
1456 &mut self,
1457 _device_id: &Self::DeviceId,
1458 cb: F,
1459 ) -> O {
1460 cb(&self.state.tx_queue)
1461 }
1462
1463 fn send_frame(
1464 &mut self,
1465 _bindings_ctx: &mut FakeBindingsCtx,
1466 device_id: &Self::DeviceId,
1467 dequeue_context: Option<&mut !>,
1468 _tx_meta: Self::Meta,
1469 buf: packet::Buf<Vec<u8>>,
1470 ) -> Result<(), DeviceSendFrameError> {
1471 match dequeue_context {
1472 Some(never) => match *never {},
1473 None => (),
1474 }
1475 self.frames.push(device_id.clone(), buf.as_ref().to_vec());
1476 Ok(())
1477 }
1478 }
1479
1480 impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtx {
1481 type DeviceId = FakeDeviceId;
1482 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1483 }
1484
1485 impl DeviceIdContext<EthernetLinkDevice> for FakeInnerCtx {
1486 type DeviceId = FakeDeviceId;
1487 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1488 }
1489
1490 impl CounterContext<ArpCounters> for FakeCoreCtx {
1491 fn counters(&self) -> &ArpCounters {
1492 &self.inner.state.arp_counters
1493 }
1494 }
1495
1496 #[test]
1497 fn test_mtu() {
1498 fn test(size: usize, expect_frames_sent: bool) {
1502 let mut ctx = new_context();
1503 NeighborApi::<Ipv4, EthernetLinkDevice, _>::new(ctx.as_mut())
1504 .insert_static_entry(
1505 &FakeDeviceId,
1506 TEST_ADDRS_V4.remote_ip.get(),
1507 TEST_ADDRS_V4.remote_mac,
1508 )
1509 .unwrap();
1510 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1511 let result = send_ip_frame::<FakeBindingsCtx, FakeCoreCtx, Ipv4, _>(
1512 core_ctx,
1513 bindings_ctx,
1514 &FakeDeviceId,
1515 IpPacketDestination::<Ipv4, _>::Neighbor(TEST_ADDRS_V4.remote_ip),
1516 Buf::new(&mut vec![0; size], ..),
1517 FakeTxMetadata::default(),
1518 )
1519 .map_err(|_serializer| ());
1520 let sent_frames = core_ctx.inner.frames().len();
1521 if expect_frames_sent {
1522 assert_eq!(sent_frames, 1);
1523 result.expect("should succeed");
1524 } else {
1525 assert_eq!(sent_frames, 0);
1526 result.expect_err("should fail");
1527 }
1528 }
1529
1530 test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap(), true);
1531 test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap() + 1, false);
1532 }
1533
1534 #[test]
1535 fn broadcast() {
1536 let mut ctx = new_context();
1537 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1538 send_ip_frame::<FakeBindingsCtx, FakeCoreCtx, Ipv4, _>(
1539 core_ctx,
1540 bindings_ctx,
1541 &FakeDeviceId,
1542 IpPacketDestination::<Ipv4, _>::Broadcast(()),
1543 Buf::new(&mut vec![0; 100], ..),
1544 FakeTxMetadata::default(),
1545 )
1546 .map_err(|_serializer| ())
1547 .expect("send_ip_frame should succeed");
1548 let sent_frames = core_ctx.inner.frames().len();
1549 assert_eq!(sent_frames, 1);
1550 let (FakeDeviceId, frame) = core_ctx.inner.frames()[0].clone();
1551 let (_body, _src_mac, dst_mac, _ether_type) =
1552 parse_ethernet_frame(&frame, EthernetFrameLengthCheck::NoCheck).unwrap();
1553 assert_eq!(dst_mac, Mac::BROADCAST);
1554 }
1555
1556 #[test]
1557 fn test_join_link_multicast() {
1558 let mut ctx = new_context();
1559 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1560
1561 let address1: MulticastAddr<Mac> =
1562 MulticastAddr::new(Ipv4Addr::new([224, 0, 0, 200])).unwrap().into();
1563 let address2: MulticastAddr<Mac> =
1564 MulticastAddr::new(Ipv4Addr::new([224, 0, 10, 30])).unwrap().into();
1565
1566 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1567 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1568 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1569
1570 assert_eq!(
1571 bindings_ctx.state.link_multicast_group_memberships,
1572 HashSet::from_iter([(FakeDeviceId, address1), (FakeDeviceId, address2)])
1573 );
1574
1575 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1576
1577 assert_eq!(
1578 bindings_ctx.state.link_multicast_group_memberships,
1579 HashSet::from_iter([(FakeDeviceId, address2)])
1580 );
1581
1582 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1584
1585 assert_eq!(
1586 bindings_ctx.state.link_multicast_group_memberships,
1587 HashSet::from_iter([(FakeDeviceId, address2)])
1588 );
1589
1590 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1591
1592 assert_eq!(bindings_ctx.state.link_multicast_group_memberships, HashSet::new());
1593 }
1594}