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;
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, PacketType,
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 let packet_type = frame_dst.map(PacketType::from).unwrap_or(PacketType::Host);
332 let metadata = DeviceIpLayerMetadata::with_marks_and_packet_type(marks, packet_type);
333 match I::VERSION {
334 IpVersion::V4 => ip::receive_ipv4_packet(
335 core_ctx,
336 bindings_ctx,
337 device,
338 frame_dst,
339 metadata,
340 parsing_context,
341 None,
342 buffer,
343 ),
344 IpVersion::V6 => ip::receive_ipv6_packet(
345 core_ctx,
346 bindings_ctx,
347 device,
348 frame_dst,
349 metadata,
350 parsing_context,
351 None,
352 buffer,
353 ),
354 }
355 }
356
357 pub fn receive_ethernet_frame<B: BufferMut + Debug>(
359 &mut self,
360 device: &EthernetDeviceId<BC>,
361 buffer: B,
362 ) {
363 self.core_api().device::<EthernetLinkDevice>().receive_frame(
364 RecvEthernetFrameMeta {
365 device_id: device.clone(),
366 parsing_context: NetworkParsingContext::default(),
367 gso_info: None,
368 },
369 buffer,
370 );
371 }
372
373 pub fn add_route(
375 &mut self,
376 entry: AddableEntryEither<DeviceId<BC>>,
377 ) -> Result<(), AddRouteError> {
378 let (core_ctx, _bindings_ctx) = self.contexts();
379 match entry {
380 AddableEntryEither::V4(entry) => ip::testutil::add_route::<Ipv4, _, _>(core_ctx, entry),
381 AddableEntryEither::V6(entry) => ip::testutil::add_route::<Ipv6, _, _>(core_ctx, entry),
382 }
383 }
384
385 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
387 pub fn set_rules<I: IpExt>(&mut self, rules: Vec<netstack3_ip::Rule<I, DeviceId<BC>, BC>>) {
388 let (core_ctx, _bindings_ctx) = self.contexts();
389 ip::testutil::set_rules(core_ctx, rules)
390 }
391
392 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
394 pub fn resolve_route_with_src_addr<I: IpExt>(
395 &mut self,
396 src_ip: IpDeviceAddr<I::Addr>,
397 dst_ip: Option<RoutableIpAddr<I::Addr>>,
398 ) -> Result<ResolvedRoute<I, DeviceId<BC>>, ResolveRouteError> {
399 let (core_ctx, _bindings_ctx) = self.contexts();
400 ip::resolve_output_route_to_destination(
401 core_ctx,
402 None,
403 Some((src_ip, ip::NonLocalSrcAddrPolicy::Deny)),
404 dst_ip,
405 &Default::default(),
406 )
407 }
408
409 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
411 pub fn resolve_route_with_marks<I: IpExt>(
412 &mut self,
413 dst_ip: Option<RoutableIpAddr<I::Addr>>,
414 marks: &Marks,
415 ) -> Result<ResolvedRoute<I, DeviceId<BC>>, ResolveRouteError> {
416 let (core_ctx, _bindings_ctx) = self.contexts();
417 ip::resolve_output_route_to_destination(core_ctx, None, None, dst_ip, marks)
418 }
419
420 pub fn del_routes_to_subnet(
423 &mut self,
424 subnet: net_types::ip::SubnetEither,
425 ) -> Result<(), NotFoundError> {
426 let (core_ctx, _bindings_ctx) = self.contexts();
427 match subnet {
428 SubnetEither::V4(subnet) => {
429 ip::testutil::del_routes_to_subnet::<Ipv4, _, _>(core_ctx, subnet)
430 }
431 SubnetEither::V6(subnet) => {
432 ip::testutil::del_routes_to_subnet::<Ipv6, _, _>(core_ctx, subnet)
433 }
434 }
435 }
436
437 pub fn del_device_routes(&mut self, device: &DeviceId<BC>) {
439 let (core_ctx, _bindings_ctx) = self.contexts();
440 ip::testutil::del_device_routes::<Ipv4, _, _>(core_ctx, device);
441 ip::testutil::del_device_routes::<Ipv6, _, _>(core_ctx, device);
442 }
443
444 pub fn clear_routes_and_remove_device<D: Into<DeviceId<BC>>>(&mut self, device: D) {
446 let device = device.into();
447 self.del_device_routes(&device);
448
449 for_any_device_id!(DeviceId, DeviceProvider, D, device,
450 device => match self.core_api().device::<D>().remove_device(device) {
451 RemoveResourceResult::Removed(_external_state) => {}
452 RemoveResourceResult::Deferred(_reference_receiver) => {
453 panic!("failed to remove device")
454 }
455 });
456 }
457
458 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
461 pub fn set_ip_device_enabled<I: IpExt>(
462 &mut self,
463 device: &DeviceId<BC>,
464 enabled: bool,
465 ) -> bool {
466 let update =
467 IpDeviceConfigurationUpdate { ip_enabled: Some(enabled), ..Default::default() };
468 let prev =
469 self.core_api().device_ip::<I>().update_configuration(device, update.into()).unwrap();
470 prev.as_ref().ip_enabled.unwrap()
471 }
472
473 pub fn enable_device(&mut self, device: &DeviceId<BC>) {
475 let _was_enabled: bool = self.set_ip_device_enabled::<Ipv4>(device, true);
476 let _was_enabled: bool = self.set_ip_device_enabled::<Ipv6>(device, true);
477 }
478
479 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
481 pub fn set_unicast_forwarding_enabled<I: IpExt>(
482 &mut self,
483 device: &DeviceId<BC>,
484 enabled: bool,
485 ) {
486 let _config = self
487 .core_api()
488 .device_ip::<I>()
489 .update_configuration(
490 device,
491 IpDeviceConfigurationUpdate {
492 unicast_forwarding_enabled: Some(enabled),
493 ..Default::default()
494 }
495 .into(),
496 )
497 .unwrap();
498 }
499
500 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
502 pub fn set_multicast_forwarding_enabled<I: IpExt>(
503 &mut self,
504 device: &DeviceId<BC>,
505 enabled: bool,
506 ) {
507 let _config = self
508 .core_api()
509 .device_ip::<I>()
510 .update_configuration(
511 device,
512 IpDeviceConfigurationUpdate {
513 multicast_forwarding_enabled: Some(enabled),
514 ..Default::default()
515 }
516 .into(),
517 )
518 .unwrap();
519 }
520
521 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
523 pub fn is_unicast_forwarding_enabled<I: IpExt>(&mut self, device: &DeviceId<BC>) -> bool {
524 let configuration = self.core_api().device_ip::<I>().get_configuration(device);
525 let IpDeviceConfiguration { unicast_forwarding_enabled, .. } = configuration.as_ref();
526 *unicast_forwarding_enabled
527 }
528
529 pub fn add_loopback(&mut self) -> LoopbackDeviceId<BC>
531 where
532 <BC as DeviceLayerStateTypes>::DeviceIdentifier: Default,
533 <BC as DeviceLayerStateTypes>::LoopbackDeviceState: Default,
534 {
535 let loopback_id = self.core_api().device::<LoopbackDevice>().add_device_with_default_state(
536 LoopbackCreationProperties { mtu: Mtu::new(u32::MAX) },
537 DEFAULT_INTERFACE_METRIC,
538 );
539 let device_id: DeviceId<_> = loopback_id.clone().into();
540 self.enable_device(&device_id);
541
542 self.core_api()
543 .device_ip::<Ipv4>()
544 .add_ip_addr_subnet(
545 &device_id,
546 AddrSubnet::from_witness(Ipv4::LOOPBACK_ADDRESS, Ipv4::LOOPBACK_SUBNET.prefix())
547 .unwrap(),
548 )
549 .unwrap();
550
551 self.core_api()
552 .device_ip::<Ipv6>()
553 .add_ip_addr_subnet(
554 &device_id,
555 AddrSubnet::from_witness(Ipv6::LOOPBACK_ADDRESS, Ipv6::LOOPBACK_SUBNET.prefix())
556 .unwrap(),
557 )
558 .unwrap();
559 loopback_id
560 }
561}
562
563impl<'a> TestApi<'a, FakeBindingsCtx> {
564 pub fn handle_queued_rx_packets(&mut self) -> bool {
567 let mut handled = false;
568 loop {
569 let (_, bindings_ctx) = self.contexts();
570 let rx_available = core::mem::take(&mut bindings_ctx.state_mut().rx_available);
571 if rx_available.len() == 0 {
572 break handled;
573 }
574 handled = true;
575 for id in rx_available.into_iter() {
576 loop {
577 match self.core_api().receive_queue().handle_queued_frames(&id) {
578 WorkQueueReport::AllDone => break,
579 WorkQueueReport::Pending => (),
580 }
581 }
582 }
583 }
584 }
585}
586
587#[derive(Default)]
588pub struct FakeBindingsCtxState {
590 icmpv4_replies:
591 HashMap<IcmpSocketId<Ipv4, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
592 icmpv6_replies:
593 HashMap<IcmpSocketId<Ipv6, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
594 udpv4_received:
595 HashMap<UdpSocketId<Ipv4, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
596 udpv6_received:
597 HashMap<UdpSocketId<Ipv6, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
598 pub rx_available: Vec<LoopbackDeviceId<FakeBindingsCtx>>,
600 pub tx_available: Vec<DeviceId<FakeBindingsCtx>>,
602 pub packet_metadata: Vec<(
605 netstack3_base::socket::SocketInfo,
606 Marks,
607 PacketType,
608 Option<netstack3_base::GsoInfo>,
609 )>,
610 #[cfg(loom)]
612 pub deferred_receivers: Vec<loom_notifiers::LoomReceiver>,
613}
614
615impl FakeBindingsCtxState {
616 pub(crate) fn udp_state_mut<I: IpExt>(
617 &mut self,
618 ) -> &mut HashMap<UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>
619 {
620 #[derive(GenericOverIp)]
621 #[generic_over_ip(I, Ip)]
622 struct Wrapper<'a, I: IpExt>(
623 &'a mut HashMap<
624 UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
625 Vec<Vec<u8>>,
626 >,
627 );
628 let Wrapper(map) = I::map_ip_out::<_, Wrapper<'_, I>>(
629 self,
630 |this| Wrapper(&mut this.udpv4_received),
631 |this| Wrapper(&mut this.udpv6_received),
632 );
633 map
634 }
635}
636
637pub type FakeCtx = Ctx<FakeBindingsCtx>;
639pub type FakeCoreCtx = StackState<FakeBindingsCtx>;
641
642type InnerFakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<
643 TimerId<FakeBindingsCtx>,
644 DispatchedEvent,
645 FakeBindingsCtxState,
646 DispatchedFrame,
647>;
648
649type Mutex<T> = netstack3_base::sync::Mutex<T, netstack3_base::sync::lock_impl::RawMutex>;
650
651#[derive(Default, Clone)]
653pub struct FakeBindingsCtx(Arc<Mutex<InnerFakeBindingsCtx>>);
654
655impl netstack3_base::BindingsSyncTypes for FakeBindingsCtx {
656 type Mutex = netstack3_base::sync::lock_impl::RawMutex;
657 type RwLock = netstack3_base::sync::lock_impl::RawRwLock;
658 type Once = netstack3_base::sync::lock_impl::Once;
659}
660
661struct Wrapper<S, Callback, CallbackMut>(S, Callback, CallbackMut);
671
672impl<T: ?Sized, S: Deref, Callback: for<'a> Fn(&'a <S as Deref>::Target) -> &'a T, CallbackMut>
673 Deref for Wrapper<S, Callback, CallbackMut>
674{
675 type Target = T;
676
677 fn deref(&self) -> &T {
678 let Self(guard, f, _) = self;
679 let target = guard.deref();
680 f(target)
681 }
682}
683
684impl<
685 T: ?Sized,
686 S: DerefMut,
687 Callback: for<'a> Fn(&'a <S as Deref>::Target) -> &'a T,
688 CallbackMut: for<'a> Fn(&'a mut <S as Deref>::Target) -> &'a mut T,
689> DerefMut for Wrapper<S, Callback, CallbackMut>
690{
691 fn deref_mut(&mut self) -> &mut T {
692 let Self(guard, _, f) = self;
693 let target = guard.deref_mut();
694 f(target)
695 }
696}
697
698impl FakeBindingsCtx {
699 fn with_inner<F: FnOnce(&InnerFakeBindingsCtx) -> O, O>(&self, f: F) -> O {
700 let Self(this) = self;
701 let locked = this.lock();
702 f(&*locked)
703 }
704
705 fn with_inner_mut<F: FnOnce(&mut InnerFakeBindingsCtx) -> O, O>(&self, f: F) -> O {
706 let Self(this) = self;
707 let mut locked = this.lock();
708 f(&mut *locked)
709 }
710
711 pub fn timer_ctx(&self) -> impl Deref<Target = FakeTimerCtx<TimerId<Self>>> + '_ {
713 fn get_timers<'a>(
716 i: &'a InnerFakeBindingsCtx,
717 ) -> &'a FakeTimerCtx<TimerId<FakeBindingsCtx>> {
718 &i.timers
719 }
720 Wrapper(self.0.lock(), get_timers, ())
721 }
722
723 pub fn state_mut(&mut self) -> impl DerefMut<Target = FakeBindingsCtxState> + '_ {
725 fn get_state<'a>(i: &'a InnerFakeBindingsCtx) -> &'a FakeBindingsCtxState {
728 &i.state
729 }
730 fn get_state_mut<'a>(i: &'a mut InnerFakeBindingsCtx) -> &'a mut FakeBindingsCtxState {
731 &mut i.state
732 }
733 Wrapper(self.0.lock(), get_state, get_state_mut)
734 }
735
736 pub fn copy_ethernet_frames(
742 &mut self,
743 ) -> Vec<(EthernetWeakDeviceId<FakeBindingsCtx>, Vec<u8>)> {
744 self.with_inner_mut(|ctx| {
745 ctx.frames
746 .frames()
747 .iter()
748 .map(|(meta, frame)| match meta {
749 DispatchedFrame::Ethernet(eth) => (eth.clone(), frame.clone()),
750 DispatchedFrame::PureIp(ip) => panic!("unexpected IP packet {ip:?}: {frame:?}"),
751 })
752 .collect()
753 })
754 }
755
756 pub fn take_ethernet_frames(
762 &mut self,
763 ) -> Vec<(EthernetWeakDeviceId<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) => (eth, frame),
770 DispatchedFrame::PureIp(ip) => panic!("unexpected IP packet {ip:?}: {frame:?}"),
771 })
772 .collect()
773 })
774 }
775
776 pub fn take_ip_frames(&mut self) -> Vec<(PureIpDeviceAndIpVersion<FakeBindingsCtx>, Vec<u8>)> {
782 self.with_inner_mut(|ctx| {
783 ctx.frames
784 .take_frames()
785 .into_iter()
786 .map(|(meta, frame)| match meta {
787 DispatchedFrame::Ethernet(eth) => {
788 panic!("unexpected Ethernet frame {eth:?}: {frame:?}")
789 }
790 DispatchedFrame::PureIp(ip) => (ip, frame),
791 })
792 .collect()
793 })
794 }
795
796 pub fn take_events(&mut self) -> Vec<DispatchedEvent> {
798 self.with_inner_mut(|ctx| ctx.events.take())
799 }
800
801 pub fn take_icmp_replies<I: IpExt>(
803 &mut self,
804 conn: &IcmpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
805 ) -> Vec<Vec<u8>> {
806 I::map_ip_in(
807 (IpInvariant(self), conn),
808 |(IpInvariant(this), conn)| this.state_mut().icmpv4_replies.remove(conn),
809 |(IpInvariant(this), conn)| this.state_mut().icmpv6_replies.remove(conn),
810 )
811 .unwrap_or_else(Vec::default)
812 }
813
814 pub fn take_udp_received<I: IpExt>(
816 &mut self,
817 conn: &UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
818 ) -> Vec<Vec<u8>> {
819 self.state_mut().udp_state_mut::<I>().remove(conn).unwrap_or_else(Vec::default)
820 }
821
822 pub fn seed_rng(&self, seed: u128) {
824 self.with_inner_mut(|ctx| {
825 ctx.rng = FakeCryptoRng::new_xorshift(seed);
826 })
827 }
828
829 pub fn sleep(&self, duration: Duration) {
831 self.with_inner_mut(|ctx| ctx.timers.instant.sleep(duration));
832 }
833}
834
835impl MatcherBindingsTypes for FakeBindingsCtx {
836 type DeviceClass = ();
837 type BindingsPacketMatcher = !;
838}
839
840impl DeviceBufferBindingsTypes for FakeBindingsCtx {
841 type TxBuffer = packet::Buf<Vec<u8>>;
842 type TxAllocator = netstack3_device::queue::BufVecU8Allocator;
843}
844
845struct FakeSocketOpsFilter<'a>(&'a FakeBindingsCtx);
846
847impl SocketOpsFilter<DeviceId<FakeBindingsCtx>> for FakeSocketOpsFilter<'_> {
848 fn on_egress<I: netstack3_filter::FilterIpExt, P: netstack3_filter::FilterIpPacket<I>>(
849 &self,
850 _packet: &P,
851 _device: &DeviceId<FakeBindingsCtx>,
852 _socket_info: netstack3_base::socket::SocketInfo,
853 _marks: &Marks,
854 _gso_info: Option<netstack3_base::GsoInfo>,
855 ) -> netstack3_filter::SocketEgressFilterResult {
856 netstack3_filter::SocketEgressFilterResult::Pass { congestion: false }
857 }
858
859 fn on_ingress(
860 &self,
861 _ip_version: net_types::ip::IpVersion,
862 _packet: packet::FragmentedByteSlice<'_, &[u8]>,
863 _header_len: usize,
864 _device: &DeviceId<FakeBindingsCtx>,
865 socket_info: netstack3_base::socket::SocketInfo,
866 marks: &Marks,
867 packet_type: PacketType,
868 gso_info: Option<netstack3_base::GsoInfo>,
869 ) -> netstack3_filter::SocketIngressFilterResult {
870 self.0.0.lock().state.packet_metadata.push((socket_info, *marks, packet_type, gso_info));
871 netstack3_filter::SocketIngressFilterResult::Accept
872 }
873}
874
875impl SocketOpsFilterBindingContext<DeviceId<FakeBindingsCtx>> for FakeBindingsCtx {
876 fn socket_ops_filter(&self) -> impl SocketOpsFilter<DeviceId<FakeBindingsCtx>> {
877 FakeSocketOpsFilter(self)
878 }
879}
880
881impl WithFakeTimerContext<TimerId<FakeBindingsCtx>> for FakeBindingsCtx {
882 fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId<FakeBindingsCtx>>) -> O>(
883 &self,
884 f: F,
885 ) -> O {
886 self.with_inner(|ctx| f(&ctx.timers))
887 }
888
889 fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId<FakeBindingsCtx>>) -> O>(
890 &mut self,
891 f: F,
892 ) -> O {
893 self.with_inner_mut(|ctx| f(&mut ctx.timers))
894 }
895}
896
897impl WithFakeFrameContext<DispatchedFrame> for FakeBindingsCtx {
898 fn with_fake_frame_ctx_mut<O, F: FnOnce(&mut FakeFrameCtx<DispatchedFrame>) -> O>(
899 &mut self,
900 f: F,
901 ) -> O {
902 self.with_inner_mut(|ctx| f(&mut ctx.frames))
903 }
904}
905
906impl InstantBindingsTypes for FakeBindingsCtx {
907 type Instant = FakeInstant;
908 type AtomicInstant = FakeAtomicInstant;
909}
910
911impl InstantContext for FakeBindingsCtx {
912 fn now(&self) -> FakeInstant {
913 self.with_inner(|ctx| ctx.now())
914 }
915}
916
917impl TimerBindingsTypes for FakeBindingsCtx {
918 type Timer = <FakeTimerCtx<TimerId<Self>> as TimerBindingsTypes>::Timer;
919 type DispatchId = TimerId<Self>;
920 type UniqueTimerId = <FakeTimerCtx<TimerId<Self>> as TimerBindingsTypes>::UniqueTimerId;
921}
922
923impl TimerContext for FakeBindingsCtx {
924 fn new_timer(&mut self, id: Self::DispatchId) -> Self::Timer {
925 self.with_inner_mut(|ctx| ctx.new_timer(id))
926 }
927
928 fn schedule_timer_instant(
929 &mut self,
930 time: Self::Instant,
931 timer: &mut Self::Timer,
932 ) -> Option<Self::Instant> {
933 match timer.dispatch_id.0 {
937 TimerIdInner::IpLayer(IpLayerTimerId::FilterTimerv4(FilterTimerId::ConntrackGc(_)))
938 | TimerIdInner::IpLayer(IpLayerTimerId::FilterTimerv6(FilterTimerId::ConntrackGc(_))) =>
939 {
940 return None;
941 }
942 _ => {}
943 }
944 self.with_inner_mut(|ctx| ctx.schedule_timer_instant(time, timer))
945 }
946
947 fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
948 self.with_inner_mut(|ctx| ctx.cancel_timer(timer))
949 }
950
951 fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
952 self.with_inner_mut(|ctx| ctx.scheduled_instant(timer))
953 }
954
955 fn unique_timer_id(&self, timer: &Self::Timer) -> Self::UniqueTimerId {
956 self.with_inner_mut(|ctx| ctx.unique_timer_id(timer))
957 }
958}
959
960impl TxMetadataBindingsTypes for FakeBindingsCtx {
961 type TxMetadata = CoreTxMetadata<Self>;
962}
963
964impl RngContext for FakeBindingsCtx {
965 type Rng<'a> = FakeCryptoRng;
966
967 fn rng(&mut self) -> Self::Rng<'_> {
968 let Self(this) = self;
969 this.lock().rng()
970 }
971}
972
973impl<T: Into<DispatchedEvent>> EventContext<T> for FakeBindingsCtx {
974 fn on_event(&mut self, event: T) {
975 self.with_inner_mut(|ctx| ctx.events.on_event(event.into()))
976 }
977}
978
979impl TcpBindingsTypes for FakeBindingsCtx {
980 type ReceiveBuffer = Arc<Mutex<RingBuffer>>;
981
982 type SendBuffer = TestSendBuffer;
983
984 type ReturnedBuffers = ClientBuffers;
985
986 type ListenerNotifierOrProvidedBuffers = ProvidedBuffers;
987
988 fn new_passive_open_buffers(
989 buffer_sizes: BufferSizes,
990 ) -> (Self::ReceiveBuffer, Self::SendBuffer, Self::ReturnedBuffers) {
991 let client = ClientBuffers::new(buffer_sizes);
992 (
993 Arc::clone(&client.receive),
994 TestSendBuffer::new(Arc::clone(&client.send), RingBuffer::default()),
995 client,
996 )
997 }
998}
999
1000impl IpRoutingBindingsTypes for FakeBindingsCtx {
1001 type RoutingTableId = ();
1002}
1003
1004impl MarksBindingsContext for FakeBindingsCtx {
1005 fn marks_to_keep_on_egress() -> &'static [MarkDomain] {
1006 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark1];
1007 &MARKS
1008 }
1009
1010 fn marks_to_set_on_ingress() -> &'static [MarkDomain] {
1011 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark2];
1012 &MARKS
1013 }
1014}
1015
1016#[cfg(not(loom))]
1017mod fake_notifiers {
1018
1019 use super::*;
1020
1021 impl ReferenceNotifiers for FakeBindingsCtx {
1022 type ReferenceReceiver<T: 'static> = !;
1023
1024 type ReferenceNotifier<T: Send + 'static> = !;
1025
1026 fn new_reference_notifier<T: Send + 'static>(
1027 debug_references: DynDebugReferences,
1028 ) -> (Self::ReferenceNotifier<T>, Self::ReferenceReceiver<T>) {
1029 panic!(
1033 "FakeBindingsCtx can't create deferred reference notifiers for type {}: \
1034 debug_references={debug_references:?}",
1035 core::any::type_name::<T>()
1036 );
1037 }
1038 }
1039
1040 impl DeferredResourceRemovalContext for FakeBindingsCtx {
1041 fn defer_removal<T: Send + 'static>(&mut self, receiver: Self::ReferenceReceiver<T>) {
1042 match receiver {}
1043 }
1044 }
1045}
1046
1047#[cfg(loom)]
1050mod loom_notifiers {
1051 use super::*;
1052
1053 use core::sync::atomic::{self, AtomicBool};
1054 use netstack3_sync::rc::Notifier;
1055
1056 #[derive(Debug)]
1057 pub struct LoomNotifier(Arc<AtomicBool>);
1058
1059 #[derive(Debug)]
1060 pub struct LoomReceiver {
1061 pub debug_refs: DynDebugReferences,
1062 pub signal: Arc<AtomicBool>,
1063 }
1064
1065 impl LoomReceiver {
1066 #[track_caller]
1067 pub fn assert_signalled(&self) {
1068 let Self { debug_refs, signal } = self;
1069 assert!(signal.load(atomic::Ordering::SeqCst), "pending references: {debug_refs:?}")
1070 }
1071 }
1072
1073 impl<T> Notifier<T> for LoomNotifier {
1074 fn notify(&mut self, _data: T) {
1075 let Self(signal) = self;
1076 signal.store(true, atomic::Ordering::SeqCst);
1077 }
1078 }
1079
1080 impl ReferenceNotifiers for FakeBindingsCtx {
1081 type ReferenceReceiver<T: 'static> = LoomReceiver;
1082 type ReferenceNotifier<T: Send + 'static> = LoomNotifier;
1083
1084 fn new_reference_notifier<T: Send + 'static>(
1085 debug_refs: DynDebugReferences,
1086 ) -> (Self::ReferenceNotifier<T>, Self::ReferenceReceiver<T>) {
1087 let signal = Arc::new(AtomicBool::default());
1088 (LoomNotifier(Arc::clone(&signal)), LoomReceiver { debug_refs, signal })
1089 }
1090 }
1091
1092 impl DeferredResourceRemovalContext for FakeBindingsCtx {
1093 fn defer_removal<T: Send + 'static>(&mut self, receiver: Self::ReferenceReceiver<T>) {
1094 self.state_mut().deferred_receivers.push(receiver);
1095 }
1096 }
1097}
1098
1099#[derive(Debug)]
1101pub struct NoOpLinkResolutionNotifier;
1102
1103impl<D: LinkDevice> LinkResolutionContext<D> for FakeBindingsCtx {
1104 type Notifier = NoOpLinkResolutionNotifier;
1105}
1106
1107impl<D: LinkDevice> LinkResolutionNotifier<D> for NoOpLinkResolutionNotifier {
1108 type Observer = ();
1109
1110 fn new() -> (Self, Self::Observer) {
1111 (NoOpLinkResolutionNotifier, ())
1112 }
1113
1114 fn notify(self, _result: Result<UnicastAddr<D::Address>, AddressResolutionFailed>) {}
1115}
1116
1117#[derive(Clone)]
1118struct DeviceConfig {
1119 mac: UnicastAddr<Mac>,
1120 addr_subnet: Option<AddrSubnetEither>,
1121 ipv4_config: Option<Ipv4DeviceConfigurationUpdate>,
1122 ipv6_config: Option<Ipv6DeviceConfigurationUpdate>,
1123}
1124
1125#[derive(Clone, Default)]
1132pub struct FakeCtxBuilder {
1133 devices: Vec<DeviceConfig>,
1134 arp_table_entries: Vec<(usize, SpecifiedAddr<Ipv4Addr>, UnicastAddr<Mac>)>,
1136 ndp_table_entries: Vec<(usize, UnicastAddr<Ipv6Addr>, UnicastAddr<Mac>)>,
1137 device_routes: Vec<(SubnetEither, usize)>,
1139}
1140
1141impl FakeCtxBuilder {
1142 pub fn with_addrs<A: IpAddress>(addrs: TestAddrs<A>) -> FakeCtxBuilder {
1144 assert!(addrs.subnet.contains(&addrs.local_ip));
1145 assert!(addrs.subnet.contains(&addrs.remote_ip));
1146
1147 let mut builder = FakeCtxBuilder::default();
1148 builder.devices.push(DeviceConfig {
1149 mac: addrs.local_mac,
1150 addr_subnet: Some(
1151 AddrSubnetEither::new(addrs.local_ip.get().into(), addrs.subnet.prefix()).unwrap(),
1152 ),
1153 ipv4_config: None,
1154 ipv6_config: None,
1155 });
1156
1157 match addrs.remote_ip.into() {
1158 IpAddr::V4(ip) => builder.arp_table_entries.push((0, ip, addrs.remote_mac)),
1159 IpAddr::V6(ip) => builder.ndp_table_entries.push((
1160 0,
1161 UnicastAddr::new(ip.get()).unwrap(),
1162 addrs.remote_mac,
1163 )),
1164 };
1165
1166 builder.ndp_table_entries.push((
1169 0,
1170 addrs.remote_mac.to_ipv6_link_local().addr().get(),
1171 addrs.remote_mac,
1172 ));
1173
1174 builder.device_routes.push((addrs.subnet.into(), 0));
1175 builder
1176 }
1177
1178 pub fn add_device(&mut self, mac: UnicastAddr<Mac>) -> usize {
1183 let idx = self.devices.len();
1184 self.devices.push(DeviceConfig {
1185 mac,
1186 addr_subnet: None,
1187 ipv4_config: None,
1188 ipv6_config: None,
1189 });
1190 idx
1191 }
1192
1193 pub fn add_device_with_config(
1198 &mut self,
1199 mac: UnicastAddr<Mac>,
1200 ipv4_config: Ipv4DeviceConfigurationUpdate,
1201 ipv6_config: Ipv6DeviceConfigurationUpdate,
1202 ) -> usize {
1203 let idx = self.devices.len();
1204 self.devices.push(DeviceConfig {
1205 mac,
1206 addr_subnet: None,
1207 ipv4_config: Some(ipv4_config),
1208 ipv6_config: Some(ipv6_config),
1209 });
1210 idx
1211 }
1212
1213 pub fn add_device_with_ip<A: IpAddress>(
1218 &mut self,
1219 mac: UnicastAddr<Mac>,
1220 ip: A,
1221 subnet: Subnet<A>,
1222 ) -> usize {
1223 assert!(subnet.contains(&ip));
1224 let idx = self.devices.len();
1225 self.devices.push(DeviceConfig {
1226 mac,
1227 addr_subnet: Some(AddrSubnetEither::new(ip.into(), subnet.prefix()).unwrap()),
1228 ipv4_config: None,
1229 ipv6_config: None,
1230 });
1231 self.device_routes.push((subnet.into(), idx));
1232 idx
1233 }
1234
1235 pub fn add_device_with_ip_and_config<A: IpAddress>(
1243 &mut self,
1244 mac: UnicastAddr<Mac>,
1245 ip: A,
1246 subnet: Subnet<A>,
1247 ipv4_config: Ipv4DeviceConfigurationUpdate,
1248 ipv6_config: Ipv6DeviceConfigurationUpdate,
1249 ) -> usize {
1250 assert!(subnet.contains(&ip));
1251 let idx = self.devices.len();
1252 self.devices.push(DeviceConfig {
1253 mac,
1254 addr_subnet: Some(AddrSubnetEither::new(ip.into(), subnet.prefix()).unwrap()),
1255 ipv4_config: Some(ipv4_config),
1256 ipv6_config: Some(ipv6_config),
1257 });
1258 self.device_routes.push((subnet.into(), idx));
1259 idx
1260 }
1261
1262 pub fn add_arp_table_entry(
1264 &mut self,
1265 device: usize,
1266 ip: SpecifiedAddr<Ipv4Addr>,
1268 mac: UnicastAddr<Mac>,
1269 ) {
1270 self.arp_table_entries.push((device, ip, mac));
1271 }
1272
1273 pub fn add_ndp_table_entry(
1275 &mut self,
1276 device: usize,
1277 ip: UnicastAddr<Ipv6Addr>,
1279 mac: UnicastAddr<Mac>,
1280 ) {
1281 self.ndp_table_entries.push((device, ip, mac));
1282 }
1283
1284 pub fn add_arp_or_ndp_table_entry<A: IpAddress>(
1287 &mut self,
1288 device: usize,
1289 ip: SpecifiedAddr<A>,
1291 mac: UnicastAddr<Mac>,
1292 ) {
1293 match ip.into() {
1294 IpAddr::V4(ip) => self.add_arp_table_entry(device, ip, mac),
1295 IpAddr::V6(ip) => {
1296 self.add_ndp_table_entry(device, UnicastAddr::new(ip.get()).unwrap(), mac)
1297 }
1298 }
1299 }
1300
1301 pub fn build(self) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1303 self.build_with_modifications(|_| {})
1304 }
1305
1306 pub fn build_with_modifications<F: FnOnce(&mut StackStateBuilder)>(
1310 self,
1311 f: F,
1312 ) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1313 let mut stack_builder = StackStateBuilder::default();
1314 f(&mut stack_builder);
1315 self.build_with(stack_builder)
1316 }
1317
1318 pub fn build_with(
1321 self,
1322 state_builder: StackStateBuilder,
1323 ) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1324 let mut ctx = Ctx::new_with_builder(state_builder);
1325
1326 let FakeCtxBuilder { devices, arp_table_entries, ndp_table_entries, device_routes } = self;
1327 let idx_to_device_id: Vec<_> = devices
1328 .into_iter()
1329 .map(|DeviceConfig { mac, addr_subnet: ip_and_subnet, ipv4_config, ipv6_config }| {
1330 let eth_id =
1331 ctx.core_api().device::<EthernetLinkDevice>().add_device_with_default_state(
1332 EthernetCreationProperties {
1333 mac: mac,
1334 max_frame_size: IPV6_MIN_IMPLIED_MAX_FRAME_SIZE,
1335 tx_offload_spec: Default::default(),
1336 },
1337 DEFAULT_INTERFACE_METRIC,
1338 );
1339 let id = eth_id.clone().into();
1340 if let Some(ipv4_config) = ipv4_config {
1341 let _previous = ctx
1342 .core_api()
1343 .device_ip::<Ipv4>()
1344 .update_configuration(&id, ipv4_config)
1345 .unwrap();
1346 }
1347 if let Some(ipv6_config) = ipv6_config {
1348 let _previous = ctx
1349 .core_api()
1350 .device_ip::<Ipv6>()
1351 .update_configuration(&id, ipv6_config)
1352 .unwrap();
1353 }
1354 ctx.test_api().enable_device(&id);
1355 match ip_and_subnet {
1356 Some(addr_sub) => {
1357 ctx.core_api().device_ip_any().add_ip_addr_subnet(&id, addr_sub).unwrap();
1358 }
1359 None => {}
1360 }
1361 eth_id
1362 })
1363 .collect();
1364 for (idx, ip, mac) in arp_table_entries {
1365 let device = &idx_to_device_id[idx];
1366 ctx.core_api()
1367 .neighbor::<Ipv4, EthernetLinkDevice>()
1368 .insert_static_entry(&device, ip.get(), mac)
1369 .expect("error inserting static ARP entry");
1370 }
1371 for (idx, ip, mac) in ndp_table_entries {
1372 let device = &idx_to_device_id[idx];
1373 ctx.core_api()
1374 .neighbor::<Ipv6, EthernetLinkDevice>()
1375 .insert_static_entry(&device, ip.get(), mac)
1376 .expect("error inserting static NDP entry");
1377 }
1378
1379 for (subnet, idx) in device_routes {
1380 let device = &idx_to_device_id[idx];
1381 ctx.test_api()
1382 .add_route(AddableEntryEither::without_gateway(
1383 subnet,
1384 device.clone().into(),
1385 AddableMetric::ExplicitMetric(RawMetric(0)),
1386 ))
1387 .expect("add device route");
1388 }
1389
1390 (ctx, idx_to_device_id)
1391 }
1392}
1393
1394pub enum FakeCtxNetworkSpec {}
1398
1399impl FakeNetworkSpec for FakeCtxNetworkSpec {
1400 type Context = FakeCtx;
1401 type TimerId = TimerId<FakeBindingsCtx>;
1402 type SendMeta = DispatchedFrame;
1403 type RecvMeta = EthernetDeviceId<FakeBindingsCtx>;
1404 fn handle_frame(ctx: &mut FakeCtx, device_id: Self::RecvMeta, data: Buf<Vec<u8>>) {
1405 ctx.core_api().device::<EthernetLinkDevice>().receive_frame(
1406 RecvEthernetFrameMeta {
1407 device_id,
1408 parsing_context: NetworkParsingContext::default(),
1409 gso_info: None,
1410 },
1411 data,
1412 )
1413 }
1414 fn handle_timer(ctx: &mut FakeCtx, dispatch: Self::TimerId, timer: FakeTimerId) {
1415 ctx.core_api().handle_timer(dispatch, timer)
1416 }
1417 fn process_queues(ctx: &mut FakeCtx) -> bool {
1418 ctx.test_api().handle_queued_rx_packets()
1419 }
1420 fn fake_frames(ctx: &mut FakeCtx) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
1421 &mut ctx.bindings_ctx
1422 }
1423}
1424
1425impl<I: IpExt> UdpReceiveBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1426 fn receive_udp(
1427 &mut self,
1428 id: &UdpSocketId<I, WeakDeviceId<Self>, FakeBindingsCtx>,
1429 _device_id: &DeviceId<Self>,
1430 _meta: UdpPacketMeta<I>,
1431 body: &[u8],
1432 ) -> Result<(), ReceiveUdpError> {
1433 let mut state = self.state_mut();
1434 let received =
1435 (&mut *state).udp_state_mut::<I>().entry(id.clone()).or_insert_with(Vec::default);
1436 received.push(body.to_owned());
1437 Ok(())
1438 }
1439
1440 fn on_socket_error(
1441 &mut self,
1442 _id: &UdpSocketId<I, WeakDeviceId<Self>, FakeBindingsCtx>,
1443 _err: PendingDatagramSocketError,
1444 ) {
1445 }
1446}
1447
1448impl UdpBindingsTypes for FakeBindingsCtx {
1449 type ExternalData<I: Ip> = ();
1450 type SendToken = FakeSendToken;
1451}
1452
1453impl<I: IpExt> IcmpEchoBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1454 fn receive_icmp_echo_reply<B: BufferMut>(
1455 &mut self,
1456 conn: &IcmpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
1457 _device: &DeviceId<Self>,
1458 _src_ip: I::Addr,
1459 _dst_ip: I::Addr,
1460 _id: u16,
1461 data: B,
1462 ) -> Result<(), ReceiveIcmpEchoError> {
1463 I::map_ip_in(
1464 (IpInvariant(self.state_mut()), conn.clone()),
1465 |(IpInvariant(mut state), conn)| {
1466 let replies = state.icmpv4_replies.entry(conn).or_insert_with(Vec::default);
1467 replies.push(data.as_ref().to_owned());
1468 },
1469 |(IpInvariant(mut state), conn)| {
1470 let replies = state.icmpv6_replies.entry(conn).or_insert_with(Vec::default);
1471 replies.push(data.as_ref().to_owned());
1472 },
1473 );
1474 Ok(())
1475 }
1476}
1477
1478impl IcmpEchoBindingsTypes for FakeBindingsCtx {
1479 type ExternalData<I: Ip> = ();
1480 type SendToken = FakeSendToken;
1481}
1482
1483impl DeviceSocketTypes for FakeBindingsCtx {
1484 type SocketState<D: Send + Sync + Debug> = Mutex<Vec<(WeakDeviceId<FakeBindingsCtx>, Vec<u8>)>>;
1485}
1486
1487impl RawIpSocketsBindingsTypes for FakeBindingsCtx {
1488 type RawIpSocketState<I: Ip> = ();
1489}
1490
1491impl DeviceSocketBindingsContext<DeviceId<Self>> for FakeBindingsCtx {
1492 fn receive_frame(
1493 &self,
1494 socket_id: &SocketId<Self>,
1495 device: &DeviceId<Self>,
1496 _frame: device::socket::Frame<&[u8]>,
1497 raw_frame: &[u8],
1498 ) -> Result<(), ReceiveFrameError> {
1499 let state = socket_id.socket_state();
1500 state.lock().push((device.downgrade(), raw_frame.into()));
1501 Ok(())
1502 }
1503}
1504
1505impl<I: IpExt> RawIpSocketsBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1506 fn receive_packet<B: SplitByteSlice>(
1507 &self,
1508 _socket: &RawIpSocketId<I, WeakDeviceId<Self>, Self>,
1509 _packet: &I::Packet<B>,
1510 _device: &DeviceId<Self>,
1511 ) -> Result<(), ReceivePacketError> {
1512 unimplemented!()
1513 }
1514}
1515
1516impl DeviceLayerStateTypes for FakeBindingsCtx {
1517 type LoopbackDeviceState = ();
1518 type EthernetDeviceState = ();
1519 type BlackholeDeviceState = ();
1520 type PureIpDeviceState = ();
1521 type DeviceIdentifier = MonotonicIdentifier;
1522}
1523
1524impl ReceiveQueueBindingsContext<LoopbackDeviceId<Self>> for FakeBindingsCtx {
1525 fn wake_rx_task(&mut self, device: &LoopbackDeviceId<FakeBindingsCtx>) {
1526 self.state_mut().rx_available.push(device.clone());
1527 }
1528}
1529
1530impl<D: Clone + Into<DeviceId<Self>>> TransmitQueueBindingsContext<D> for FakeBindingsCtx {
1531 fn wake_tx_task(&mut self, device: &D) {
1532 self.state_mut().tx_available.push(device.clone().into());
1533 }
1534}
1535
1536impl DeviceLayerEventDispatcher for FakeBindingsCtx {
1537 type DequeueContext = ();
1538
1539 fn send_ethernet_frame(
1540 &mut self,
1541 device: &EthernetDeviceId<FakeBindingsCtx>,
1542 frame: Buf<Vec<u8>>,
1543 _dequeue_context: Option<&mut Self::DequeueContext>,
1544 _csum_offload: Option<netstack3_base::ChecksumOffloadResult>,
1545 ) -> Result<(), DeviceSendFrameError> {
1546 let frame_meta = DispatchedFrame::Ethernet(device.downgrade());
1547 self.with_inner_mut(|ctx| ctx.frames.push(frame_meta, frame.into_inner()));
1548 Ok(())
1549 }
1550
1551 fn send_ip_packet(
1552 &mut self,
1553 device: &PureIpDeviceId<FakeBindingsCtx>,
1554 packet: Buf<Vec<u8>>,
1555 ip_version: IpVersion,
1556 _dequeue_context: Option<&mut Self::DequeueContext>,
1557 _csum_offload: Option<netstack3_base::ChecksumOffloadResult>,
1558 ) -> Result<(), DeviceSendFrameError> {
1559 let frame_meta = DispatchedFrame::PureIp(PureIpDeviceAndIpVersion {
1560 device: device.downgrade(),
1561 version: ip_version,
1562 });
1563 self.with_inner_mut(|ctx| ctx.frames.push(frame_meta, packet.into_inner()));
1564 Ok(())
1565 }
1566}
1567
1568impl AlwaysDefaultsSettingsContext for FakeBindingsCtx {}
1569
1570#[derive(Debug, Eq, PartialEq, Hash, GenericOverIp)]
1572#[generic_over_ip()]
1573#[allow(missing_docs)]
1574pub enum DispatchedEvent {
1575 IpDeviceIpv4(IpDeviceEvent<WeakDeviceId<FakeBindingsCtx>, Ipv4, FakeInstant>),
1576 IpDeviceIpv6(IpDeviceEvent<WeakDeviceId<FakeBindingsCtx>, Ipv6, FakeInstant>),
1577 IpLayerIpv4(IpLayerEvent<WeakDeviceId<FakeBindingsCtx>, Ipv4>),
1578 IpLayerIpv6(IpLayerEvent<WeakDeviceId<FakeBindingsCtx>, Ipv6>),
1579 NeighborIpv4(nud::Event<Mac, EthernetWeakDeviceId<FakeBindingsCtx>, Ipv4, FakeInstant>),
1580 NeighborIpv6(nud::Event<Mac, EthernetWeakDeviceId<FakeBindingsCtx>, Ipv6, FakeInstant>),
1581 RouterAdvertisement(RouterAdvertisementEvent<WeakDeviceId<FakeBindingsCtx>>),
1582 EthernetDevice(EthernetDeviceEvent<EthernetWeakDeviceId<FakeBindingsCtx>>),
1583}
1584
1585#[derive(Derivative)]
1587#[derivative(Debug(bound = ""))]
1588#[allow(missing_docs)]
1589pub struct PureIpDeviceAndIpVersion<BT: DeviceLayerTypes> {
1590 pub device: PureIpWeakDeviceId<BT>,
1591 pub version: IpVersion,
1592}
1593
1594#[derive(Debug)]
1596pub enum DispatchedFrame {
1597 Ethernet(EthernetWeakDeviceId<FakeBindingsCtx>),
1599 PureIp(PureIpDeviceAndIpVersion<FakeBindingsCtx>),
1601}
1602
1603impl<I: Ip> From<IpDeviceEvent<DeviceId<FakeBindingsCtx>, I, FakeInstant>> for DispatchedEvent {
1604 fn from(e: IpDeviceEvent<DeviceId<FakeBindingsCtx>, I, FakeInstant>) -> DispatchedEvent {
1605 let e = e.map_device(|d| d.downgrade());
1606 I::map_ip(e, |e| DispatchedEvent::IpDeviceIpv4(e), |e| DispatchedEvent::IpDeviceIpv6(e))
1607 }
1608}
1609
1610impl<I: IpExt> From<IpLayerEvent<DeviceId<FakeBindingsCtx>, I>> for DispatchedEvent {
1611 fn from(e: IpLayerEvent<DeviceId<FakeBindingsCtx>, I>) -> DispatchedEvent {
1612 let e = e.map_device(|d| d.downgrade());
1613 I::map_ip(e, |e| DispatchedEvent::IpLayerIpv4(e), |e| DispatchedEvent::IpLayerIpv6(e))
1614 }
1615}
1616
1617impl<I: Ip> From<nud::Event<Mac, EthernetDeviceId<FakeBindingsCtx>, I, FakeInstant>>
1618 for DispatchedEvent
1619{
1620 fn from(
1621 e: nud::Event<Mac, EthernetDeviceId<FakeBindingsCtx>, I, FakeInstant>,
1622 ) -> DispatchedEvent {
1623 let e = e.map_device(|d| d.downgrade());
1624 I::map_ip(e, |e| DispatchedEvent::NeighborIpv4(e), |e| DispatchedEvent::NeighborIpv6(e))
1625 }
1626}
1627
1628impl From<EthernetDeviceEvent<EthernetDeviceId<FakeBindingsCtx>>> for DispatchedEvent {
1629 fn from(e: EthernetDeviceEvent<EthernetDeviceId<FakeBindingsCtx>>) -> DispatchedEvent {
1630 let e = e.map_device(|d| d.downgrade());
1631 DispatchedEvent::EthernetDevice(e)
1632 }
1633}
1634
1635impl From<RouterAdvertisementEvent<DeviceId<FakeBindingsCtx>>> for DispatchedEvent {
1636 fn from(e: RouterAdvertisementEvent<DeviceId<FakeBindingsCtx>>) -> DispatchedEvent {
1637 let e = e.map_device(|d| d.downgrade());
1638 DispatchedEvent::RouterAdvertisement(e)
1639 }
1640}
1641
1642impl TcpSocketDestructionContext for FakeBindingsCtx {
1643 fn defer_tcp_socket_destruction<I, S>(&self, _result: RemoveResourceResultWithContext<S, Self>)
1644 where
1645 I: Ip,
1646 S: SocketDiagnosticsSeed<Output = TcpSocketDiagnostics<I, Self::Instant>> + Send + 'static,
1647 {
1648 }
1650}
1651
1652pub fn new_simple_fake_network<CtxId: Copy + Debug + Hash + Eq>(
1658 a_id: CtxId,
1659 a: FakeCtx,
1660 a_device_id: EthernetWeakDeviceId<FakeBindingsCtx>,
1661 b_id: CtxId,
1662 b: FakeCtx,
1663 b_device_id: EthernetWeakDeviceId<FakeBindingsCtx>,
1664) -> FakeNetwork<
1665 FakeCtxNetworkSpec,
1666 CtxId,
1667 impl FakeNetworkLinks<DispatchedFrame, EthernetDeviceId<FakeBindingsCtx>, CtxId>,
1668> {
1669 let contexts = vec![(a_id, a), (b_id, b)].into_iter();
1670 FakeNetwork::new(contexts, move |net, _frame: DispatchedFrame| {
1671 if net == a_id {
1672 b_device_id
1673 .upgrade()
1674 .map(|device_id| (b_id, device_id, None))
1675 .into_iter()
1676 .collect::<Vec<_>>()
1677 } else {
1678 a_device_id
1679 .upgrade()
1680 .map(|device_id| (a_id, device_id, None))
1681 .into_iter()
1682 .collect::<Vec<_>>()
1683 }
1684 })
1685}