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