1#![cfg(any(test, feature = "testutils"))]
8
9pub use netstack3_base::testutil::{FakeDeviceId, TestIpExt};
10pub use netstack3_filter::testutil::new_filter_egress_ip_packet;
11
12use alloc::borrow::ToOwned;
13use alloc::sync::Arc;
14use alloc::vec;
15use alloc::vec::Vec;
16
17use core::borrow::Borrow;
18use core::convert::Infallible as Never;
19use core::fmt::Debug;
20use core::hash::Hash;
21use core::ops::{Deref, DerefMut};
22use core::time::Duration;
23
24use derivative::Derivative;
25use net_types::ethernet::Mac;
26use net_types::ip::{
27 AddrSubnet, AddrSubnetEither, GenericOverIp, Ip, IpAddr, IpAddress, IpInvariant, IpVersion,
28 Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Mtu, Subnet, SubnetEither,
29};
30use net_types::{MulticastAddr, SpecifiedAddr, UnicastAddr, Witness as _};
31use netstack3_base::sync::{DynDebugReferences, Mutex};
32use netstack3_base::testutil::{
33 AlwaysDefaultsSettingsContext, FakeAtomicInstant, FakeCryptoRng, FakeFrameCtx, FakeInstant,
34 FakeNetwork, FakeNetworkLinks, FakeNetworkSpec, FakeSocketWritableListener, FakeTimerCtx,
35 FakeTimerCtxExt, FakeTimerId, MonotonicIdentifier, TestAddrs, WithFakeFrameContext,
36 WithFakeTimerContext,
37};
38use netstack3_base::{
39 AddressResolutionFailed, CtxPair, DeferredResourceRemovalContext, EventContext,
40 FrameDestination, InstantBindingsTypes, InstantContext, IpDeviceAddr, LinkDevice, Marks,
41 MatcherBindingsTypes, NotFoundError, ReferenceNotifiers, RemoveResourceResult, RngContext,
42 TimerBindingsTypes, TimerContext, TimerHandler, TxMetadataBindingsTypes, WorkQueueReport,
43};
44use netstack3_device::ethernet::{
45 EthernetCreationProperties, EthernetDeviceEvent, EthernetDeviceId, EthernetLinkDevice,
46 EthernetWeakDeviceId, RecvEthernetFrameMeta,
47};
48use netstack3_device::loopback::{LoopbackCreationProperties, LoopbackDevice, LoopbackDeviceId};
49use netstack3_device::pure_ip::{PureIpDeviceId, PureIpWeakDeviceId};
50use netstack3_device::queue::{ReceiveQueueBindingsContext, TransmitQueueBindingsContext};
51use netstack3_device::socket::{
52 DeviceSocketBindingsContext, DeviceSocketTypes, ReceiveFrameError, SocketId,
53};
54use netstack3_device::testutil::IPV6_MIN_IMPLIED_MAX_FRAME_SIZE;
55use netstack3_device::{
56 self as device, DeviceId, DeviceLayerEventDispatcher, DeviceLayerStateTypes, DeviceLayerTypes,
57 DeviceProvider, DeviceSendFrameError, WeakDeviceId, for_any_device_id,
58};
59use netstack3_filter::testutil::NoOpSocketOpsFilter;
60use netstack3_filter::{FilterTimerId, SocketOpsFilter, SocketOpsFilterBindingContext};
61use netstack3_hashmap::HashMap;
62use netstack3_icmp_echo::{
63 IcmpEchoBindingsContext, IcmpEchoBindingsTypes, IcmpSocketId, ReceiveIcmpEchoError,
64};
65use netstack3_ip::device::{
66 IpDeviceConfiguration, IpDeviceConfigurationUpdate, IpDeviceEvent,
67 Ipv4DeviceConfigurationUpdate, Ipv6DeviceConfigurationUpdate,
68};
69use netstack3_ip::nud::{self, LinkResolutionContext, LinkResolutionNotifier};
70use netstack3_ip::raw::{
71 RawIpSocketId, RawIpSocketsBindingsContext, RawIpSocketsBindingsTypes, ReceivePacketError,
72};
73use netstack3_ip::{
74 self as ip, AddRouteError, AddableEntryEither, AddableMetric, DeviceIpLayerMetadata,
75 IpLayerEvent, IpLayerTimerId, IpRoutingBindingsTypes, RawMetric, ResolveRouteError,
76 ResolvedRoute, RoutableIpAddr, RouterAdvertisementEvent,
77};
78use netstack3_tcp::testutil::{ClientBuffers, ProvidedBuffers, RingBuffer, TestSendBuffer};
79use netstack3_tcp::{BufferSizes, TcpBindingsTypes};
80use netstack3_udp::{
81 ReceiveUdpError, UdpBindingsTypes, UdpPacketMeta, UdpReceiveBindingsContext, UdpSocketId,
82};
83use packet::{Buf, BufferMut};
84use zerocopy::SplitByteSlice;
85
86use crate::api::CoreApi;
87use crate::context::UnlockedCoreCtx;
88use crate::context::prelude::*;
89use crate::state::{StackState, StackStateBuilder};
90use crate::time::{TimerId, TimerIdInner};
91use crate::{BindingsContext, BindingsTypes, CoreTxMetadata, IpExt};
92
93pub const DEFAULT_INTERFACE_METRIC: RawMetric = RawMetric(100);
95
96pub type Ctx<BT> = CtxPair<StackState<BT>, BT>;
98
99pub trait CtxPairExt<BC: BindingsContext> {
101 fn contexts(&mut self) -> (UnlockedCoreCtx<'_, BC>, &mut BC);
106
107 fn core_api(&mut self) -> CoreApi<'_, &mut BC> {
109 let (core_ctx, bindings_ctx) = self.contexts();
110 CoreApi::new(CtxPair { core_ctx, bindings_ctx })
111 }
112
113 fn core_ctx(&self) -> UnlockedCoreCtx<'_, BC>;
115
116 fn test_api(&mut self) -> TestApi<'_, BC> {
118 let (core_ctx, bindings_ctx) = self.contexts();
119 TestApi(core_ctx, bindings_ctx)
120 }
121
122 fn trigger_next_timer<Id>(&mut self) -> Option<Id>
124 where
125 BC: FakeTimerCtxExt<Id>,
126 for<'a> UnlockedCoreCtx<'a, BC>: TimerHandler<BC, Id>,
127 {
128 let (mut core_ctx, bindings_ctx) = self.contexts();
129 bindings_ctx.trigger_next_timer(&mut core_ctx)
130 }
131
132 fn trigger_timers_for<Id>(&mut self, duration: Duration) -> Vec<Id>
134 where
135 BC: FakeTimerCtxExt<Id>,
136 for<'a> UnlockedCoreCtx<'a, BC>: TimerHandler<BC, Id>,
137 {
138 let (mut core_ctx, bindings_ctx) = self.contexts();
139 bindings_ctx.trigger_timers_for(duration, &mut core_ctx)
140 }
141
142 fn trigger_timers_until_instant<Id>(&mut self, instant: FakeInstant) -> Vec<Id>
144 where
145 BC: FakeTimerCtxExt<Id>,
146 for<'a> UnlockedCoreCtx<'a, BC>: TimerHandler<BC, Id>,
147 {
148 let (mut core_ctx, bindings_ctx) = self.contexts();
149 bindings_ctx.trigger_timers_until_instant(instant, &mut core_ctx)
150 }
151
152 fn trigger_timers_until_and_expect_unordered<Id, I: IntoIterator<Item = Id>>(
154 &mut self,
155 instant: FakeInstant,
156 timers: I,
157 ) where
158 Id: Debug + Hash + Eq,
159 BC: FakeTimerCtxExt<Id>,
160 for<'a> UnlockedCoreCtx<'a, BC>: TimerHandler<BC, Id>,
161 {
162 let (mut core_ctx, bindings_ctx) = self.contexts();
163 bindings_ctx.trigger_timers_until_and_expect_unordered(instant, timers, &mut core_ctx)
164 }
165}
166
167impl<CC, BC> CtxPairExt<BC> for CtxPair<CC, BC>
168where
169 CC: Borrow<StackState<BC>>,
170 BC: BindingsContext,
171{
172 fn contexts(&mut self) -> (UnlockedCoreCtx<'_, BC>, &mut BC) {
173 let Self { core_ctx, bindings_ctx } = self;
174 (UnlockedCoreCtx::new(CC::borrow(core_ctx)), bindings_ctx)
175 }
176
177 fn core_ctx(&self) -> UnlockedCoreCtx<'_, BC> {
178 UnlockedCoreCtx::new(CC::borrow(&self.core_ctx))
179 }
180}
181
182pub struct TestApi<'a, BT: BindingsTypes>(UnlockedCoreCtx<'a, BT>, &'a mut BT);
184
185impl<'l, BC> TestApi<'l, BC>
186where
187 BC: BindingsContext,
188{
189 fn contexts(&mut self) -> (&mut UnlockedCoreCtx<'l, BC>, &mut BC) {
190 let Self(core_ctx, bindings_ctx) = self;
191 (core_ctx, bindings_ctx)
192 }
193
194 fn core_api(&mut self) -> CoreApi<'_, &mut BC> {
195 let (core_ctx, bindings_ctx) = self.contexts();
196 let core_ctx = core_ctx.as_owned();
197 CoreApi::new(CtxPair { core_ctx, bindings_ctx })
198 }
199
200 #[netstack3_macros::context_ip_bounds(A::Version, BC, crate)]
202 pub fn join_ip_multicast<A: IpAddress>(
203 &mut self,
204 device: &DeviceId<BC>,
205 multicast_addr: MulticastAddr<A>,
206 ) where
207 A::Version: IpExt,
208 {
209 let (core_ctx, bindings_ctx) = self.contexts();
210 ip::device::join_ip_multicast::<A::Version, _, _>(
211 core_ctx,
212 bindings_ctx,
213 device,
214 multicast_addr,
215 );
216 }
217
218 #[netstack3_macros::context_ip_bounds(A::Version, BC, crate)]
220 pub fn leave_ip_multicast<A: IpAddress>(
221 &mut self,
222 device: &DeviceId<BC>,
223 multicast_addr: MulticastAddr<A>,
224 ) where
225 A::Version: IpExt,
226 {
227 let (core_ctx, bindings_ctx) = self.contexts();
228 ip::device::leave_ip_multicast::<A::Version, _, _>(
229 core_ctx,
230 bindings_ctx,
231 device,
232 multicast_addr,
233 );
234 }
235
236 #[netstack3_macros::context_ip_bounds(A::Version, BC, crate)]
238 pub fn is_in_ip_multicast<A: IpAddress>(
239 &mut self,
240 device: &DeviceId<BC>,
241 addr: MulticastAddr<A>,
242 ) -> bool
243 where
244 A::Version: IpExt,
245 {
246 use ip::{
247 AddressStatus, IpDeviceIngressStateContext, IpLayerIpExt, Ipv4PresentAddressStatus,
248 Ipv6PresentAddressStatus,
249 };
250
251 let (core_ctx, _) = self.contexts();
252 let addr_status = IpDeviceIngressStateContext::<A::Version>::address_status_for_device(
253 core_ctx,
254 addr.into_specified(),
255 device,
256 );
257 let status = match addr_status {
258 AddressStatus::Present(p) => p,
259 AddressStatus::Unassigned => return false,
260 };
261 #[derive(GenericOverIp)]
262 #[generic_over_ip(I, Ip)]
263 struct Wrap<I: IpLayerIpExt>(I::AddressStatus);
264 A::Version::map_ip(
265 Wrap(status),
266 |Wrap(v4)| match v4 {
267 Ipv4PresentAddressStatus::Multicast => true,
268 Ipv4PresentAddressStatus::LimitedBroadcast
269 | Ipv4PresentAddressStatus::SubnetBroadcast
270 | Ipv4PresentAddressStatus::LoopbackSubnet
271 | Ipv4PresentAddressStatus::UnicastAssigned
272 | Ipv4PresentAddressStatus::UnicastTentative => false,
273 },
274 |Wrap(v6)| match v6 {
275 Ipv6PresentAddressStatus::Multicast => true,
276 Ipv6PresentAddressStatus::UnicastAssigned
277 | Ipv6PresentAddressStatus::UnicastTentative => false,
278 },
279 )
280 }
281
282 pub fn receive_ip_packet<I: Ip, B: BufferMut>(
287 &mut self,
288 device: &DeviceId<BC>,
289 frame_dst: Option<FrameDestination>,
290 buffer: B,
291 ) {
292 self.receive_ip_packet_with_marks::<I, B>(device, frame_dst, buffer, Default::default())
293 }
294
295 pub fn receive_ip_packet_with_marks<I: Ip, B: BufferMut>(
300 &mut self,
301 device: &DeviceId<BC>,
302 frame_dst: Option<FrameDestination>,
303 buffer: B,
304 marks: Marks,
305 ) {
306 let (core_ctx, bindings_ctx) = self.contexts();
307 match I::VERSION {
308 IpVersion::V4 => ip::receive_ipv4_packet(
309 core_ctx,
310 bindings_ctx,
311 device,
312 frame_dst,
313 DeviceIpLayerMetadata::with_marks(marks),
314 buffer,
315 ),
316 IpVersion::V6 => ip::receive_ipv6_packet(
317 core_ctx,
318 bindings_ctx,
319 device,
320 frame_dst,
321 DeviceIpLayerMetadata::with_marks(marks),
322 buffer,
323 ),
324 }
325 }
326
327 pub fn add_route(
329 &mut self,
330 entry: AddableEntryEither<DeviceId<BC>>,
331 ) -> Result<(), AddRouteError> {
332 let (core_ctx, _bindings_ctx) = self.contexts();
333 match entry {
334 AddableEntryEither::V4(entry) => ip::testutil::add_route::<Ipv4, _, _>(core_ctx, entry),
335 AddableEntryEither::V6(entry) => ip::testutil::add_route::<Ipv6, _, _>(core_ctx, entry),
336 }
337 }
338
339 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
341 pub fn set_rules<I: IpExt>(&mut self, rules: Vec<netstack3_ip::Rule<I, DeviceId<BC>, BC>>) {
342 let (core_ctx, _bindings_ctx) = self.contexts();
343 ip::testutil::set_rules(core_ctx, rules)
344 }
345
346 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
348 pub fn resolve_route_with_src_addr<I: IpExt>(
349 &mut self,
350 src_ip: IpDeviceAddr<I::Addr>,
351 dst_ip: Option<RoutableIpAddr<I::Addr>>,
352 ) -> Result<ResolvedRoute<I, DeviceId<BC>>, ResolveRouteError> {
353 let (core_ctx, _bindings_ctx) = self.contexts();
354 ip::resolve_output_route_to_destination(
355 core_ctx,
356 None,
357 Some((src_ip, ip::NonLocalSrcAddrPolicy::Deny)),
358 dst_ip,
359 &Default::default(),
360 )
361 }
362
363 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
365 pub fn resolve_route_with_marks<I: IpExt>(
366 &mut self,
367 dst_ip: Option<RoutableIpAddr<I::Addr>>,
368 marks: &Marks,
369 ) -> Result<ResolvedRoute<I, DeviceId<BC>>, ResolveRouteError> {
370 let (core_ctx, _bindings_ctx) = self.contexts();
371 ip::resolve_output_route_to_destination(core_ctx, None, None, dst_ip, marks)
372 }
373
374 pub fn del_routes_to_subnet(
377 &mut self,
378 subnet: net_types::ip::SubnetEither,
379 ) -> Result<(), NotFoundError> {
380 let (core_ctx, _bindings_ctx) = self.contexts();
381 match subnet {
382 SubnetEither::V4(subnet) => {
383 ip::testutil::del_routes_to_subnet::<Ipv4, _, _>(core_ctx, subnet)
384 }
385 SubnetEither::V6(subnet) => {
386 ip::testutil::del_routes_to_subnet::<Ipv6, _, _>(core_ctx, subnet)
387 }
388 }
389 }
390
391 pub fn del_device_routes(&mut self, device: &DeviceId<BC>) {
393 let (core_ctx, _bindings_ctx) = self.contexts();
394 ip::testutil::del_device_routes::<Ipv4, _, _>(core_ctx, device);
395 ip::testutil::del_device_routes::<Ipv6, _, _>(core_ctx, device);
396 }
397
398 pub fn clear_routes_and_remove_device<D: Into<DeviceId<BC>>>(&mut self, device: D) {
400 let device = device.into();
401 self.del_device_routes(&device);
402
403 for_any_device_id!(DeviceId, DeviceProvider, D, device,
404 device => match self.core_api().device::<D>().remove_device(device) {
405 RemoveResourceResult::Removed(_external_state) => {}
406 RemoveResourceResult::Deferred(_reference_receiver) => {
407 panic!("failed to remove device")
408 }
409 });
410 }
411
412 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
415 pub fn set_ip_device_enabled<I: IpExt>(
416 &mut self,
417 device: &DeviceId<BC>,
418 enabled: bool,
419 ) -> bool {
420 let update =
421 IpDeviceConfigurationUpdate { ip_enabled: Some(enabled), ..Default::default() };
422 let prev =
423 self.core_api().device_ip::<I>().update_configuration(device, update.into()).unwrap();
424 prev.as_ref().ip_enabled.unwrap()
425 }
426
427 pub fn enable_device(&mut self, device: &DeviceId<BC>) {
429 let _was_enabled: bool = self.set_ip_device_enabled::<Ipv4>(device, true);
430 let _was_enabled: bool = self.set_ip_device_enabled::<Ipv6>(device, true);
431 }
432
433 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
435 pub fn set_unicast_forwarding_enabled<I: IpExt>(
436 &mut self,
437 device: &DeviceId<BC>,
438 enabled: bool,
439 ) {
440 let _config = self
441 .core_api()
442 .device_ip::<I>()
443 .update_configuration(
444 device,
445 IpDeviceConfigurationUpdate {
446 unicast_forwarding_enabled: Some(enabled),
447 ..Default::default()
448 }
449 .into(),
450 )
451 .unwrap();
452 }
453
454 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
456 pub fn set_multicast_forwarding_enabled<I: IpExt>(
457 &mut self,
458 device: &DeviceId<BC>,
459 enabled: bool,
460 ) {
461 let _config = self
462 .core_api()
463 .device_ip::<I>()
464 .update_configuration(
465 device,
466 IpDeviceConfigurationUpdate {
467 multicast_forwarding_enabled: Some(enabled),
468 ..Default::default()
469 }
470 .into(),
471 )
472 .unwrap();
473 }
474
475 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
477 pub fn is_unicast_forwarding_enabled<I: IpExt>(&mut self, device: &DeviceId<BC>) -> bool {
478 let configuration = self.core_api().device_ip::<I>().get_configuration(device);
479 let IpDeviceConfiguration { unicast_forwarding_enabled, .. } = configuration.as_ref();
480 *unicast_forwarding_enabled
481 }
482
483 pub fn add_loopback(&mut self) -> LoopbackDeviceId<BC>
485 where
486 <BC as DeviceLayerStateTypes>::DeviceIdentifier: Default,
487 <BC as DeviceLayerStateTypes>::LoopbackDeviceState: Default,
488 {
489 let loopback_id = self.core_api().device::<LoopbackDevice>().add_device_with_default_state(
490 LoopbackCreationProperties { mtu: Mtu::new(u32::MAX) },
491 DEFAULT_INTERFACE_METRIC,
492 );
493 let device_id: DeviceId<_> = loopback_id.clone().into();
494 self.enable_device(&device_id);
495
496 self.core_api()
497 .device_ip::<Ipv4>()
498 .add_ip_addr_subnet(
499 &device_id,
500 AddrSubnet::from_witness(Ipv4::LOOPBACK_ADDRESS, Ipv4::LOOPBACK_SUBNET.prefix())
501 .unwrap(),
502 )
503 .unwrap();
504
505 self.core_api()
506 .device_ip::<Ipv6>()
507 .add_ip_addr_subnet(
508 &device_id,
509 AddrSubnet::from_witness(Ipv6::LOOPBACK_ADDRESS, Ipv6::LOOPBACK_SUBNET.prefix())
510 .unwrap(),
511 )
512 .unwrap();
513 loopback_id
514 }
515}
516
517impl<'a> TestApi<'a, FakeBindingsCtx> {
518 pub fn handle_queued_rx_packets(&mut self) -> bool {
521 let mut handled = false;
522 loop {
523 let (_, bindings_ctx) = self.contexts();
524 let rx_available = core::mem::take(&mut bindings_ctx.state_mut().rx_available);
525 if rx_available.len() == 0 {
526 break handled;
527 }
528 handled = true;
529 for id in rx_available.into_iter() {
530 loop {
531 match self.core_api().receive_queue().handle_queued_frames(&id) {
532 WorkQueueReport::AllDone => break,
533 WorkQueueReport::Pending => (),
534 }
535 }
536 }
537 }
538 }
539}
540
541#[derive(Default)]
542pub struct FakeBindingsCtxState {
544 icmpv4_replies:
545 HashMap<IcmpSocketId<Ipv4, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
546 icmpv6_replies:
547 HashMap<IcmpSocketId<Ipv6, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
548 udpv4_received:
549 HashMap<UdpSocketId<Ipv4, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
550 udpv6_received:
551 HashMap<UdpSocketId<Ipv6, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
552 pub rx_available: Vec<LoopbackDeviceId<FakeBindingsCtx>>,
554 pub tx_available: Vec<DeviceId<FakeBindingsCtx>>,
556 #[cfg(loom)]
558 pub deferred_receivers: Vec<loom_notifiers::LoomReceiver>,
559}
560
561impl FakeBindingsCtxState {
562 pub(crate) fn udp_state_mut<I: IpExt>(
563 &mut self,
564 ) -> &mut HashMap<UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>
565 {
566 #[derive(GenericOverIp)]
567 #[generic_over_ip(I, Ip)]
568 struct Wrapper<'a, I: IpExt>(
569 &'a mut HashMap<
570 UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
571 Vec<Vec<u8>>,
572 >,
573 );
574 let Wrapper(map) = I::map_ip_out::<_, Wrapper<'_, I>>(
575 self,
576 |this| Wrapper(&mut this.udpv4_received),
577 |this| Wrapper(&mut this.udpv6_received),
578 );
579 map
580 }
581}
582
583pub type FakeCtx = Ctx<FakeBindingsCtx>;
585pub type FakeCoreCtx = StackState<FakeBindingsCtx>;
587
588type InnerFakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<
589 TimerId<FakeBindingsCtx>,
590 DispatchedEvent,
591 FakeBindingsCtxState,
592 DispatchedFrame,
593>;
594
595#[derive(Default, Clone)]
597pub struct FakeBindingsCtx(Arc<Mutex<InnerFakeBindingsCtx>>);
598
599struct Wrapper<S, Callback, CallbackMut>(S, Callback, CallbackMut);
609
610impl<T: ?Sized, S: Deref, Callback: for<'a> Fn(&'a <S as Deref>::Target) -> &'a T, CallbackMut>
611 Deref for Wrapper<S, Callback, CallbackMut>
612{
613 type Target = T;
614
615 fn deref(&self) -> &T {
616 let Self(guard, f, _) = self;
617 let target = guard.deref();
618 f(target)
619 }
620}
621
622impl<
623 T: ?Sized,
624 S: DerefMut,
625 Callback: for<'a> Fn(&'a <S as Deref>::Target) -> &'a T,
626 CallbackMut: for<'a> Fn(&'a mut <S as Deref>::Target) -> &'a mut T,
627> DerefMut for Wrapper<S, Callback, CallbackMut>
628{
629 fn deref_mut(&mut self) -> &mut T {
630 let Self(guard, _, f) = self;
631 let target = guard.deref_mut();
632 f(target)
633 }
634}
635
636impl FakeBindingsCtx {
637 fn with_inner<F: FnOnce(&InnerFakeBindingsCtx) -> O, O>(&self, f: F) -> O {
638 let Self(this) = self;
639 let locked = this.lock();
640 f(&*locked)
641 }
642
643 fn with_inner_mut<F: FnOnce(&mut InnerFakeBindingsCtx) -> O, O>(&self, f: F) -> O {
644 let Self(this) = self;
645 let mut locked = this.lock();
646 f(&mut *locked)
647 }
648
649 pub fn timer_ctx(&self) -> impl Deref<Target = FakeTimerCtx<TimerId<Self>>> + '_ {
651 fn get_timers<'a>(
654 i: &'a InnerFakeBindingsCtx,
655 ) -> &'a FakeTimerCtx<TimerId<FakeBindingsCtx>> {
656 &i.timers
657 }
658 Wrapper(self.0.lock(), get_timers, ())
659 }
660
661 pub fn state_mut(&mut self) -> impl DerefMut<Target = FakeBindingsCtxState> + '_ {
663 fn get_state<'a>(i: &'a InnerFakeBindingsCtx) -> &'a FakeBindingsCtxState {
666 &i.state
667 }
668 fn get_state_mut<'a>(i: &'a mut InnerFakeBindingsCtx) -> &'a mut FakeBindingsCtxState {
669 &mut i.state
670 }
671 Wrapper(self.0.lock(), get_state, get_state_mut)
672 }
673
674 pub fn copy_ethernet_frames(
680 &mut self,
681 ) -> Vec<(EthernetWeakDeviceId<FakeBindingsCtx>, Vec<u8>)> {
682 self.with_inner_mut(|ctx| {
683 ctx.frames
684 .frames()
685 .into_iter()
686 .map(|(meta, frame)| match meta {
687 DispatchedFrame::Ethernet(eth) => (eth.clone(), frame.clone()),
688 DispatchedFrame::PureIp(ip) => panic!("unexpected IP packet {ip:?}: {frame:?}"),
689 })
690 .collect()
691 })
692 }
693
694 pub fn take_ethernet_frames(
700 &mut self,
701 ) -> Vec<(EthernetWeakDeviceId<FakeBindingsCtx>, Vec<u8>)> {
702 self.with_inner_mut(|ctx| {
703 ctx.frames
704 .take_frames()
705 .into_iter()
706 .map(|(meta, frame)| match meta {
707 DispatchedFrame::Ethernet(eth) => (eth, frame),
708 DispatchedFrame::PureIp(ip) => panic!("unexpected IP packet {ip:?}: {frame:?}"),
709 })
710 .collect()
711 })
712 }
713
714 pub fn take_ip_frames(&mut self) -> Vec<(PureIpDeviceAndIpVersion<FakeBindingsCtx>, Vec<u8>)> {
720 self.with_inner_mut(|ctx| {
721 ctx.frames
722 .take_frames()
723 .into_iter()
724 .map(|(meta, frame)| match meta {
725 DispatchedFrame::Ethernet(eth) => {
726 panic!("unexpected Ethernet frame {eth:?}: {frame:?}")
727 }
728 DispatchedFrame::PureIp(ip) => (ip, frame),
729 })
730 .collect()
731 })
732 }
733
734 pub fn take_events(&mut self) -> Vec<DispatchedEvent> {
736 self.with_inner_mut(|ctx| ctx.events.take())
737 }
738
739 pub fn take_icmp_replies<I: IpExt>(
741 &mut self,
742 conn: &IcmpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
743 ) -> Vec<Vec<u8>> {
744 I::map_ip_in(
745 (IpInvariant(self), conn),
746 |(IpInvariant(this), conn)| this.state_mut().icmpv4_replies.remove(conn),
747 |(IpInvariant(this), conn)| this.state_mut().icmpv6_replies.remove(conn),
748 )
749 .unwrap_or_else(Vec::default)
750 }
751
752 pub fn take_udp_received<I: IpExt>(
754 &mut self,
755 conn: &UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
756 ) -> Vec<Vec<u8>> {
757 self.state_mut().udp_state_mut::<I>().remove(conn).unwrap_or_else(Vec::default)
758 }
759
760 pub fn seed_rng(&self, seed: u128) {
762 self.with_inner_mut(|ctx| {
763 ctx.rng = FakeCryptoRng::new_xorshift(seed);
764 })
765 }
766}
767
768impl MatcherBindingsTypes for FakeBindingsCtx {
769 type DeviceClass = ();
770 type BindingsPacketMatcher = Never;
771}
772
773impl SocketOpsFilterBindingContext<DeviceId<FakeBindingsCtx>> for FakeBindingsCtx {
774 fn socket_ops_filter(&self) -> impl SocketOpsFilter<DeviceId<FakeBindingsCtx>> {
775 NoOpSocketOpsFilter
776 }
777}
778
779impl WithFakeTimerContext<TimerId<FakeBindingsCtx>> for FakeBindingsCtx {
780 fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId<FakeBindingsCtx>>) -> O>(
781 &self,
782 f: F,
783 ) -> O {
784 self.with_inner(|ctx| f(&ctx.timers))
785 }
786
787 fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId<FakeBindingsCtx>>) -> O>(
788 &mut self,
789 f: F,
790 ) -> O {
791 self.with_inner_mut(|ctx| f(&mut ctx.timers))
792 }
793}
794
795impl WithFakeFrameContext<DispatchedFrame> for FakeBindingsCtx {
796 fn with_fake_frame_ctx_mut<O, F: FnOnce(&mut FakeFrameCtx<DispatchedFrame>) -> O>(
797 &mut self,
798 f: F,
799 ) -> O {
800 self.with_inner_mut(|ctx| f(&mut ctx.frames))
801 }
802}
803
804impl InstantBindingsTypes for FakeBindingsCtx {
805 type Instant = FakeInstant;
806 type AtomicInstant = FakeAtomicInstant;
807}
808
809impl InstantContext for FakeBindingsCtx {
810 fn now(&self) -> FakeInstant {
811 self.with_inner(|ctx| ctx.now())
812 }
813}
814
815impl TimerBindingsTypes for FakeBindingsCtx {
816 type Timer = <FakeTimerCtx<TimerId<Self>> as TimerBindingsTypes>::Timer;
817 type DispatchId = TimerId<Self>;
818 type UniqueTimerId = <FakeTimerCtx<TimerId<Self>> as TimerBindingsTypes>::UniqueTimerId;
819}
820
821impl TimerContext for FakeBindingsCtx {
822 fn new_timer(&mut self, id: Self::DispatchId) -> Self::Timer {
823 self.with_inner_mut(|ctx| ctx.new_timer(id))
824 }
825
826 fn schedule_timer_instant(
827 &mut self,
828 time: Self::Instant,
829 timer: &mut Self::Timer,
830 ) -> Option<Self::Instant> {
831 match timer.dispatch_id.0 {
835 TimerIdInner::IpLayer(IpLayerTimerId::FilterTimerv4(FilterTimerId::ConntrackGc(_)))
836 | TimerIdInner::IpLayer(IpLayerTimerId::FilterTimerv6(FilterTimerId::ConntrackGc(_))) =>
837 {
838 return None;
839 }
840 _ => {}
841 }
842 self.with_inner_mut(|ctx| ctx.schedule_timer_instant(time, timer))
843 }
844
845 fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
846 self.with_inner_mut(|ctx| ctx.cancel_timer(timer))
847 }
848
849 fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
850 self.with_inner_mut(|ctx| ctx.scheduled_instant(timer))
851 }
852
853 fn unique_timer_id(&self, timer: &Self::Timer) -> Self::UniqueTimerId {
854 self.with_inner_mut(|ctx| ctx.unique_timer_id(timer))
855 }
856}
857
858impl TxMetadataBindingsTypes for FakeBindingsCtx {
859 type TxMetadata = CoreTxMetadata<Self>;
860}
861
862impl RngContext for FakeBindingsCtx {
863 type Rng<'a> = FakeCryptoRng;
864
865 fn rng(&mut self) -> Self::Rng<'_> {
866 let Self(this) = self;
867 this.lock().rng()
868 }
869}
870
871impl<T: Into<DispatchedEvent>> EventContext<T> for FakeBindingsCtx {
872 fn on_event(&mut self, event: T) {
873 self.with_inner_mut(|ctx| ctx.events.on_event(event.into()))
874 }
875}
876
877impl TcpBindingsTypes for FakeBindingsCtx {
878 type ReceiveBuffer = Arc<Mutex<RingBuffer>>;
879
880 type SendBuffer = TestSendBuffer;
881
882 type ReturnedBuffers = ClientBuffers;
883
884 type ListenerNotifierOrProvidedBuffers = ProvidedBuffers;
885
886 fn new_passive_open_buffers(
887 buffer_sizes: BufferSizes,
888 ) -> (Self::ReceiveBuffer, Self::SendBuffer, Self::ReturnedBuffers) {
889 let client = ClientBuffers::new(buffer_sizes);
890 (
891 Arc::clone(&client.receive),
892 TestSendBuffer::new(Arc::clone(&client.send), RingBuffer::default()),
893 client,
894 )
895 }
896}
897
898impl IpRoutingBindingsTypes for FakeBindingsCtx {
899 type RoutingTableId = ();
900}
901
902#[cfg(not(loom))]
903mod fake_notifiers {
904 use core::convert::Infallible as Never;
905
906 use super::*;
907
908 impl ReferenceNotifiers for FakeBindingsCtx {
909 type ReferenceReceiver<T: 'static> = Never;
910
911 type ReferenceNotifier<T: Send + 'static> = Never;
912
913 fn new_reference_notifier<T: Send + 'static>(
914 debug_references: DynDebugReferences,
915 ) -> (Self::ReferenceNotifier<T>, Self::ReferenceReceiver<T>) {
916 panic!(
920 "FakeBindingsCtx can't create deferred reference notifiers for type {}: \
921 debug_references={debug_references:?}",
922 core::any::type_name::<T>()
923 );
924 }
925 }
926
927 impl DeferredResourceRemovalContext for FakeBindingsCtx {
928 fn defer_removal<T: Send + 'static>(&mut self, receiver: Self::ReferenceReceiver<T>) {
929 match receiver {}
930 }
931 }
932}
933
934#[cfg(loom)]
937mod loom_notifiers {
938 use super::*;
939
940 use core::sync::atomic::{self, AtomicBool};
941 use netstack3_sync::rc::Notifier;
942
943 #[derive(Debug)]
944 pub struct LoomNotifier(Arc<AtomicBool>);
945
946 #[derive(Debug)]
947 pub struct LoomReceiver {
948 pub debug_refs: DynDebugReferences,
949 pub signal: Arc<AtomicBool>,
950 }
951
952 impl LoomReceiver {
953 #[track_caller]
954 pub fn assert_signalled(&self) {
955 let Self { debug_refs, signal } = self;
956 assert!(signal.load(atomic::Ordering::SeqCst), "pending references: {debug_refs:?}")
957 }
958 }
959
960 impl<T> Notifier<T> for LoomNotifier {
961 fn notify(&mut self, _data: T) {
962 let Self(signal) = self;
963 signal.store(true, atomic::Ordering::SeqCst);
964 }
965 }
966
967 impl ReferenceNotifiers for FakeBindingsCtx {
968 type ReferenceReceiver<T: 'static> = LoomReceiver;
969 type ReferenceNotifier<T: Send + 'static> = LoomNotifier;
970
971 fn new_reference_notifier<T: Send + 'static>(
972 debug_refs: DynDebugReferences,
973 ) -> (Self::ReferenceNotifier<T>, Self::ReferenceReceiver<T>) {
974 let signal = Arc::new(AtomicBool::default());
975 (LoomNotifier(Arc::clone(&signal)), LoomReceiver { debug_refs, signal })
976 }
977 }
978
979 impl DeferredResourceRemovalContext for FakeBindingsCtx {
980 fn defer_removal<T: Send + 'static>(&mut self, receiver: Self::ReferenceReceiver<T>) {
981 self.state_mut().deferred_receivers.push(receiver);
982 }
983 }
984}
985
986#[derive(Debug)]
988pub struct NoOpLinkResolutionNotifier;
989
990impl<D: LinkDevice> LinkResolutionContext<D> for FakeBindingsCtx {
991 type Notifier = NoOpLinkResolutionNotifier;
992}
993
994impl<D: LinkDevice> LinkResolutionNotifier<D> for NoOpLinkResolutionNotifier {
995 type Observer = ();
996
997 fn new() -> (Self, Self::Observer) {
998 (NoOpLinkResolutionNotifier, ())
999 }
1000
1001 fn notify(self, _result: Result<D::Address, AddressResolutionFailed>) {}
1002}
1003
1004#[derive(Clone)]
1005struct DeviceConfig {
1006 mac: UnicastAddr<Mac>,
1007 addr_subnet: Option<AddrSubnetEither>,
1008 ipv4_config: Option<Ipv4DeviceConfigurationUpdate>,
1009 ipv6_config: Option<Ipv6DeviceConfigurationUpdate>,
1010}
1011
1012#[derive(Clone, Default)]
1019pub struct FakeCtxBuilder {
1020 devices: Vec<DeviceConfig>,
1021 arp_table_entries: Vec<(usize, SpecifiedAddr<Ipv4Addr>, UnicastAddr<Mac>)>,
1023 ndp_table_entries: Vec<(usize, UnicastAddr<Ipv6Addr>, UnicastAddr<Mac>)>,
1024 device_routes: Vec<(SubnetEither, usize)>,
1026}
1027
1028impl FakeCtxBuilder {
1029 pub fn with_addrs<A: IpAddress>(addrs: TestAddrs<A>) -> FakeCtxBuilder {
1031 assert!(addrs.subnet.contains(&addrs.local_ip));
1032 assert!(addrs.subnet.contains(&addrs.remote_ip));
1033
1034 let mut builder = FakeCtxBuilder::default();
1035 builder.devices.push(DeviceConfig {
1036 mac: addrs.local_mac,
1037 addr_subnet: Some(
1038 AddrSubnetEither::new(addrs.local_ip.get().into(), addrs.subnet.prefix()).unwrap(),
1039 ),
1040 ipv4_config: None,
1041 ipv6_config: None,
1042 });
1043
1044 match addrs.remote_ip.into() {
1045 IpAddr::V4(ip) => builder.arp_table_entries.push((0, ip, addrs.remote_mac)),
1046 IpAddr::V6(ip) => builder.ndp_table_entries.push((
1047 0,
1048 UnicastAddr::new(ip.get()).unwrap(),
1049 addrs.remote_mac,
1050 )),
1051 };
1052
1053 builder.ndp_table_entries.push((
1056 0,
1057 addrs.remote_mac.to_ipv6_link_local().addr().get(),
1058 addrs.remote_mac,
1059 ));
1060
1061 builder.device_routes.push((addrs.subnet.into(), 0));
1062 builder
1063 }
1064
1065 pub fn add_device(&mut self, mac: UnicastAddr<Mac>) -> usize {
1070 let idx = self.devices.len();
1071 self.devices.push(DeviceConfig {
1072 mac,
1073 addr_subnet: None,
1074 ipv4_config: None,
1075 ipv6_config: None,
1076 });
1077 idx
1078 }
1079
1080 pub fn add_device_with_config(
1085 &mut self,
1086 mac: UnicastAddr<Mac>,
1087 ipv4_config: Ipv4DeviceConfigurationUpdate,
1088 ipv6_config: Ipv6DeviceConfigurationUpdate,
1089 ) -> usize {
1090 let idx = self.devices.len();
1091 self.devices.push(DeviceConfig {
1092 mac,
1093 addr_subnet: None,
1094 ipv4_config: Some(ipv4_config),
1095 ipv6_config: Some(ipv6_config),
1096 });
1097 idx
1098 }
1099
1100 pub fn add_device_with_ip<A: IpAddress>(
1105 &mut self,
1106 mac: UnicastAddr<Mac>,
1107 ip: A,
1108 subnet: Subnet<A>,
1109 ) -> usize {
1110 assert!(subnet.contains(&ip));
1111 let idx = self.devices.len();
1112 self.devices.push(DeviceConfig {
1113 mac,
1114 addr_subnet: Some(AddrSubnetEither::new(ip.into(), subnet.prefix()).unwrap()),
1115 ipv4_config: None,
1116 ipv6_config: None,
1117 });
1118 self.device_routes.push((subnet.into(), idx));
1119 idx
1120 }
1121
1122 pub fn add_device_with_ip_and_config<A: IpAddress>(
1130 &mut self,
1131 mac: UnicastAddr<Mac>,
1132 ip: A,
1133 subnet: Subnet<A>,
1134 ipv4_config: Ipv4DeviceConfigurationUpdate,
1135 ipv6_config: Ipv6DeviceConfigurationUpdate,
1136 ) -> usize {
1137 assert!(subnet.contains(&ip));
1138 let idx = self.devices.len();
1139 self.devices.push(DeviceConfig {
1140 mac,
1141 addr_subnet: Some(AddrSubnetEither::new(ip.into(), subnet.prefix()).unwrap()),
1142 ipv4_config: Some(ipv4_config),
1143 ipv6_config: Some(ipv6_config),
1144 });
1145 self.device_routes.push((subnet.into(), idx));
1146 idx
1147 }
1148
1149 pub fn add_arp_table_entry(
1151 &mut self,
1152 device: usize,
1153 ip: SpecifiedAddr<Ipv4Addr>,
1155 mac: UnicastAddr<Mac>,
1156 ) {
1157 self.arp_table_entries.push((device, ip, mac));
1158 }
1159
1160 pub fn add_ndp_table_entry(
1162 &mut self,
1163 device: usize,
1164 ip: UnicastAddr<Ipv6Addr>,
1166 mac: UnicastAddr<Mac>,
1167 ) {
1168 self.ndp_table_entries.push((device, ip, mac));
1169 }
1170
1171 pub fn add_arp_or_ndp_table_entry<A: IpAddress>(
1174 &mut self,
1175 device: usize,
1176 ip: SpecifiedAddr<A>,
1178 mac: UnicastAddr<Mac>,
1179 ) {
1180 match ip.into() {
1181 IpAddr::V4(ip) => self.add_arp_table_entry(device, ip, mac),
1182 IpAddr::V6(ip) => {
1183 self.add_ndp_table_entry(device, UnicastAddr::new(ip.get()).unwrap(), mac)
1184 }
1185 }
1186 }
1187
1188 pub fn build(self) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1190 self.build_with_modifications(|_| {})
1191 }
1192
1193 pub fn build_with_modifications<F: FnOnce(&mut StackStateBuilder)>(
1197 self,
1198 f: F,
1199 ) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1200 let mut stack_builder = StackStateBuilder::default();
1201 f(&mut stack_builder);
1202 self.build_with(stack_builder)
1203 }
1204
1205 pub fn build_with(
1208 self,
1209 state_builder: StackStateBuilder,
1210 ) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1211 let mut ctx = Ctx::new_with_builder(state_builder);
1212
1213 let FakeCtxBuilder { devices, arp_table_entries, ndp_table_entries, device_routes } = self;
1214 let idx_to_device_id: Vec<_> = devices
1215 .into_iter()
1216 .map(|DeviceConfig { mac, addr_subnet: ip_and_subnet, ipv4_config, ipv6_config }| {
1217 let eth_id =
1218 ctx.core_api().device::<EthernetLinkDevice>().add_device_with_default_state(
1219 EthernetCreationProperties {
1220 mac: mac,
1221 max_frame_size: IPV6_MIN_IMPLIED_MAX_FRAME_SIZE,
1222 },
1223 DEFAULT_INTERFACE_METRIC,
1224 );
1225 let id = eth_id.clone().into();
1226 if let Some(ipv4_config) = ipv4_config {
1227 let _previous = ctx
1228 .core_api()
1229 .device_ip::<Ipv4>()
1230 .update_configuration(&id, ipv4_config)
1231 .unwrap();
1232 }
1233 if let Some(ipv6_config) = ipv6_config {
1234 let _previous = ctx
1235 .core_api()
1236 .device_ip::<Ipv6>()
1237 .update_configuration(&id, ipv6_config)
1238 .unwrap();
1239 }
1240 ctx.test_api().enable_device(&id);
1241 match ip_and_subnet {
1242 Some(addr_sub) => {
1243 ctx.core_api().device_ip_any().add_ip_addr_subnet(&id, addr_sub).unwrap();
1244 }
1245 None => {}
1246 }
1247 eth_id
1248 })
1249 .collect();
1250 for (idx, ip, mac) in arp_table_entries {
1251 let device = &idx_to_device_id[idx];
1252 ctx.core_api()
1253 .neighbor::<Ipv4, EthernetLinkDevice>()
1254 .insert_static_entry(&device, ip.get(), mac.get())
1255 .expect("error inserting static ARP entry");
1256 }
1257 for (idx, ip, mac) in ndp_table_entries {
1258 let device = &idx_to_device_id[idx];
1259 ctx.core_api()
1260 .neighbor::<Ipv6, EthernetLinkDevice>()
1261 .insert_static_entry(&device, ip.get(), mac.get())
1262 .expect("error inserting static NDP entry");
1263 }
1264
1265 for (subnet, idx) in device_routes {
1266 let device = &idx_to_device_id[idx];
1267 ctx.test_api()
1268 .add_route(AddableEntryEither::without_gateway(
1269 subnet,
1270 device.clone().into(),
1271 AddableMetric::ExplicitMetric(RawMetric(0)),
1272 ))
1273 .expect("add device route");
1274 }
1275
1276 (ctx, idx_to_device_id)
1277 }
1278}
1279
1280pub enum FakeCtxNetworkSpec {}
1284
1285impl FakeNetworkSpec for FakeCtxNetworkSpec {
1286 type Context = FakeCtx;
1287 type TimerId = TimerId<FakeBindingsCtx>;
1288 type SendMeta = DispatchedFrame;
1289 type RecvMeta = EthernetDeviceId<FakeBindingsCtx>;
1290 fn handle_frame(ctx: &mut FakeCtx, device_id: Self::RecvMeta, data: Buf<Vec<u8>>) {
1291 ctx.core_api()
1292 .device::<EthernetLinkDevice>()
1293 .receive_frame(RecvEthernetFrameMeta { device_id }, data)
1294 }
1295 fn handle_timer(ctx: &mut FakeCtx, dispatch: Self::TimerId, timer: FakeTimerId) {
1296 ctx.core_api().handle_timer(dispatch, timer)
1297 }
1298 fn process_queues(ctx: &mut FakeCtx) -> bool {
1299 ctx.test_api().handle_queued_rx_packets()
1300 }
1301 fn fake_frames(ctx: &mut FakeCtx) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
1302 &mut ctx.bindings_ctx
1303 }
1304}
1305
1306impl<I: IpExt> UdpReceiveBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1307 fn receive_udp(
1308 &mut self,
1309 id: &UdpSocketId<I, WeakDeviceId<Self>, FakeBindingsCtx>,
1310 _device_id: &DeviceId<Self>,
1311 _meta: UdpPacketMeta<I>,
1312 body: &[u8],
1313 ) -> Result<(), ReceiveUdpError> {
1314 let mut state = self.state_mut();
1315 let received =
1316 (&mut *state).udp_state_mut::<I>().entry(id.clone()).or_insert_with(Vec::default);
1317 received.push(body.to_owned());
1318 Ok(())
1319 }
1320}
1321
1322impl UdpBindingsTypes for FakeBindingsCtx {
1323 type ExternalData<I: Ip> = ();
1324 type SocketWritableListener = FakeSocketWritableListener;
1325}
1326
1327impl<I: IpExt> IcmpEchoBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1328 fn receive_icmp_echo_reply<B: BufferMut>(
1329 &mut self,
1330 conn: &IcmpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
1331 _device: &DeviceId<Self>,
1332 _src_ip: I::Addr,
1333 _dst_ip: I::Addr,
1334 _id: u16,
1335 data: B,
1336 ) -> Result<(), ReceiveIcmpEchoError> {
1337 I::map_ip_in(
1338 (IpInvariant(self.state_mut()), conn.clone()),
1339 |(IpInvariant(mut state), conn)| {
1340 let replies = state.icmpv4_replies.entry(conn).or_insert_with(Vec::default);
1341 replies.push(data.as_ref().to_owned());
1342 },
1343 |(IpInvariant(mut state), conn)| {
1344 let replies = state.icmpv6_replies.entry(conn).or_insert_with(Vec::default);
1345 replies.push(data.as_ref().to_owned());
1346 },
1347 );
1348 Ok(())
1349 }
1350}
1351
1352impl IcmpEchoBindingsTypes for FakeBindingsCtx {
1353 type ExternalData<I: Ip> = ();
1354 type SocketWritableListener = FakeSocketWritableListener;
1355}
1356
1357impl DeviceSocketTypes for FakeBindingsCtx {
1358 type SocketState<D: Send + Sync + Debug> = Mutex<Vec<(WeakDeviceId<FakeBindingsCtx>, Vec<u8>)>>;
1359}
1360
1361impl RawIpSocketsBindingsTypes for FakeBindingsCtx {
1362 type RawIpSocketState<I: Ip> = ();
1363}
1364
1365impl DeviceSocketBindingsContext<DeviceId<Self>> for FakeBindingsCtx {
1366 fn receive_frame(
1367 &self,
1368 socket_id: &SocketId<Self>,
1369 device: &DeviceId<Self>,
1370 _frame: device::socket::Frame<&[u8]>,
1371 raw_frame: &[u8],
1372 ) -> Result<(), ReceiveFrameError> {
1373 let state = socket_id.socket_state();
1374 state.lock().push((device.downgrade(), raw_frame.into()));
1375 Ok(())
1376 }
1377}
1378
1379impl<I: IpExt> RawIpSocketsBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1380 fn receive_packet<B: SplitByteSlice>(
1381 &self,
1382 _socket: &RawIpSocketId<I, WeakDeviceId<Self>, Self>,
1383 _packet: &I::Packet<B>,
1384 _device: &DeviceId<Self>,
1385 ) -> Result<(), ReceivePacketError> {
1386 unimplemented!()
1387 }
1388}
1389
1390impl DeviceLayerStateTypes for FakeBindingsCtx {
1391 type LoopbackDeviceState = ();
1392 type EthernetDeviceState = ();
1393 type BlackholeDeviceState = ();
1394 type PureIpDeviceState = ();
1395 type DeviceIdentifier = MonotonicIdentifier;
1396}
1397
1398impl ReceiveQueueBindingsContext<LoopbackDeviceId<Self>> for FakeBindingsCtx {
1399 fn wake_rx_task(&mut self, device: &LoopbackDeviceId<FakeBindingsCtx>) {
1400 self.state_mut().rx_available.push(device.clone());
1401 }
1402}
1403
1404impl<D: Clone + Into<DeviceId<Self>>> TransmitQueueBindingsContext<D> for FakeBindingsCtx {
1405 fn wake_tx_task(&mut self, device: &D) {
1406 self.state_mut().tx_available.push(device.clone().into());
1407 }
1408}
1409
1410impl DeviceLayerEventDispatcher for FakeBindingsCtx {
1411 type DequeueContext = ();
1412
1413 fn send_ethernet_frame(
1414 &mut self,
1415 device: &EthernetDeviceId<FakeBindingsCtx>,
1416 frame: Buf<Vec<u8>>,
1417 _dequeue_context: Option<&mut Self::DequeueContext>,
1418 ) -> Result<(), DeviceSendFrameError> {
1419 let frame_meta = DispatchedFrame::Ethernet(device.downgrade());
1420 self.with_inner_mut(|ctx| ctx.frames.push(frame_meta, frame.into_inner()));
1421 Ok(())
1422 }
1423
1424 fn send_ip_packet(
1425 &mut self,
1426 device: &PureIpDeviceId<FakeBindingsCtx>,
1427 packet: Buf<Vec<u8>>,
1428 ip_version: IpVersion,
1429 _dequeue_context: Option<&mut Self::DequeueContext>,
1430 ) -> Result<(), DeviceSendFrameError> {
1431 let frame_meta = DispatchedFrame::PureIp(PureIpDeviceAndIpVersion {
1432 device: device.downgrade(),
1433 version: ip_version,
1434 });
1435 self.with_inner_mut(|ctx| ctx.frames.push(frame_meta, packet.into_inner()));
1436 Ok(())
1437 }
1438}
1439
1440impl AlwaysDefaultsSettingsContext for FakeBindingsCtx {}
1441
1442#[derive(Debug, Eq, PartialEq, Hash, GenericOverIp)]
1444#[generic_over_ip()]
1445#[allow(missing_docs)]
1446pub enum DispatchedEvent {
1447 IpDeviceIpv4(IpDeviceEvent<WeakDeviceId<FakeBindingsCtx>, Ipv4, FakeInstant>),
1448 IpDeviceIpv6(IpDeviceEvent<WeakDeviceId<FakeBindingsCtx>, Ipv6, FakeInstant>),
1449 IpLayerIpv4(IpLayerEvent<WeakDeviceId<FakeBindingsCtx>, Ipv4>),
1450 IpLayerIpv6(IpLayerEvent<WeakDeviceId<FakeBindingsCtx>, Ipv6>),
1451 NeighborIpv4(nud::Event<Mac, EthernetWeakDeviceId<FakeBindingsCtx>, Ipv4, FakeInstant>),
1452 NeighborIpv6(nud::Event<Mac, EthernetWeakDeviceId<FakeBindingsCtx>, Ipv6, FakeInstant>),
1453 RouterAdvertisement(RouterAdvertisementEvent<WeakDeviceId<FakeBindingsCtx>>),
1454 EthernetDevice(EthernetDeviceEvent<EthernetWeakDeviceId<FakeBindingsCtx>>),
1455}
1456
1457#[derive(Derivative)]
1459#[derivative(Debug(bound = ""))]
1460#[allow(missing_docs)]
1461pub struct PureIpDeviceAndIpVersion<BT: DeviceLayerTypes> {
1462 pub device: PureIpWeakDeviceId<BT>,
1463 pub version: IpVersion,
1464}
1465
1466#[derive(Debug)]
1468pub enum DispatchedFrame {
1469 Ethernet(EthernetWeakDeviceId<FakeBindingsCtx>),
1471 PureIp(PureIpDeviceAndIpVersion<FakeBindingsCtx>),
1473}
1474
1475impl<I: Ip> From<IpDeviceEvent<DeviceId<FakeBindingsCtx>, I, FakeInstant>> for DispatchedEvent {
1476 fn from(e: IpDeviceEvent<DeviceId<FakeBindingsCtx>, I, FakeInstant>) -> DispatchedEvent {
1477 let e = e.map_device(|d| d.downgrade());
1478 I::map_ip(e, |e| DispatchedEvent::IpDeviceIpv4(e), |e| DispatchedEvent::IpDeviceIpv6(e))
1479 }
1480}
1481
1482impl<I: IpExt> From<IpLayerEvent<DeviceId<FakeBindingsCtx>, I>> for DispatchedEvent {
1483 fn from(e: IpLayerEvent<DeviceId<FakeBindingsCtx>, I>) -> DispatchedEvent {
1484 let e = e.map_device(|d| d.downgrade());
1485 I::map_ip(e, |e| DispatchedEvent::IpLayerIpv4(e), |e| DispatchedEvent::IpLayerIpv6(e))
1486 }
1487}
1488
1489impl<I: Ip> From<nud::Event<Mac, EthernetDeviceId<FakeBindingsCtx>, I, FakeInstant>>
1490 for DispatchedEvent
1491{
1492 fn from(
1493 e: nud::Event<Mac, EthernetDeviceId<FakeBindingsCtx>, I, FakeInstant>,
1494 ) -> DispatchedEvent {
1495 let e = e.map_device(|d| d.downgrade());
1496 I::map_ip(e, |e| DispatchedEvent::NeighborIpv4(e), |e| DispatchedEvent::NeighborIpv6(e))
1497 }
1498}
1499
1500impl From<EthernetDeviceEvent<EthernetDeviceId<FakeBindingsCtx>>> for DispatchedEvent {
1501 fn from(e: EthernetDeviceEvent<EthernetDeviceId<FakeBindingsCtx>>) -> DispatchedEvent {
1502 let e = e.map_device(|d| d.downgrade());
1503 DispatchedEvent::EthernetDevice(e)
1504 }
1505}
1506
1507impl From<RouterAdvertisementEvent<DeviceId<FakeBindingsCtx>>> for DispatchedEvent {
1508 fn from(e: RouterAdvertisementEvent<DeviceId<FakeBindingsCtx>>) -> DispatchedEvent {
1509 let e = e.map_device(|d| d.downgrade());
1510 DispatchedEvent::RouterAdvertisement(e)
1511 }
1512}
1513
1514pub fn new_simple_fake_network<CtxId: Copy + Debug + Hash + Eq>(
1520 a_id: CtxId,
1521 a: FakeCtx,
1522 a_device_id: EthernetWeakDeviceId<FakeBindingsCtx>,
1523 b_id: CtxId,
1524 b: FakeCtx,
1525 b_device_id: EthernetWeakDeviceId<FakeBindingsCtx>,
1526) -> FakeNetwork<
1527 FakeCtxNetworkSpec,
1528 CtxId,
1529 impl FakeNetworkLinks<DispatchedFrame, EthernetDeviceId<FakeBindingsCtx>, CtxId>,
1530> {
1531 let contexts = vec![(a_id, a), (b_id, b)].into_iter();
1532 FakeNetwork::new(contexts, move |net, _frame: DispatchedFrame| {
1533 if net == a_id {
1534 b_device_id
1535 .upgrade()
1536 .map(|device_id| (b_id, device_id, None))
1537 .into_iter()
1538 .collect::<Vec<_>>()
1539 } else {
1540 a_device_id
1541 .upgrade()
1542 .map(|device_id| (a_id, device_id, None))
1543 .into_iter()
1544 .collect::<Vec<_>>()
1545 }
1546 })
1547}