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