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::fmt::Debug;
19use core::hash::Hash;
20use core::ops::{Deref, DerefMut};
21use core::time::Duration;
22
23use derivative::Derivative;
24use net_types::ethernet::Mac;
25use net_types::ip::{
26 AddrSubnet, AddrSubnetEither, GenericOverIp, Ip, IpAddr, IpAddress, IpInvariant, IpVersion,
27 Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Mtu, Subnet, SubnetEither,
28};
29use net_types::{MulticastAddr, SpecifiedAddr, UnicastAddr, Witness as _};
30use netstack3_base::sync::{DynDebugReferences, Mutex};
31use netstack3_base::testutil::{
32 AlwaysDefaultsSettingsContext, FakeAtomicInstant, FakeCryptoRng, FakeFrameCtx, FakeInstant,
33 FakeNetwork, FakeNetworkLinks, FakeNetworkSpec, FakeSendToken, FakeTimerCtx, FakeTimerCtxExt,
34 FakeTimerId, MonotonicIdentifier, TestAddrs, WithFakeFrameContext, WithFakeTimerContext,
35};
36use netstack3_base::{
37 AddressResolutionFailed, CtxPair, DeferredResourceRemovalContext, EventContext,
38 InstantBindingsTypes, InstantContext, IpDeviceAddr, LinkDevice, LocalFrameDestination,
39 MarkDomain, Marks, MatcherBindingsTypes, NetworkParsingContext, NotFoundError,
40 ReferenceNotifiers, RemoveResourceResult, RemoveResourceResultWithContext, RngContext,
41 SocketDiagnosticsSeed, TimerBindingsTypes, TimerContext, TimerHandler, TxMetadataBindingsTypes,
42 WorkQueueReport,
43};
44use netstack3_datagram::PendingDatagramSocketError;
45use netstack3_device::ethernet::{
46 EthernetCreationProperties, EthernetDeviceEvent, EthernetDeviceId, EthernetLinkDevice,
47 EthernetWeakDeviceId, RecvEthernetFrameMeta,
48};
49use netstack3_device::loopback::{LoopbackCreationProperties, LoopbackDevice, LoopbackDeviceId};
50use netstack3_device::pure_ip::{PureIpDeviceId, PureIpWeakDeviceId};
51use netstack3_device::queue::{ReceiveQueueBindingsContext, TransmitQueueBindingsContext};
52use netstack3_device::socket::{
53 DeviceSocketBindingsContext, DeviceSocketTypes, ReceiveFrameError, SocketId,
54};
55use netstack3_device::testutil::IPV6_MIN_IMPLIED_MAX_FRAME_SIZE;
56use netstack3_device::{
57 self as device, DeviceBufferBindingsTypes, DeviceId, DeviceLayerEventDispatcher,
58 DeviceLayerStateTypes, DeviceLayerTypes, DeviceProvider, DeviceSendFrameError, WeakDeviceId,
59 for_any_device_id,
60};
61use netstack3_filter::{FilterTimerId, SocketOpsFilter, SocketOpsFilterBindingContext};
62use netstack3_hashmap::HashMap;
63use netstack3_icmp_echo::{
64 IcmpEchoBindingsContext, IcmpEchoBindingsTypes, IcmpSocketId, ReceiveIcmpEchoError,
65};
66use netstack3_ip::device::{
67 IpDeviceConfiguration, IpDeviceConfigurationUpdate, IpDeviceEvent,
68 Ipv4DeviceConfigurationUpdate, Ipv6DeviceConfigurationUpdate,
69};
70use netstack3_ip::nud::{self, LinkResolutionContext, LinkResolutionNotifier};
71use netstack3_ip::raw::{
72 RawIpSocketId, RawIpSocketsBindingsContext, RawIpSocketsBindingsTypes, ReceivePacketError,
73};
74use netstack3_ip::{
75 self as ip, AddRouteError, AddableEntryEither, AddableMetric, DeviceIpLayerMetadata,
76 IpLayerEvent, IpLayerTimerId, IpRoutingBindingsTypes, MarksBindingsContext, RawMetric,
77 ResolveRouteError, ResolvedRoute, RoutableIpAddr, RouterAdvertisementEvent,
78};
79use netstack3_tcp::testutil::{ClientBuffers, ProvidedBuffers, RingBuffer, TestSendBuffer};
80use netstack3_tcp::{
81 BufferSizes, TcpBindingsTypes, TcpSocketDestructionContext, TcpSocketDiagnostics,
82};
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 self.receive_ip_packet_with_marks_and_context::<I, B>(
310 device,
311 frame_dst,
312 buffer,
313 marks,
314 NetworkParsingContext::default(),
315 )
316 }
317
318 pub fn receive_ip_packet_with_marks_and_context<I: Ip, B: BufferMut>(
323 &mut self,
324 device: &DeviceId<BC>,
325 frame_dst: Option<LocalFrameDestination>,
326 buffer: B,
327 marks: Marks,
328 parsing_context: NetworkParsingContext,
329 ) {
330 let (core_ctx, bindings_ctx) = self.contexts();
331 match I::VERSION {
332 IpVersion::V4 => ip::receive_ipv4_packet(
333 core_ctx,
334 bindings_ctx,
335 device,
336 frame_dst,
337 DeviceIpLayerMetadata::with_marks(marks),
338 parsing_context,
339 None,
340 buffer,
341 ),
342 IpVersion::V6 => ip::receive_ipv6_packet(
343 core_ctx,
344 bindings_ctx,
345 device,
346 frame_dst,
347 DeviceIpLayerMetadata::with_marks(marks),
348 parsing_context,
349 None,
350 buffer,
351 ),
352 }
353 }
354
355 pub fn receive_ethernet_frame<B: BufferMut + Debug>(
357 &mut self,
358 device: &EthernetDeviceId<BC>,
359 buffer: B,
360 ) {
361 self.core_api().device::<EthernetLinkDevice>().receive_frame(
362 RecvEthernetFrameMeta {
363 device_id: device.clone(),
364 parsing_context: NetworkParsingContext::default(),
365 gso_info: None,
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 pub socket_ingress_filter_marks: Vec<(netstack3_base::socket::SocketInfo, Marks)>,
602 #[cfg(loom)]
604 pub deferred_receivers: Vec<loom_notifiers::LoomReceiver>,
605}
606
607impl FakeBindingsCtxState {
608 pub(crate) fn udp_state_mut<I: IpExt>(
609 &mut self,
610 ) -> &mut HashMap<UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>
611 {
612 #[derive(GenericOverIp)]
613 #[generic_over_ip(I, Ip)]
614 struct Wrapper<'a, I: IpExt>(
615 &'a mut HashMap<
616 UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
617 Vec<Vec<u8>>,
618 >,
619 );
620 let Wrapper(map) = I::map_ip_out::<_, Wrapper<'_, I>>(
621 self,
622 |this| Wrapper(&mut this.udpv4_received),
623 |this| Wrapper(&mut this.udpv6_received),
624 );
625 map
626 }
627}
628
629pub type FakeCtx = Ctx<FakeBindingsCtx>;
631pub type FakeCoreCtx = StackState<FakeBindingsCtx>;
633
634type InnerFakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<
635 TimerId<FakeBindingsCtx>,
636 DispatchedEvent,
637 FakeBindingsCtxState,
638 DispatchedFrame,
639>;
640
641#[derive(Default, Clone)]
643pub struct FakeBindingsCtx(Arc<Mutex<InnerFakeBindingsCtx>>);
644
645struct Wrapper<S, Callback, CallbackMut>(S, Callback, CallbackMut);
655
656impl<T: ?Sized, S: Deref, Callback: for<'a> Fn(&'a <S as Deref>::Target) -> &'a T, CallbackMut>
657 Deref for Wrapper<S, Callback, CallbackMut>
658{
659 type Target = T;
660
661 fn deref(&self) -> &T {
662 let Self(guard, f, _) = self;
663 let target = guard.deref();
664 f(target)
665 }
666}
667
668impl<
669 T: ?Sized,
670 S: DerefMut,
671 Callback: for<'a> Fn(&'a <S as Deref>::Target) -> &'a T,
672 CallbackMut: for<'a> Fn(&'a mut <S as Deref>::Target) -> &'a mut T,
673> DerefMut for Wrapper<S, Callback, CallbackMut>
674{
675 fn deref_mut(&mut self) -> &mut T {
676 let Self(guard, _, f) = self;
677 let target = guard.deref_mut();
678 f(target)
679 }
680}
681
682impl FakeBindingsCtx {
683 fn with_inner<F: FnOnce(&InnerFakeBindingsCtx) -> O, O>(&self, f: F) -> O {
684 let Self(this) = self;
685 let locked = this.lock();
686 f(&*locked)
687 }
688
689 fn with_inner_mut<F: FnOnce(&mut InnerFakeBindingsCtx) -> O, O>(&self, f: F) -> O {
690 let Self(this) = self;
691 let mut locked = this.lock();
692 f(&mut *locked)
693 }
694
695 pub fn timer_ctx(&self) -> impl Deref<Target = FakeTimerCtx<TimerId<Self>>> + '_ {
697 fn get_timers<'a>(
700 i: &'a InnerFakeBindingsCtx,
701 ) -> &'a FakeTimerCtx<TimerId<FakeBindingsCtx>> {
702 &i.timers
703 }
704 Wrapper(self.0.lock(), get_timers, ())
705 }
706
707 pub fn state_mut(&mut self) -> impl DerefMut<Target = FakeBindingsCtxState> + '_ {
709 fn get_state<'a>(i: &'a InnerFakeBindingsCtx) -> &'a FakeBindingsCtxState {
712 &i.state
713 }
714 fn get_state_mut<'a>(i: &'a mut InnerFakeBindingsCtx) -> &'a mut FakeBindingsCtxState {
715 &mut i.state
716 }
717 Wrapper(self.0.lock(), get_state, get_state_mut)
718 }
719
720 pub fn copy_ethernet_frames(
726 &mut self,
727 ) -> Vec<(EthernetWeakDeviceId<FakeBindingsCtx>, Vec<u8>)> {
728 self.with_inner_mut(|ctx| {
729 ctx.frames
730 .frames()
731 .iter()
732 .map(|(meta, frame)| match meta {
733 DispatchedFrame::Ethernet(eth) => (eth.clone(), frame.clone()),
734 DispatchedFrame::PureIp(ip) => panic!("unexpected IP packet {ip:?}: {frame:?}"),
735 })
736 .collect()
737 })
738 }
739
740 pub fn take_ethernet_frames(
746 &mut self,
747 ) -> Vec<(EthernetWeakDeviceId<FakeBindingsCtx>, Vec<u8>)> {
748 self.with_inner_mut(|ctx| {
749 ctx.frames
750 .take_frames()
751 .into_iter()
752 .map(|(meta, frame)| match meta {
753 DispatchedFrame::Ethernet(eth) => (eth, frame),
754 DispatchedFrame::PureIp(ip) => panic!("unexpected IP packet {ip:?}: {frame:?}"),
755 })
756 .collect()
757 })
758 }
759
760 pub fn take_ip_frames(&mut self) -> Vec<(PureIpDeviceAndIpVersion<FakeBindingsCtx>, Vec<u8>)> {
766 self.with_inner_mut(|ctx| {
767 ctx.frames
768 .take_frames()
769 .into_iter()
770 .map(|(meta, frame)| match meta {
771 DispatchedFrame::Ethernet(eth) => {
772 panic!("unexpected Ethernet frame {eth:?}: {frame:?}")
773 }
774 DispatchedFrame::PureIp(ip) => (ip, frame),
775 })
776 .collect()
777 })
778 }
779
780 pub fn take_events(&mut self) -> Vec<DispatchedEvent> {
782 self.with_inner_mut(|ctx| ctx.events.take())
783 }
784
785 pub fn take_icmp_replies<I: IpExt>(
787 &mut self,
788 conn: &IcmpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
789 ) -> Vec<Vec<u8>> {
790 I::map_ip_in(
791 (IpInvariant(self), conn),
792 |(IpInvariant(this), conn)| this.state_mut().icmpv4_replies.remove(conn),
793 |(IpInvariant(this), conn)| this.state_mut().icmpv6_replies.remove(conn),
794 )
795 .unwrap_or_else(Vec::default)
796 }
797
798 pub fn take_udp_received<I: IpExt>(
800 &mut self,
801 conn: &UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
802 ) -> Vec<Vec<u8>> {
803 self.state_mut().udp_state_mut::<I>().remove(conn).unwrap_or_else(Vec::default)
804 }
805
806 pub fn seed_rng(&self, seed: u128) {
808 self.with_inner_mut(|ctx| {
809 ctx.rng = FakeCryptoRng::new_xorshift(seed);
810 })
811 }
812
813 pub fn sleep(&self, duration: Duration) {
815 self.with_inner_mut(|ctx| ctx.timers.instant.sleep(duration));
816 }
817}
818
819impl MatcherBindingsTypes for FakeBindingsCtx {
820 type DeviceClass = ();
821 type BindingsPacketMatcher = !;
822}
823
824impl DeviceBufferBindingsTypes for FakeBindingsCtx {
825 type TxBuffer = packet::Buf<Vec<u8>>;
826 type TxAllocator = netstack3_device::queue::BufVecU8Allocator;
827}
828
829struct FakeSocketOpsFilter<'a>(&'a FakeBindingsCtx);
830
831impl SocketOpsFilter<DeviceId<FakeBindingsCtx>> for FakeSocketOpsFilter<'_> {
832 fn on_egress<I: netstack3_filter::FilterIpExt, P: netstack3_filter::FilterIpPacket<I>>(
833 &self,
834 _packet: &P,
835 _device: &DeviceId<FakeBindingsCtx>,
836 _socket_info: netstack3_base::socket::SocketInfo,
837 _marks: &Marks,
838 ) -> netstack3_filter::SocketEgressFilterResult {
839 netstack3_filter::SocketEgressFilterResult::Pass { congestion: false }
840 }
841
842 fn on_ingress(
843 &self,
844 _ip_version: net_types::ip::IpVersion,
845 _packet: packet::FragmentedByteSlice<'_, &[u8]>,
846 _header_len: usize,
847 _device: &DeviceId<FakeBindingsCtx>,
848 socket_info: netstack3_base::socket::SocketInfo,
849 marks: &Marks,
850 ) -> netstack3_filter::SocketIngressFilterResult {
851 self.0.0.lock().state.socket_ingress_filter_marks.push((socket_info, *marks));
852 netstack3_filter::SocketIngressFilterResult::Accept
853 }
854}
855
856impl SocketOpsFilterBindingContext<DeviceId<FakeBindingsCtx>> for FakeBindingsCtx {
857 fn socket_ops_filter(&self) -> impl SocketOpsFilter<DeviceId<FakeBindingsCtx>> {
858 FakeSocketOpsFilter(self)
859 }
860}
861
862impl WithFakeTimerContext<TimerId<FakeBindingsCtx>> for FakeBindingsCtx {
863 fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId<FakeBindingsCtx>>) -> O>(
864 &self,
865 f: F,
866 ) -> O {
867 self.with_inner(|ctx| f(&ctx.timers))
868 }
869
870 fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId<FakeBindingsCtx>>) -> O>(
871 &mut self,
872 f: F,
873 ) -> O {
874 self.with_inner_mut(|ctx| f(&mut ctx.timers))
875 }
876}
877
878impl WithFakeFrameContext<DispatchedFrame> for FakeBindingsCtx {
879 fn with_fake_frame_ctx_mut<O, F: FnOnce(&mut FakeFrameCtx<DispatchedFrame>) -> O>(
880 &mut self,
881 f: F,
882 ) -> O {
883 self.with_inner_mut(|ctx| f(&mut ctx.frames))
884 }
885}
886
887impl InstantBindingsTypes for FakeBindingsCtx {
888 type Instant = FakeInstant;
889 type AtomicInstant = FakeAtomicInstant;
890}
891
892impl InstantContext for FakeBindingsCtx {
893 fn now(&self) -> FakeInstant {
894 self.with_inner(|ctx| ctx.now())
895 }
896}
897
898impl TimerBindingsTypes for FakeBindingsCtx {
899 type Timer = <FakeTimerCtx<TimerId<Self>> as TimerBindingsTypes>::Timer;
900 type DispatchId = TimerId<Self>;
901 type UniqueTimerId = <FakeTimerCtx<TimerId<Self>> as TimerBindingsTypes>::UniqueTimerId;
902}
903
904impl TimerContext for FakeBindingsCtx {
905 fn new_timer(&mut self, id: Self::DispatchId) -> Self::Timer {
906 self.with_inner_mut(|ctx| ctx.new_timer(id))
907 }
908
909 fn schedule_timer_instant(
910 &mut self,
911 time: Self::Instant,
912 timer: &mut Self::Timer,
913 ) -> Option<Self::Instant> {
914 match timer.dispatch_id.0 {
918 TimerIdInner::IpLayer(IpLayerTimerId::FilterTimerv4(FilterTimerId::ConntrackGc(_)))
919 | TimerIdInner::IpLayer(IpLayerTimerId::FilterTimerv6(FilterTimerId::ConntrackGc(_))) =>
920 {
921 return None;
922 }
923 _ => {}
924 }
925 self.with_inner_mut(|ctx| ctx.schedule_timer_instant(time, timer))
926 }
927
928 fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
929 self.with_inner_mut(|ctx| ctx.cancel_timer(timer))
930 }
931
932 fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
933 self.with_inner_mut(|ctx| ctx.scheduled_instant(timer))
934 }
935
936 fn unique_timer_id(&self, timer: &Self::Timer) -> Self::UniqueTimerId {
937 self.with_inner_mut(|ctx| ctx.unique_timer_id(timer))
938 }
939}
940
941impl TxMetadataBindingsTypes for FakeBindingsCtx {
942 type TxMetadata = CoreTxMetadata<Self>;
943}
944
945impl RngContext for FakeBindingsCtx {
946 type Rng<'a> = FakeCryptoRng;
947
948 fn rng(&mut self) -> Self::Rng<'_> {
949 let Self(this) = self;
950 this.lock().rng()
951 }
952}
953
954impl<T: Into<DispatchedEvent>> EventContext<T> for FakeBindingsCtx {
955 fn on_event(&mut self, event: T) {
956 self.with_inner_mut(|ctx| ctx.events.on_event(event.into()))
957 }
958}
959
960impl TcpBindingsTypes for FakeBindingsCtx {
961 type ReceiveBuffer = Arc<Mutex<RingBuffer>>;
962
963 type SendBuffer = TestSendBuffer;
964
965 type ReturnedBuffers = ClientBuffers;
966
967 type ListenerNotifierOrProvidedBuffers = ProvidedBuffers;
968
969 fn new_passive_open_buffers(
970 buffer_sizes: BufferSizes,
971 ) -> (Self::ReceiveBuffer, Self::SendBuffer, Self::ReturnedBuffers) {
972 let client = ClientBuffers::new(buffer_sizes);
973 (
974 Arc::clone(&client.receive),
975 TestSendBuffer::new(Arc::clone(&client.send), RingBuffer::default()),
976 client,
977 )
978 }
979}
980
981impl IpRoutingBindingsTypes for FakeBindingsCtx {
982 type RoutingTableId = ();
983}
984
985impl MarksBindingsContext for FakeBindingsCtx {
986 fn marks_to_keep_on_egress() -> &'static [MarkDomain] {
987 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark1];
988 &MARKS
989 }
990
991 fn marks_to_set_on_ingress() -> &'static [MarkDomain] {
992 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark2];
993 &MARKS
994 }
995}
996
997#[cfg(not(loom))]
998mod fake_notifiers {
999
1000 use super::*;
1001
1002 impl ReferenceNotifiers for FakeBindingsCtx {
1003 type ReferenceReceiver<T: 'static> = !;
1004
1005 type ReferenceNotifier<T: Send + 'static> = !;
1006
1007 fn new_reference_notifier<T: Send + 'static>(
1008 debug_references: DynDebugReferences,
1009 ) -> (Self::ReferenceNotifier<T>, Self::ReferenceReceiver<T>) {
1010 panic!(
1014 "FakeBindingsCtx can't create deferred reference notifiers for type {}: \
1015 debug_references={debug_references:?}",
1016 core::any::type_name::<T>()
1017 );
1018 }
1019 }
1020
1021 impl DeferredResourceRemovalContext for FakeBindingsCtx {
1022 fn defer_removal<T: Send + 'static>(&mut self, receiver: Self::ReferenceReceiver<T>) {
1023 match receiver {}
1024 }
1025 }
1026}
1027
1028#[cfg(loom)]
1031mod loom_notifiers {
1032 use super::*;
1033
1034 use core::sync::atomic::{self, AtomicBool};
1035 use netstack3_sync::rc::Notifier;
1036
1037 #[derive(Debug)]
1038 pub struct LoomNotifier(Arc<AtomicBool>);
1039
1040 #[derive(Debug)]
1041 pub struct LoomReceiver {
1042 pub debug_refs: DynDebugReferences,
1043 pub signal: Arc<AtomicBool>,
1044 }
1045
1046 impl LoomReceiver {
1047 #[track_caller]
1048 pub fn assert_signalled(&self) {
1049 let Self { debug_refs, signal } = self;
1050 assert!(signal.load(atomic::Ordering::SeqCst), "pending references: {debug_refs:?}")
1051 }
1052 }
1053
1054 impl<T> Notifier<T> for LoomNotifier {
1055 fn notify(&mut self, _data: T) {
1056 let Self(signal) = self;
1057 signal.store(true, atomic::Ordering::SeqCst);
1058 }
1059 }
1060
1061 impl ReferenceNotifiers for FakeBindingsCtx {
1062 type ReferenceReceiver<T: 'static> = LoomReceiver;
1063 type ReferenceNotifier<T: Send + 'static> = LoomNotifier;
1064
1065 fn new_reference_notifier<T: Send + 'static>(
1066 debug_refs: DynDebugReferences,
1067 ) -> (Self::ReferenceNotifier<T>, Self::ReferenceReceiver<T>) {
1068 let signal = Arc::new(AtomicBool::default());
1069 (LoomNotifier(Arc::clone(&signal)), LoomReceiver { debug_refs, signal })
1070 }
1071 }
1072
1073 impl DeferredResourceRemovalContext for FakeBindingsCtx {
1074 fn defer_removal<T: Send + 'static>(&mut self, receiver: Self::ReferenceReceiver<T>) {
1075 self.state_mut().deferred_receivers.push(receiver);
1076 }
1077 }
1078}
1079
1080#[derive(Debug)]
1082pub struct NoOpLinkResolutionNotifier;
1083
1084impl<D: LinkDevice> LinkResolutionContext<D> for FakeBindingsCtx {
1085 type Notifier = NoOpLinkResolutionNotifier;
1086}
1087
1088impl<D: LinkDevice> LinkResolutionNotifier<D> for NoOpLinkResolutionNotifier {
1089 type Observer = ();
1090
1091 fn new() -> (Self, Self::Observer) {
1092 (NoOpLinkResolutionNotifier, ())
1093 }
1094
1095 fn notify(self, _result: Result<UnicastAddr<D::Address>, AddressResolutionFailed>) {}
1096}
1097
1098#[derive(Clone)]
1099struct DeviceConfig {
1100 mac: UnicastAddr<Mac>,
1101 addr_subnet: Option<AddrSubnetEither>,
1102 ipv4_config: Option<Ipv4DeviceConfigurationUpdate>,
1103 ipv6_config: Option<Ipv6DeviceConfigurationUpdate>,
1104}
1105
1106#[derive(Clone, Default)]
1113pub struct FakeCtxBuilder {
1114 devices: Vec<DeviceConfig>,
1115 arp_table_entries: Vec<(usize, SpecifiedAddr<Ipv4Addr>, UnicastAddr<Mac>)>,
1117 ndp_table_entries: Vec<(usize, UnicastAddr<Ipv6Addr>, UnicastAddr<Mac>)>,
1118 device_routes: Vec<(SubnetEither, usize)>,
1120}
1121
1122impl FakeCtxBuilder {
1123 pub fn with_addrs<A: IpAddress>(addrs: TestAddrs<A>) -> FakeCtxBuilder {
1125 assert!(addrs.subnet.contains(&addrs.local_ip));
1126 assert!(addrs.subnet.contains(&addrs.remote_ip));
1127
1128 let mut builder = FakeCtxBuilder::default();
1129 builder.devices.push(DeviceConfig {
1130 mac: addrs.local_mac,
1131 addr_subnet: Some(
1132 AddrSubnetEither::new(addrs.local_ip.get().into(), addrs.subnet.prefix()).unwrap(),
1133 ),
1134 ipv4_config: None,
1135 ipv6_config: None,
1136 });
1137
1138 match addrs.remote_ip.into() {
1139 IpAddr::V4(ip) => builder.arp_table_entries.push((0, ip, addrs.remote_mac)),
1140 IpAddr::V6(ip) => builder.ndp_table_entries.push((
1141 0,
1142 UnicastAddr::new(ip.get()).unwrap(),
1143 addrs.remote_mac,
1144 )),
1145 };
1146
1147 builder.ndp_table_entries.push((
1150 0,
1151 addrs.remote_mac.to_ipv6_link_local().addr().get(),
1152 addrs.remote_mac,
1153 ));
1154
1155 builder.device_routes.push((addrs.subnet.into(), 0));
1156 builder
1157 }
1158
1159 pub fn add_device(&mut self, mac: UnicastAddr<Mac>) -> usize {
1164 let idx = self.devices.len();
1165 self.devices.push(DeviceConfig {
1166 mac,
1167 addr_subnet: None,
1168 ipv4_config: None,
1169 ipv6_config: None,
1170 });
1171 idx
1172 }
1173
1174 pub fn add_device_with_config(
1179 &mut self,
1180 mac: UnicastAddr<Mac>,
1181 ipv4_config: Ipv4DeviceConfigurationUpdate,
1182 ipv6_config: Ipv6DeviceConfigurationUpdate,
1183 ) -> usize {
1184 let idx = self.devices.len();
1185 self.devices.push(DeviceConfig {
1186 mac,
1187 addr_subnet: None,
1188 ipv4_config: Some(ipv4_config),
1189 ipv6_config: Some(ipv6_config),
1190 });
1191 idx
1192 }
1193
1194 pub fn add_device_with_ip<A: IpAddress>(
1199 &mut self,
1200 mac: UnicastAddr<Mac>,
1201 ip: A,
1202 subnet: Subnet<A>,
1203 ) -> usize {
1204 assert!(subnet.contains(&ip));
1205 let idx = self.devices.len();
1206 self.devices.push(DeviceConfig {
1207 mac,
1208 addr_subnet: Some(AddrSubnetEither::new(ip.into(), subnet.prefix()).unwrap()),
1209 ipv4_config: None,
1210 ipv6_config: None,
1211 });
1212 self.device_routes.push((subnet.into(), idx));
1213 idx
1214 }
1215
1216 pub fn add_device_with_ip_and_config<A: IpAddress>(
1224 &mut self,
1225 mac: UnicastAddr<Mac>,
1226 ip: A,
1227 subnet: Subnet<A>,
1228 ipv4_config: Ipv4DeviceConfigurationUpdate,
1229 ipv6_config: Ipv6DeviceConfigurationUpdate,
1230 ) -> usize {
1231 assert!(subnet.contains(&ip));
1232 let idx = self.devices.len();
1233 self.devices.push(DeviceConfig {
1234 mac,
1235 addr_subnet: Some(AddrSubnetEither::new(ip.into(), subnet.prefix()).unwrap()),
1236 ipv4_config: Some(ipv4_config),
1237 ipv6_config: Some(ipv6_config),
1238 });
1239 self.device_routes.push((subnet.into(), idx));
1240 idx
1241 }
1242
1243 pub fn add_arp_table_entry(
1245 &mut self,
1246 device: usize,
1247 ip: SpecifiedAddr<Ipv4Addr>,
1249 mac: UnicastAddr<Mac>,
1250 ) {
1251 self.arp_table_entries.push((device, ip, mac));
1252 }
1253
1254 pub fn add_ndp_table_entry(
1256 &mut self,
1257 device: usize,
1258 ip: UnicastAddr<Ipv6Addr>,
1260 mac: UnicastAddr<Mac>,
1261 ) {
1262 self.ndp_table_entries.push((device, ip, mac));
1263 }
1264
1265 pub fn add_arp_or_ndp_table_entry<A: IpAddress>(
1268 &mut self,
1269 device: usize,
1270 ip: SpecifiedAddr<A>,
1272 mac: UnicastAddr<Mac>,
1273 ) {
1274 match ip.into() {
1275 IpAddr::V4(ip) => self.add_arp_table_entry(device, ip, mac),
1276 IpAddr::V6(ip) => {
1277 self.add_ndp_table_entry(device, UnicastAddr::new(ip.get()).unwrap(), mac)
1278 }
1279 }
1280 }
1281
1282 pub fn build(self) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1284 self.build_with_modifications(|_| {})
1285 }
1286
1287 pub fn build_with_modifications<F: FnOnce(&mut StackStateBuilder)>(
1291 self,
1292 f: F,
1293 ) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1294 let mut stack_builder = StackStateBuilder::default();
1295 f(&mut stack_builder);
1296 self.build_with(stack_builder)
1297 }
1298
1299 pub fn build_with(
1302 self,
1303 state_builder: StackStateBuilder,
1304 ) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1305 let mut ctx = Ctx::new_with_builder(state_builder);
1306
1307 let FakeCtxBuilder { devices, arp_table_entries, ndp_table_entries, device_routes } = self;
1308 let idx_to_device_id: Vec<_> = devices
1309 .into_iter()
1310 .map(|DeviceConfig { mac, addr_subnet: ip_and_subnet, ipv4_config, ipv6_config }| {
1311 let eth_id =
1312 ctx.core_api().device::<EthernetLinkDevice>().add_device_with_default_state(
1313 EthernetCreationProperties {
1314 mac: mac,
1315 max_frame_size: IPV6_MIN_IMPLIED_MAX_FRAME_SIZE,
1316 tx_offload_spec: Default::default(),
1317 },
1318 DEFAULT_INTERFACE_METRIC,
1319 );
1320 let id = eth_id.clone().into();
1321 if let Some(ipv4_config) = ipv4_config {
1322 let _previous = ctx
1323 .core_api()
1324 .device_ip::<Ipv4>()
1325 .update_configuration(&id, ipv4_config)
1326 .unwrap();
1327 }
1328 if let Some(ipv6_config) = ipv6_config {
1329 let _previous = ctx
1330 .core_api()
1331 .device_ip::<Ipv6>()
1332 .update_configuration(&id, ipv6_config)
1333 .unwrap();
1334 }
1335 ctx.test_api().enable_device(&id);
1336 match ip_and_subnet {
1337 Some(addr_sub) => {
1338 ctx.core_api().device_ip_any().add_ip_addr_subnet(&id, addr_sub).unwrap();
1339 }
1340 None => {}
1341 }
1342 eth_id
1343 })
1344 .collect();
1345 for (idx, ip, mac) in arp_table_entries {
1346 let device = &idx_to_device_id[idx];
1347 ctx.core_api()
1348 .neighbor::<Ipv4, EthernetLinkDevice>()
1349 .insert_static_entry(&device, ip.get(), mac)
1350 .expect("error inserting static ARP entry");
1351 }
1352 for (idx, ip, mac) in ndp_table_entries {
1353 let device = &idx_to_device_id[idx];
1354 ctx.core_api()
1355 .neighbor::<Ipv6, EthernetLinkDevice>()
1356 .insert_static_entry(&device, ip.get(), mac)
1357 .expect("error inserting static NDP entry");
1358 }
1359
1360 for (subnet, idx) in device_routes {
1361 let device = &idx_to_device_id[idx];
1362 ctx.test_api()
1363 .add_route(AddableEntryEither::without_gateway(
1364 subnet,
1365 device.clone().into(),
1366 AddableMetric::ExplicitMetric(RawMetric(0)),
1367 ))
1368 .expect("add device route");
1369 }
1370
1371 (ctx, idx_to_device_id)
1372 }
1373}
1374
1375pub enum FakeCtxNetworkSpec {}
1379
1380impl FakeNetworkSpec for FakeCtxNetworkSpec {
1381 type Context = FakeCtx;
1382 type TimerId = TimerId<FakeBindingsCtx>;
1383 type SendMeta = DispatchedFrame;
1384 type RecvMeta = EthernetDeviceId<FakeBindingsCtx>;
1385 fn handle_frame(ctx: &mut FakeCtx, device_id: Self::RecvMeta, data: Buf<Vec<u8>>) {
1386 ctx.core_api().device::<EthernetLinkDevice>().receive_frame(
1387 RecvEthernetFrameMeta {
1388 device_id,
1389 parsing_context: NetworkParsingContext::default(),
1390 gso_info: None,
1391 },
1392 data,
1393 )
1394 }
1395 fn handle_timer(ctx: &mut FakeCtx, dispatch: Self::TimerId, timer: FakeTimerId) {
1396 ctx.core_api().handle_timer(dispatch, timer)
1397 }
1398 fn process_queues(ctx: &mut FakeCtx) -> bool {
1399 ctx.test_api().handle_queued_rx_packets()
1400 }
1401 fn fake_frames(ctx: &mut FakeCtx) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
1402 &mut ctx.bindings_ctx
1403 }
1404}
1405
1406impl<I: IpExt> UdpReceiveBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1407 fn receive_udp(
1408 &mut self,
1409 id: &UdpSocketId<I, WeakDeviceId<Self>, FakeBindingsCtx>,
1410 _device_id: &DeviceId<Self>,
1411 _meta: UdpPacketMeta<I>,
1412 body: &[u8],
1413 ) -> Result<(), ReceiveUdpError> {
1414 let mut state = self.state_mut();
1415 let received =
1416 (&mut *state).udp_state_mut::<I>().entry(id.clone()).or_insert_with(Vec::default);
1417 received.push(body.to_owned());
1418 Ok(())
1419 }
1420
1421 fn on_socket_error(
1422 &mut self,
1423 _id: &UdpSocketId<I, WeakDeviceId<Self>, FakeBindingsCtx>,
1424 _err: PendingDatagramSocketError,
1425 ) {
1426 }
1427}
1428
1429impl UdpBindingsTypes for FakeBindingsCtx {
1430 type ExternalData<I: Ip> = ();
1431 type SendToken = FakeSendToken;
1432}
1433
1434impl<I: IpExt> IcmpEchoBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1435 fn receive_icmp_echo_reply<B: BufferMut>(
1436 &mut self,
1437 conn: &IcmpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
1438 _device: &DeviceId<Self>,
1439 _src_ip: I::Addr,
1440 _dst_ip: I::Addr,
1441 _id: u16,
1442 data: B,
1443 ) -> Result<(), ReceiveIcmpEchoError> {
1444 I::map_ip_in(
1445 (IpInvariant(self.state_mut()), conn.clone()),
1446 |(IpInvariant(mut state), conn)| {
1447 let replies = state.icmpv4_replies.entry(conn).or_insert_with(Vec::default);
1448 replies.push(data.as_ref().to_owned());
1449 },
1450 |(IpInvariant(mut state), conn)| {
1451 let replies = state.icmpv6_replies.entry(conn).or_insert_with(Vec::default);
1452 replies.push(data.as_ref().to_owned());
1453 },
1454 );
1455 Ok(())
1456 }
1457}
1458
1459impl IcmpEchoBindingsTypes for FakeBindingsCtx {
1460 type ExternalData<I: Ip> = ();
1461 type SendToken = FakeSendToken;
1462}
1463
1464impl DeviceSocketTypes for FakeBindingsCtx {
1465 type SocketState<D: Send + Sync + Debug> = Mutex<Vec<(WeakDeviceId<FakeBindingsCtx>, Vec<u8>)>>;
1466}
1467
1468impl RawIpSocketsBindingsTypes for FakeBindingsCtx {
1469 type RawIpSocketState<I: Ip> = ();
1470}
1471
1472impl DeviceSocketBindingsContext<DeviceId<Self>> for FakeBindingsCtx {
1473 fn receive_frame(
1474 &self,
1475 socket_id: &SocketId<Self>,
1476 device: &DeviceId<Self>,
1477 _frame: device::socket::Frame<&[u8]>,
1478 raw_frame: &[u8],
1479 ) -> Result<(), ReceiveFrameError> {
1480 let state = socket_id.socket_state();
1481 state.lock().push((device.downgrade(), raw_frame.into()));
1482 Ok(())
1483 }
1484}
1485
1486impl<I: IpExt> RawIpSocketsBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1487 fn receive_packet<B: SplitByteSlice>(
1488 &self,
1489 _socket: &RawIpSocketId<I, WeakDeviceId<Self>, Self>,
1490 _packet: &I::Packet<B>,
1491 _device: &DeviceId<Self>,
1492 ) -> Result<(), ReceivePacketError> {
1493 unimplemented!()
1494 }
1495}
1496
1497impl DeviceLayerStateTypes for FakeBindingsCtx {
1498 type LoopbackDeviceState = ();
1499 type EthernetDeviceState = ();
1500 type BlackholeDeviceState = ();
1501 type PureIpDeviceState = ();
1502 type DeviceIdentifier = MonotonicIdentifier;
1503}
1504
1505impl ReceiveQueueBindingsContext<LoopbackDeviceId<Self>> for FakeBindingsCtx {
1506 fn wake_rx_task(&mut self, device: &LoopbackDeviceId<FakeBindingsCtx>) {
1507 self.state_mut().rx_available.push(device.clone());
1508 }
1509}
1510
1511impl<D: Clone + Into<DeviceId<Self>>> TransmitQueueBindingsContext<D> for FakeBindingsCtx {
1512 fn wake_tx_task(&mut self, device: &D) {
1513 self.state_mut().tx_available.push(device.clone().into());
1514 }
1515}
1516
1517impl DeviceLayerEventDispatcher for FakeBindingsCtx {
1518 type DequeueContext = ();
1519
1520 fn send_ethernet_frame(
1521 &mut self,
1522 device: &EthernetDeviceId<FakeBindingsCtx>,
1523 frame: Buf<Vec<u8>>,
1524 _dequeue_context: Option<&mut Self::DequeueContext>,
1525 _csum_offload: Option<netstack3_base::ChecksumOffloadResult>,
1526 ) -> Result<(), DeviceSendFrameError> {
1527 let frame_meta = DispatchedFrame::Ethernet(device.downgrade());
1528 self.with_inner_mut(|ctx| ctx.frames.push(frame_meta, frame.into_inner()));
1529 Ok(())
1530 }
1531
1532 fn send_ip_packet(
1533 &mut self,
1534 device: &PureIpDeviceId<FakeBindingsCtx>,
1535 packet: Buf<Vec<u8>>,
1536 ip_version: IpVersion,
1537 _dequeue_context: Option<&mut Self::DequeueContext>,
1538 _csum_offload: Option<netstack3_base::ChecksumOffloadResult>,
1539 ) -> Result<(), DeviceSendFrameError> {
1540 let frame_meta = DispatchedFrame::PureIp(PureIpDeviceAndIpVersion {
1541 device: device.downgrade(),
1542 version: ip_version,
1543 });
1544 self.with_inner_mut(|ctx| ctx.frames.push(frame_meta, packet.into_inner()));
1545 Ok(())
1546 }
1547}
1548
1549impl AlwaysDefaultsSettingsContext for FakeBindingsCtx {}
1550
1551#[derive(Debug, Eq, PartialEq, Hash, GenericOverIp)]
1553#[generic_over_ip()]
1554#[allow(missing_docs)]
1555pub enum DispatchedEvent {
1556 IpDeviceIpv4(IpDeviceEvent<WeakDeviceId<FakeBindingsCtx>, Ipv4, FakeInstant>),
1557 IpDeviceIpv6(IpDeviceEvent<WeakDeviceId<FakeBindingsCtx>, Ipv6, FakeInstant>),
1558 IpLayerIpv4(IpLayerEvent<WeakDeviceId<FakeBindingsCtx>, Ipv4>),
1559 IpLayerIpv6(IpLayerEvent<WeakDeviceId<FakeBindingsCtx>, Ipv6>),
1560 NeighborIpv4(nud::Event<Mac, EthernetWeakDeviceId<FakeBindingsCtx>, Ipv4, FakeInstant>),
1561 NeighborIpv6(nud::Event<Mac, EthernetWeakDeviceId<FakeBindingsCtx>, Ipv6, FakeInstant>),
1562 RouterAdvertisement(RouterAdvertisementEvent<WeakDeviceId<FakeBindingsCtx>>),
1563 EthernetDevice(EthernetDeviceEvent<EthernetWeakDeviceId<FakeBindingsCtx>>),
1564}
1565
1566#[derive(Derivative)]
1568#[derivative(Debug(bound = ""))]
1569#[allow(missing_docs)]
1570pub struct PureIpDeviceAndIpVersion<BT: DeviceLayerTypes> {
1571 pub device: PureIpWeakDeviceId<BT>,
1572 pub version: IpVersion,
1573}
1574
1575#[derive(Debug)]
1577pub enum DispatchedFrame {
1578 Ethernet(EthernetWeakDeviceId<FakeBindingsCtx>),
1580 PureIp(PureIpDeviceAndIpVersion<FakeBindingsCtx>),
1582}
1583
1584impl<I: Ip> From<IpDeviceEvent<DeviceId<FakeBindingsCtx>, I, FakeInstant>> for DispatchedEvent {
1585 fn from(e: IpDeviceEvent<DeviceId<FakeBindingsCtx>, I, FakeInstant>) -> DispatchedEvent {
1586 let e = e.map_device(|d| d.downgrade());
1587 I::map_ip(e, |e| DispatchedEvent::IpDeviceIpv4(e), |e| DispatchedEvent::IpDeviceIpv6(e))
1588 }
1589}
1590
1591impl<I: IpExt> From<IpLayerEvent<DeviceId<FakeBindingsCtx>, I>> for DispatchedEvent {
1592 fn from(e: IpLayerEvent<DeviceId<FakeBindingsCtx>, I>) -> DispatchedEvent {
1593 let e = e.map_device(|d| d.downgrade());
1594 I::map_ip(e, |e| DispatchedEvent::IpLayerIpv4(e), |e| DispatchedEvent::IpLayerIpv6(e))
1595 }
1596}
1597
1598impl<I: Ip> From<nud::Event<Mac, EthernetDeviceId<FakeBindingsCtx>, I, FakeInstant>>
1599 for DispatchedEvent
1600{
1601 fn from(
1602 e: nud::Event<Mac, EthernetDeviceId<FakeBindingsCtx>, I, FakeInstant>,
1603 ) -> DispatchedEvent {
1604 let e = e.map_device(|d| d.downgrade());
1605 I::map_ip(e, |e| DispatchedEvent::NeighborIpv4(e), |e| DispatchedEvent::NeighborIpv6(e))
1606 }
1607}
1608
1609impl From<EthernetDeviceEvent<EthernetDeviceId<FakeBindingsCtx>>> for DispatchedEvent {
1610 fn from(e: EthernetDeviceEvent<EthernetDeviceId<FakeBindingsCtx>>) -> DispatchedEvent {
1611 let e = e.map_device(|d| d.downgrade());
1612 DispatchedEvent::EthernetDevice(e)
1613 }
1614}
1615
1616impl From<RouterAdvertisementEvent<DeviceId<FakeBindingsCtx>>> for DispatchedEvent {
1617 fn from(e: RouterAdvertisementEvent<DeviceId<FakeBindingsCtx>>) -> DispatchedEvent {
1618 let e = e.map_device(|d| d.downgrade());
1619 DispatchedEvent::RouterAdvertisement(e)
1620 }
1621}
1622
1623impl TcpSocketDestructionContext for FakeBindingsCtx {
1624 fn defer_tcp_socket_destruction<I, S>(&self, _result: RemoveResourceResultWithContext<S, Self>)
1625 where
1626 I: Ip,
1627 S: SocketDiagnosticsSeed<Output = TcpSocketDiagnostics<I, Self::Instant>> + Send + 'static,
1628 {
1629 }
1631}
1632
1633pub fn new_simple_fake_network<CtxId: Copy + Debug + Hash + Eq>(
1639 a_id: CtxId,
1640 a: FakeCtx,
1641 a_device_id: EthernetWeakDeviceId<FakeBindingsCtx>,
1642 b_id: CtxId,
1643 b: FakeCtx,
1644 b_device_id: EthernetWeakDeviceId<FakeBindingsCtx>,
1645) -> FakeNetwork<
1646 FakeCtxNetworkSpec,
1647 CtxId,
1648 impl FakeNetworkLinks<DispatchedFrame, EthernetDeviceId<FakeBindingsCtx>, CtxId>,
1649> {
1650 let contexts = vec![(a_id, a), (b_id, b)].into_iter();
1651 FakeNetwork::new(contexts, move |net, _frame: DispatchedFrame| {
1652 if net == a_id {
1653 b_device_id
1654 .upgrade()
1655 .map(|device_id| (b_id, device_id, None))
1656 .into_iter()
1657 .collect::<Vec<_>>()
1658 } else {
1659 a_device_id
1660 .upgrade()
1661 .map(|device_id| (a_id, device_id, None))
1662 .into_iter()
1663 .collect::<Vec<_>>()
1664 }
1665 })
1666}