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