1use alloc::boxed::Box;
6use alloc::vec::Vec;
7use core::convert::Infallible as Never;
8use core::fmt::Debug;
9use core::hash::Hash;
10use core::marker::PhantomData;
11use core::num::NonZeroU8;
12use core::ops::ControlFlow;
13#[cfg(test)]
14use core::ops::DerefMut;
15use core::sync::atomic::{self, AtomicU16};
16
17use derivative::Derivative;
18use explicit::ResultExt as _;
19use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
20use log::{debug, trace};
21use net_types::ip::{
22 GenericOverIp, Ip, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu, Subnet,
23};
24use net_types::{
25 LinkLocalAddress, MulticastAddr, MulticastAddress, NonMappedAddr, NonMulticastAddr,
26 SpecifiedAddr, SpecifiedAddress as _, Witness,
27};
28use netstack3_base::socket::{EitherStack, SocketIpAddr, SocketIpAddrExt as _};
29use netstack3_base::sync::{Mutex, PrimaryRc, RwLock, StrongRc, WeakRc};
30use netstack3_base::{
31 AnyDevice, BroadcastIpExt, CoreTimerContext, Counter, CounterCollectionSpec, CounterContext,
32 DeviceIdContext, DeviceIdentifier as _, ErrorAndSerializer, EventContext, HandleableTimer,
33 InstantContext, InterfaceProperties, IpAddressId, IpDeviceAddr, IpDeviceAddressIdContext,
34 IpExt, LocalFrameDestination, MarkDomain, Marks, Matcher as _, MatcherBindingsTypes,
35 NestedIntoCoreTimerCtx, NetworkParsingContext, NetworkSerializationContext, NotFoundError,
36 ResourceCounterContext, RngContext, SendFrameErrorReason, StrongDeviceIdentifier,
37 TimerBindingsTypes, TimerContext, TimerHandler, TxMetadata as _, TxMetadataBindingsTypes,
38 WeakIpAddressId, WrapBroadcastMarker,
39};
40use netstack3_filter::{
41 self as filter, ConnectionDirection, ConntrackConnection, FilterBindingsContext,
42 FilterBindingsTypes, FilterHandler as _, FilterIpContext, FilterIpExt, FilterIpMetadata,
43 FilterIpPacket, FilterPacketMetadata, FilterTimerId, ForwardedPacket, IpPacket, MarkAction,
44 MaybeTransportPacket as _, RejectType, SocketInfo, TransportPacketSerializer, Tuple,
45 WeakConnectionError, WeakConntrackConnection,
46};
47use netstack3_hashmap::HashMap;
48use packet::{
49 Buf, BufferMut, GrowBuffer, LayoutBufferAlloc, NestablePacketBuilder as _, PacketConstraints,
50 ParsablePacket as _, ParseBuffer, ParseBufferMut, ParseMetadata, SerializeError,
51 Serializer as _,
52};
53use packet_formats::error::{Ipv6ParseError, ParseError};
54use packet_formats::ip::{DscpAndEcn, IpPacket as _, IpPacketBuilder as _};
55use packet_formats::ipv4::{Ipv4FragmentType, Ipv4Packet};
56use packet_formats::ipv6::{Ipv6Packet, Ipv6PacketRaw};
57use thiserror::Error;
58use zerocopy::SplitByteSlice;
59
60use crate::internal::counters::{IpCounters, IpCountersIpExt};
61use crate::internal::device::opaque_iid::IidSecret;
62use crate::internal::device::slaac::SlaacCounters;
63use crate::internal::device::state::{
64 IpAddressData, IpAddressFlags, IpDeviceStateBindingsTypes, IpDeviceStateIpExt, WeakAddressId,
65};
66use crate::internal::device::{
67 self, IpDeviceAddressContext, IpDeviceBindingsContext, IpDeviceIpExt, IpDeviceSendContext,
68};
69use crate::internal::fragmentation::{FragmentableIpSerializer, FragmentationIpExt, IpFragmenter};
70use crate::internal::gmp::GmpQueryHandler;
71use crate::internal::gmp::igmp::IgmpCounters;
72use crate::internal::gmp::mld::MldCounters;
73use crate::internal::icmp::counters::IcmpCountersIpExt;
74use crate::internal::icmp::{
75 IcmpBindingsTypes, IcmpError, IcmpErrorHandler, IcmpHandlerIpExt, Icmpv4Error, Icmpv4State,
76 Icmpv4StateBuilder, Icmpv6Error, Icmpv6State, Icmpv6StateBuilder,
77};
78use crate::internal::ipv6::Ipv6PacketAction;
79use crate::internal::local_delivery::{
80 IpHeaderInfo, Ipv4HeaderInfo, Ipv6HeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta,
81 TransparentLocalDelivery,
82};
83use crate::internal::multicast_forwarding::counters::MulticastForwardingCounters;
84use crate::internal::multicast_forwarding::route::{
85 MulticastRouteIpExt, MulticastRouteTarget, MulticastRouteTargets,
86};
87use crate::internal::multicast_forwarding::state::{
88 MulticastForwardingState, MulticastForwardingStateContext,
89};
90use crate::internal::multicast_forwarding::{
91 MulticastForwardingBindingsTypes, MulticastForwardingDeviceContext, MulticastForwardingEvent,
92 MulticastForwardingTimerId,
93};
94use crate::internal::path_mtu::{PmtuBindingsTypes, PmtuCache, PmtuTimerId};
95use crate::internal::raw::counters::RawIpSocketCounters;
96use crate::internal::raw::{RawIpSocketHandler, RawIpSocketMap, RawIpSocketsBindingsTypes};
97use crate::internal::reassembly::{
98 FragmentBindingsTypes, FragmentHandler, FragmentProcessingState, FragmentTimerId,
99 FragmentablePacket, IpPacketFragmentCache, ReassemblyIpExt,
100};
101use crate::internal::routing::rules::{Rule, RuleAction, RuleInput, RulesTable};
102use crate::internal::routing::{
103 IpRoutingBindingsTypes, IpRoutingDeviceContext, NonLocalSrcAddrPolicy, PacketOrigin,
104 RoutingTable,
105};
106use crate::internal::socket::{IpSocketBindingsContext, IpSocketContext, IpSocketHandler};
107use crate::internal::types::{
108 self, Destination, InternalForwarding, NextHop, ResolvedRoute, RoutableIpAddr,
109};
110use crate::internal::{ipv6, multicast_forwarding};
111
112#[cfg(test)]
113mod tests;
114
115pub const DEFAULT_TTL: NonZeroU8 = NonZeroU8::new(64).unwrap();
117
118#[derive(Copy, Clone, Debug, Eq, PartialEq)]
120#[allow(missing_docs)]
121pub struct HopLimits {
122 pub unicast: NonZeroU8,
123 pub multicast: NonZeroU8,
124}
125
126pub const DEFAULT_HOP_LIMITS: HopLimits =
128 HopLimits { unicast: DEFAULT_TTL, multicast: NonZeroU8::new(1).unwrap() };
129
130pub const IPV6_DEFAULT_SUBNET: Subnet<Ipv6Addr> =
133 unsafe { Subnet::new_unchecked(Ipv6::UNSPECIFIED_ADDRESS, 0) };
134
135#[derive(Derivative)]
141#[derivative(Default(bound = ""))]
142pub struct IpLayerPacketMetadata<
143 I: packet_formats::ip::IpExt,
144 A,
145 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
146> {
147 conntrack_connection_and_direction:
148 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
149
150 tx_metadata: BT::TxMetadata,
155
156 marks: Marks,
158
159 socket_info: Option<SocketInfo>,
161
162 #[cfg(debug_assertions)]
163 drop_check: IpLayerPacketMetadataDropCheck,
164}
165
166#[cfg(debug_assertions)]
173#[derive(Default)]
174struct IpLayerPacketMetadataDropCheck {
175 okay_to_drop: bool,
176}
177
178#[derive(Derivative)]
181#[derivative(Debug(bound = ""), Default(bound = ""))]
182pub struct DeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
183 conntrack_entry: Option<(WeakConntrackConnection, ConnectionDirection)>,
191 tx_metadata: BT::TxMetadata,
196 marks: Marks,
203}
204
205impl<BT: TxMetadataBindingsTypes> DeviceIpLayerMetadata<BT> {
206 pub fn into_tx_metadata(self) -> BT::TxMetadata {
209 self.tx_metadata
210 }
211 #[cfg(any(test, feature = "testutils"))]
213 pub fn with_marks(marks: Marks) -> Self {
214 Self { conntrack_entry: None, tx_metadata: Default::default(), marks }
215 }
216}
217
218impl<
219 I: IpLayerIpExt,
220 A: WeakIpAddressId<I::Addr>,
221 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
222> IpLayerPacketMetadata<I, A, BT>
223{
224 fn from_device_ip_layer_metadata<CC, D>(
225 core_ctx: &mut CC,
226 device: &D,
227 DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks }: DeviceIpLayerMetadata<BT>,
228 ) -> Self
229 where
230 CC: ResourceCounterContext<D, IpCounters<I>>,
231 {
232 let conntrack_connection_and_direction = match conntrack_entry
233 .map(|(conn, dir)| conn.into_inner().map(|conn| (conn, dir)))
234 .transpose()
235 {
236 Ok(conn_and_dir) => conn_and_dir,
239 Err(WeakConnectionError::EntryRemoved) => None,
241 Err(WeakConnectionError::InvalidEntry) => {
245 core_ctx.increment_both(device, |c| &c.invalid_cached_conntrack_entry);
246 None
247 }
248 };
249
250 let socket_info = tx_metadata.socket_info();
251
252 Self {
253 conntrack_connection_and_direction,
254 tx_metadata,
255 marks,
256 socket_info,
257 #[cfg(debug_assertions)]
258 drop_check: Default::default(),
259 }
260 }
261}
262
263impl<I: IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
264 IpLayerPacketMetadata<I, A, BT>
265{
266 pub(crate) fn from_tx_metadata_and_marks(tx_metadata: BT::TxMetadata, marks: Marks) -> Self {
267 let socket_info = tx_metadata.socket_info();
268 Self {
269 conntrack_connection_and_direction: None,
270 tx_metadata,
271 marks,
272 socket_info,
273 #[cfg(debug_assertions)]
274 drop_check: Default::default(),
275 }
276 }
277
278 pub(crate) fn into_parts(
279 self,
280 ) -> (
281 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
282 BT::TxMetadata,
283 Marks,
284 Option<SocketInfo>,
285 ) {
286 let Self {
287 tx_metadata,
288 marks,
289 conntrack_connection_and_direction,
290 socket_info,
291 #[cfg(debug_assertions)]
292 mut drop_check,
293 } = self;
294 #[cfg(debug_assertions)]
295 {
296 drop_check.okay_to_drop = true;
297 }
298 (conntrack_connection_and_direction, tx_metadata, marks, socket_info)
299 }
300
301 pub(crate) fn acknowledge_drop(self) {
306 #[cfg(debug_assertions)]
307 {
308 let mut this = self;
309 this.drop_check.okay_to_drop = true;
310 }
311 }
312
313 pub(crate) fn tx_metadata(&self) -> &BT::TxMetadata {
315 &self.tx_metadata
316 }
317
318 pub(crate) fn marks(&self) -> &Marks {
320 &self.marks
321 }
322}
323
324#[cfg(debug_assertions)]
325impl Drop for IpLayerPacketMetadataDropCheck {
326 fn drop(&mut self) {
327 if !self.okay_to_drop {
328 panic!(
329 "IpLayerPacketMetadata dropped without acknowledgement. https://fxbug.dev/334127474"
330 );
331 }
332 }
333}
334
335impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
336 FilterIpMetadata<I, A, BT> for IpLayerPacketMetadata<I, A, BT>
337{
338 fn take_connection_and_direction(
339 &mut self,
340 ) -> Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)> {
341 self.conntrack_connection_and_direction.take()
342 }
343
344 fn replace_connection_and_direction(
345 &mut self,
346 conn: ConntrackConnection<I, A, BT>,
347 direction: ConnectionDirection,
348 ) -> Option<ConntrackConnection<I, A, BT>> {
349 self.conntrack_connection_and_direction.replace((conn, direction)).map(|(conn, _dir)| conn)
350 }
351}
352
353impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
354 FilterPacketMetadata for IpLayerPacketMetadata<I, A, BT>
355{
356 fn apply_mark_action(&mut self, domain: MarkDomain, action: MarkAction) {
357 action.apply(self.marks.get_mut(domain))
358 }
359
360 fn socket_info(&self) -> Option<SocketInfo> {
361 self.socket_info.clone()
362 }
363
364 fn marks(&self) -> &Marks {
365 &self.marks
366 }
367}
368
369pub type IpSendFrameError<S> = ErrorAndSerializer<IpSendFrameErrorReason, S>;
371
372#[derive(Debug, PartialEq)]
374pub enum IpSendFrameErrorReason {
375 Device(SendFrameErrorReason),
377 IllegalLoopbackAddress,
380}
381
382impl From<SendFrameErrorReason> for IpSendFrameErrorReason {
383 fn from(value: SendFrameErrorReason) -> Self {
384 Self::Device(value)
385 }
386}
387
388pub trait IpTransportContext<I, BC, CC>
394where
395 I: IpLayerIpExt,
396 CC: DeviceIdContext<AnyDevice> + ?Sized,
397{
398 type EarlyDemuxSocket;
400
401 fn early_demux<B: ParseBuffer>(
412 core_ctx: &mut CC,
413 device: &CC::DeviceId,
414 src_ip: I::Addr,
415 dst_ip: I::Addr,
416 buffer: B,
417 ) -> Option<Self::EarlyDemuxSocket>;
418
419 fn receive_icmp_error(
433 core_ctx: &mut CC,
434 bindings_ctx: &mut BC,
435 device: &CC::DeviceId,
436 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
437 original_dst_ip: SpecifiedAddr<I::Addr>,
438 original_body: &[u8],
439 err: I::ErrorCode,
440 );
441
442 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
448 core_ctx: &mut CC,
449 bindings_ctx: &mut BC,
450 device: &CC::DeviceId,
451 src_ip: I::RecvSrcAddr,
452 dst_ip: SpecifiedAddr<I::Addr>,
453 buffer: B,
454 info: &mut LocalDeliveryPacketInfo<I, H>,
455 early_demux_socket: Option<Self::EarlyDemuxSocket>,
456 ) -> Result<(), (B, I::IcmpError)>;
457}
458
459pub trait BaseTransportIpContext<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
462 type DevicesWithAddrIter<'s>: Iterator<Item = Self::DeviceId>;
465
466 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
472 &mut self,
473 addr: SpecifiedAddr<I::Addr>,
474 cb: F,
475 ) -> O;
476
477 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits;
482
483 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)>;
487}
488
489pub trait TransportIpContext<I: IpExt + FilterIpExt, BC: TxMetadataBindingsTypes>:
492 BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>
493{
494}
495
496impl<I, CC, BC> TransportIpContext<I, BC> for CC
497where
498 I: IpExt + FilterIpExt,
499 CC: BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>,
500 BC: TxMetadataBindingsTypes,
501{
502}
503
504pub trait MulticastMembershipHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
506 fn join_multicast_group(
513 &mut self,
514 bindings_ctx: &mut BC,
515 device: &Self::DeviceId,
516 addr: MulticastAddr<I::Addr>,
517 );
518
519 fn leave_multicast_group(
527 &mut self,
528 bindings_ctx: &mut BC,
529 device: &Self::DeviceId,
530 addr: MulticastAddr<I::Addr>,
531 );
532
533 fn select_device_for_multicast_group(
538 &mut self,
539 addr: MulticastAddr<I::Addr>,
540 marks: &Marks,
541 ) -> Result<Self::DeviceId, ResolveRouteError>;
542}
543
544pub trait UseTransportIpContextBlanket {}
556
557pub struct AssignedAddressDeviceIterator<Iter, I, D>(Iter, PhantomData<(I, D)>);
560
561impl<Iter, I, D> Iterator for AssignedAddressDeviceIterator<Iter, I, D>
562where
563 Iter: Iterator<Item = (D, I::AddressStatus)>,
564 I: IpLayerIpExt,
565{
566 type Item = D;
567 fn next(&mut self) -> Option<D> {
568 let Self(iter, PhantomData) = self;
569 iter.by_ref().find_map(|(device, state)| is_unicast_assigned::<I>(&state).then_some(device))
570 }
571}
572
573impl<
574 I: IpLayerIpExt,
575 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + IpRoutingBindingsTypes,
576 CC: IpDeviceContext<I>
577 + IpSocketHandler<I, BC>
578 + IpStateContext<I, BC>
579 + FilterIpContext<I, BC>
580 + UseTransportIpContextBlanket,
581> BaseTransportIpContext<I, BC> for CC
582{
583 type DevicesWithAddrIter<'s> =
584 AssignedAddressDeviceIterator<CC::DeviceAndAddressStatusIter<'s>, I, CC::DeviceId>;
585
586 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
587 &mut self,
588 addr: SpecifiedAddr<I::Addr>,
589 cb: F,
590 ) -> O {
591 self.with_address_statuses(addr, |it| cb(AssignedAddressDeviceIterator(it, PhantomData)))
592 }
593
594 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
595 match device {
596 Some(device) => HopLimits {
597 unicast: IpDeviceEgressStateContext::<I>::get_hop_limit(self, device),
598 ..DEFAULT_HOP_LIMITS
599 },
600 None => DEFAULT_HOP_LIMITS,
601 }
602 }
603
604 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)> {
605 self.with_filter_state(|state| {
606 let conn = state.conntrack.get_connection(&tuple)?;
607
608 if !conn.destination_nat() {
609 return None;
610 }
611
612 let original = conn.original_tuple();
616 Some((original.dst_addr, original.dst_port_or_id))
617 })
618 }
619}
620
621#[derive(Debug, PartialEq)]
623#[allow(missing_docs)]
624pub enum AddressStatus<S> {
625 Present(S),
626 Unassigned,
627}
628
629impl<S> AddressStatus<S> {
630 fn into_present(self) -> Option<S> {
631 match self {
632 Self::Present(s) => Some(s),
633 Self::Unassigned => None,
634 }
635 }
636}
637
638impl AddressStatus<Ipv4PresentAddressStatus> {
639 pub fn from_context_addr_v4<
641 BC: IpDeviceStateBindingsTypes,
642 CC: device::IpDeviceStateContext<Ipv4, BC> + GmpQueryHandler<Ipv4, BC>,
643 >(
644 core_ctx: &mut CC,
645 device: &CC::DeviceId,
646 addr: SpecifiedAddr<Ipv4Addr>,
647 ) -> AddressStatus<Ipv4PresentAddressStatus> {
648 if addr.is_limited_broadcast() {
649 return AddressStatus::Present(Ipv4PresentAddressStatus::LimitedBroadcast);
650 }
651
652 if MulticastAddr::new(addr.get())
653 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
654 {
655 return AddressStatus::Present(Ipv4PresentAddressStatus::Multicast);
656 }
657
658 core_ctx.with_address_ids(device, |mut addrs, core_ctx| {
659 addrs
660 .find_map(|addr_id| {
661 let dev_addr = addr_id.addr_sub();
662 let (dev_addr, subnet) = dev_addr.addr_subnet();
663
664 if **dev_addr == addr {
665 let assigned = core_ctx.with_ip_address_data(
666 device,
667 &addr_id,
668 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| {
669 *assigned
670 },
671 );
672
673 if assigned {
674 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastAssigned))
675 } else {
676 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastTentative))
677 }
678 } else if addr.get() == subnet.broadcast() {
679 Some(AddressStatus::Present(Ipv4PresentAddressStatus::SubnetBroadcast))
680 } else if device.is_loopback() && subnet.contains(addr.as_ref()) {
681 Some(AddressStatus::Present(Ipv4PresentAddressStatus::LoopbackSubnet))
682 } else {
683 None
684 }
685 })
686 .unwrap_or(AddressStatus::Unassigned)
687 })
688 }
689}
690
691impl AddressStatus<Ipv6PresentAddressStatus> {
692 pub fn from_context_addr_v6<
694 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
695 CC: device::Ipv6DeviceContext<BC> + GmpQueryHandler<Ipv6, BC>,
696 >(
697 core_ctx: &mut CC,
698 device: &CC::DeviceId,
699 addr: SpecifiedAddr<Ipv6Addr>,
700 ) -> AddressStatus<Ipv6PresentAddressStatus> {
701 if MulticastAddr::new(addr.get())
702 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
703 {
704 return AddressStatus::Present(Ipv6PresentAddressStatus::Multicast);
705 }
706
707 let addr_id = match core_ctx.get_address_id(device, addr) {
708 Ok(o) => o,
709 Err(NotFoundError) => return AddressStatus::Unassigned,
710 };
711
712 let assigned = core_ctx.with_ip_address_data(
713 device,
714 &addr_id,
715 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
716 );
717
718 if assigned {
719 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned)
720 } else {
721 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastTentative)
722 }
723 }
724}
725
726impl<S: GenericOverIp<I>, I: Ip> GenericOverIp<I> for AddressStatus<S> {
727 type Type = AddressStatus<S::Type>;
728}
729
730#[derive(Debug, PartialEq)]
732#[allow(missing_docs)]
733pub enum Ipv4PresentAddressStatus {
734 LimitedBroadcast,
735 SubnetBroadcast,
736 Multicast,
737 UnicastAssigned,
738 UnicastTentative,
739 LoopbackSubnet,
750}
751
752impl Ipv4PresentAddressStatus {
753 fn to_broadcast_marker(&self) -> Option<<Ipv4 as BroadcastIpExt>::BroadcastMarker> {
754 match self {
755 Self::LimitedBroadcast | Self::SubnetBroadcast => Some(()),
756 Self::Multicast
757 | Self::UnicastAssigned
758 | Self::UnicastTentative
759 | Self::LoopbackSubnet => None,
760 }
761 }
762}
763
764#[derive(Debug, PartialEq)]
766#[allow(missing_docs)]
767pub enum Ipv6PresentAddressStatus {
768 Multicast,
769 UnicastAssigned,
770 UnicastTentative,
771}
772
773pub trait IpLayerIpExt:
775 IpExt
776 + MulticastRouteIpExt
777 + IcmpHandlerIpExt
778 + FilterIpExt
779 + FragmentationIpExt
780 + IpDeviceIpExt
781 + IpCountersIpExt
782 + IcmpCountersIpExt
783 + ReassemblyIpExt
784{
785 type AddressStatus: Debug;
787 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>: AsRef<
789 IpStateInner<Self, StrongDeviceId, BT>,
790 >;
791 type PacketIdState;
793 type PacketId;
795 fn next_packet_id_from_state(state: &Self::PacketIdState) -> Self::PacketId;
797}
798
799impl IpLayerIpExt for Ipv4 {
800 type AddressStatus = Ipv4PresentAddressStatus;
801 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
802 Ipv4State<StrongDeviceId, BT>;
803 type PacketIdState = AtomicU16;
804 type PacketId = u16;
805 fn next_packet_id_from_state(next_packet_id: &Self::PacketIdState) -> Self::PacketId {
806 next_packet_id.fetch_add(1, atomic::Ordering::Relaxed)
810 }
811}
812
813impl IpLayerIpExt for Ipv6 {
814 type AddressStatus = Ipv6PresentAddressStatus;
815 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
816 Ipv6State<StrongDeviceId, BT>;
817 type PacketIdState = ();
818 type PacketId = ();
819 fn next_packet_id_from_state((): &Self::PacketIdState) -> Self::PacketId {
820 ()
821 }
822}
823
824pub trait IpStateContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes + MatcherBindingsTypes>:
826 IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>
827{
828 type IpRouteTablesCtx<'a>: IpRouteTablesContext<I, BT, DeviceId = Self::DeviceId>;
830
831 fn with_rules_table<
833 O,
834 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId, BT>) -> O,
835 >(
836 &mut self,
837 cb: F,
838 ) -> O;
839
840 fn with_rules_table_mut<
842 O,
843 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId, BT>) -> O,
844 >(
845 &mut self,
846 cb: F,
847 ) -> O;
848}
849
850pub trait IpRouteTablesContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
852 IpRouteTableContext<I, BT> + IpDeviceContext<I>
853{
854 type Ctx<'a>: IpRouteTableContext<I, BT, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>;
856
857 fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId, BT>;
859
860 fn with_ip_routing_tables<
862 O,
863 F: FnOnce(
864 &mut Self::Ctx<'_>,
865 &HashMap<
866 RoutingTableId<I, Self::DeviceId, BT>,
867 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
868 >,
869 ) -> O,
870 >(
871 &mut self,
872 cb: F,
873 ) -> O;
874
875 fn with_ip_routing_tables_mut<
877 O,
878 F: FnOnce(
879 &mut HashMap<
880 RoutingTableId<I, Self::DeviceId, BT>,
881 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
882 >,
883 ) -> O,
884 >(
885 &mut self,
886 cb: F,
887 ) -> O;
888
889 fn with_main_ip_routing_table<
893 O,
894 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
895 >(
896 &mut self,
897 cb: F,
898 ) -> O {
899 let main_table_id = self.main_table_id();
900 self.with_ip_routing_table(&main_table_id, cb)
901 }
902
903 fn with_main_ip_routing_table_mut<
907 O,
908 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
909 >(
910 &mut self,
911 cb: F,
912 ) -> O {
913 let main_table_id = self.main_table_id();
914 self.with_ip_routing_table_mut(&main_table_id, cb)
915 }
916}
917
918pub trait IpRouteTableContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
920 IpDeviceContext<I>
921{
922 type IpDeviceIdCtx<'a>: DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
924 + IpRoutingDeviceContext<I>
925 + IpDeviceContext<I>;
926
927 fn with_ip_routing_table<
929 O,
930 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
931 >(
932 &mut self,
933 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
934 cb: F,
935 ) -> O;
936
937 fn with_ip_routing_table_mut<
939 O,
940 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
941 >(
942 &mut self,
943 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
944 cb: F,
945 ) -> O;
946}
947
948pub trait IpDeviceEgressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
950 fn with_next_packet_id<O, F: FnOnce(&I::PacketIdState) -> O>(&self, cb: F) -> O;
952
953 fn get_local_addr_for_remote(
955 &mut self,
956 device_id: &Self::DeviceId,
957 remote: Option<SpecifiedAddr<I::Addr>>,
958 ) -> Option<IpDeviceAddr<I::Addr>>;
959
960 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8;
962}
963
964pub trait IpDeviceIngressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
966 fn address_status_for_device(
972 &mut self,
973 addr: SpecifiedAddr<I::Addr>,
974 device_id: &Self::DeviceId,
975 ) -> AddressStatus<I::AddressStatus>;
976}
977
978pub trait IpDeviceContext<I: IpLayerIpExt>:
980 IpDeviceEgressStateContext<I> + IpDeviceIngressStateContext<I>
981{
982 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
984
985 type DeviceAndAddressStatusIter<'a>: Iterator<Item = (Self::DeviceId, I::AddressStatus)>;
987
988 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
994 &mut self,
995 addr: SpecifiedAddr<I::Addr>,
996 cb: F,
997 ) -> R;
998
999 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
1001}
1002
1003pub trait IpDeviceConfirmReachableContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1005 fn confirm_reachable(
1008 &mut self,
1009 bindings_ctx: &mut BC,
1010 device: &Self::DeviceId,
1011 neighbor: SpecifiedAddr<I::Addr>,
1012 );
1013}
1014
1015pub trait IpDeviceMtuContext<I: Ip>: DeviceIdContext<AnyDevice> {
1017 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu;
1021}
1022
1023#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
1025#[generic_over_ip(I, Ip)]
1026pub enum IpLayerEvent<DeviceId, I: IpLayerIpExt> {
1027 AddRoute(types::AddableEntry<I::Addr, DeviceId>),
1029 RemoveRoutes {
1031 subnet: Subnet<I::Addr>,
1033 device: DeviceId,
1035 gateway: Option<SpecifiedAddr<I::Addr>>,
1037 },
1038 MulticastForwarding(MulticastForwardingEvent<I, DeviceId>),
1040}
1041
1042impl<DeviceId, I: IpLayerIpExt> From<MulticastForwardingEvent<I, DeviceId>>
1043 for IpLayerEvent<DeviceId, I>
1044{
1045 fn from(event: MulticastForwardingEvent<I, DeviceId>) -> IpLayerEvent<DeviceId, I> {
1046 IpLayerEvent::MulticastForwarding(event)
1047 }
1048}
1049
1050impl<DeviceId, I: IpLayerIpExt> IpLayerEvent<DeviceId, I> {
1051 pub fn map_device<N, F: Fn(DeviceId) -> N>(self, map: F) -> IpLayerEvent<N, I> {
1053 match self {
1054 IpLayerEvent::AddRoute(types::AddableEntry {
1055 subnet,
1056 device,
1057 gateway,
1058 metric,
1059 route_preference,
1060 }) => IpLayerEvent::AddRoute(types::AddableEntry {
1061 subnet,
1062 device: map(device),
1063 gateway,
1064 metric,
1065 route_preference,
1066 }),
1067 IpLayerEvent::RemoveRoutes { subnet, device, gateway } => {
1068 IpLayerEvent::RemoveRoutes { subnet, device: map(device), gateway }
1069 }
1070 IpLayerEvent::MulticastForwarding(e) => {
1071 IpLayerEvent::MulticastForwarding(e.map_device(map))
1072 }
1073 }
1074 }
1075}
1076
1077#[derive(Derivative, PartialEq, Eq, Clone, Hash)]
1079#[derivative(Debug)]
1080pub struct RouterAdvertisementEvent<D> {
1081 #[derivative(Debug = "ignore")]
1084 pub options_bytes: Box<[u8]>,
1085 pub source: net_types::ip::Ipv6Addr,
1087 pub device: D,
1089}
1090
1091impl<D> RouterAdvertisementEvent<D> {
1092 pub fn map_device<N, F: Fn(D) -> N>(self, map: F) -> RouterAdvertisementEvent<N> {
1094 let Self { options_bytes, source, device } = self;
1095 RouterAdvertisementEvent { options_bytes, source, device: map(device) }
1096 }
1097}
1098
1099pub trait NdpBindingsContext<DeviceId>: EventContext<RouterAdvertisementEvent<DeviceId>> {}
1101impl<DeviceId, BC: EventContext<RouterAdvertisementEvent<DeviceId>>> NdpBindingsContext<DeviceId>
1102 for BC
1103{
1104}
1105
1106pub trait MarksBindingsContext {
1108 fn marks_to_keep_on_egress() -> &'static [MarkDomain];
1113
1114 fn marks_to_set_on_ingress() -> &'static [MarkDomain];
1119}
1120
1121pub trait IpLayerBindingsContext<I: IpLayerIpExt, DeviceId>:
1123 InstantContext
1124 + EventContext<IpLayerEvent<DeviceId, I>>
1125 + FilterBindingsContext<DeviceId>
1126 + TxMetadataBindingsTypes
1127 + IpRoutingBindingsTypes
1128 + MarksBindingsContext
1129{
1130}
1131impl<
1132 I: IpLayerIpExt,
1133 DeviceId,
1134 BC: InstantContext
1135 + EventContext<IpLayerEvent<DeviceId, I>>
1136 + FilterBindingsContext<DeviceId>
1137 + TxMetadataBindingsTypes
1138 + IpRoutingBindingsTypes
1139 + MarksBindingsContext,
1140> IpLayerBindingsContext<I, DeviceId> for BC
1141{
1142}
1143
1144pub trait IpLayerBindingsTypes:
1146 IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes
1147{
1148}
1149impl<BT: IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes> IpLayerBindingsTypes
1150 for BT
1151{
1152}
1153
1154pub trait IpLayerContext<
1156 I: IpLayerIpExt,
1157 BC: IpLayerBindingsContext<I, <Self as DeviceIdContext<AnyDevice>>::DeviceId>,
1158>:
1159 IpStateContext<I, BC>
1160 + IpDeviceContext<I>
1161 + IpDeviceMtuContext<I>
1162 + IpDeviceSendContext<I, BC>
1163 + IcmpErrorHandler<I, BC>
1164 + MulticastForwardingStateContext<I, BC>
1165 + MulticastForwardingDeviceContext<I>
1166 + CounterContext<MulticastForwardingCounters<I>>
1167 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>
1168{
1169}
1170
1171impl<
1172 I: IpLayerIpExt,
1173 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
1174 CC: IpStateContext<I, BC>
1175 + IpDeviceContext<I>
1176 + IpDeviceMtuContext<I>
1177 + IpDeviceSendContext<I, BC>
1178 + IcmpErrorHandler<I, BC>
1179 + MulticastForwardingStateContext<I, BC>
1180 + MulticastForwardingDeviceContext<I>
1181 + CounterContext<MulticastForwardingCounters<I>>
1182 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>,
1183> IpLayerContext<I, BC> for CC
1184{
1185}
1186
1187fn is_unicast_assigned<I: IpLayerIpExt>(status: &I::AddressStatus) -> bool {
1188 #[derive(GenericOverIp)]
1189 #[generic_over_ip(I, Ip)]
1190 struct WrapAddressStatus<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
1191
1192 I::map_ip(
1193 WrapAddressStatus(status),
1194 |WrapAddressStatus(status)| match status {
1195 Ipv4PresentAddressStatus::UnicastAssigned
1196 | Ipv4PresentAddressStatus::LoopbackSubnet => true,
1197 Ipv4PresentAddressStatus::UnicastTentative
1198 | Ipv4PresentAddressStatus::LimitedBroadcast
1199 | Ipv4PresentAddressStatus::SubnetBroadcast
1200 | Ipv4PresentAddressStatus::Multicast => false,
1201 },
1202 |WrapAddressStatus(status)| match status {
1203 Ipv6PresentAddressStatus::UnicastAssigned => true,
1204 Ipv6PresentAddressStatus::Multicast | Ipv6PresentAddressStatus::UnicastTentative => {
1205 false
1206 }
1207 },
1208 )
1209}
1210
1211fn is_local_assigned_address<I: Ip + IpLayerIpExt, CC: IpDeviceIngressStateContext<I>>(
1212 core_ctx: &mut CC,
1213 device: &CC::DeviceId,
1214 addr: IpDeviceAddr<I::Addr>,
1215) -> bool {
1216 match core_ctx.address_status_for_device(addr.into(), device) {
1217 AddressStatus::Present(status) => is_unicast_assigned::<I>(&status),
1218 AddressStatus::Unassigned => false,
1219 }
1220}
1221
1222fn get_device_with_assigned_address<I, CC>(
1223 core_ctx: &mut CC,
1224 addr: IpDeviceAddr<I::Addr>,
1225) -> Option<(CC::DeviceId, I::AddressStatus)>
1226where
1227 I: IpLayerIpExt,
1228 CC: IpDeviceContext<I>,
1229{
1230 core_ctx.with_address_statuses(addr.into(), |mut it| {
1231 it.find_map(|(device, status)| {
1232 is_unicast_assigned::<I>(&status).then_some((device, status))
1233 })
1234 })
1235}
1236
1237fn get_local_addr<I: Ip + IpLayerIpExt, CC: IpDeviceContext<I>>(
1241 core_ctx: &mut CC,
1242 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1243 device: &CC::DeviceId,
1244 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1245) -> Result<IpDeviceAddr<I::Addr>, ResolveRouteError> {
1246 match local_ip_and_policy {
1247 Some((local_ip, NonLocalSrcAddrPolicy::Allow)) => Ok(local_ip),
1248 Some((local_ip, NonLocalSrcAddrPolicy::Deny)) => {
1249 is_local_assigned_address(core_ctx, device, local_ip)
1250 .then_some(local_ip)
1251 .ok_or(ResolveRouteError::NoSrcAddr)
1252 }
1253 None => core_ctx
1254 .get_local_addr_for_remote(device, remote_addr.map(Into::into))
1255 .ok_or(ResolveRouteError::NoSrcAddr),
1256 }
1257}
1258
1259#[derive(Error, Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
1261#[generic_over_ip()]
1262pub enum ResolveRouteError {
1263 #[error("a source address could not be selected")]
1265 NoSrcAddr,
1266 #[error("no route exists to the destination IP address")]
1268 Unreachable,
1269}
1270
1271fn get_local_addr_with_internal_forwarding<I, CC>(
1273 core_ctx: &mut CC,
1274 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1275 device: &CC::DeviceId,
1276 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1277) -> Result<(IpDeviceAddr<I::Addr>, InternalForwarding<CC::DeviceId>), ResolveRouteError>
1278where
1279 I: IpLayerIpExt,
1280 CC: IpDeviceContext<I>,
1281{
1282 match get_local_addr(core_ctx, local_ip_and_policy, device, remote_addr) {
1283 Ok(src_addr) => Ok((src_addr, InternalForwarding::NotUsed)),
1284 Err(e) => {
1285 if let Some((local_ip, _policy)) = local_ip_and_policy {
1293 if let Some((device, _addr_status)) =
1294 get_device_with_assigned_address(core_ctx, local_ip)
1295 {
1296 if core_ctx.is_device_unicast_forwarding_enabled(&device) {
1297 return Ok((local_ip, InternalForwarding::Used(device)));
1298 }
1299 }
1300 }
1301 Err(e)
1302 }
1303 }
1304}
1305
1306#[derive(Debug, PartialEq, Eq)]
1309struct RuleWalkInfo<O> {
1310 observed_source_address_matcher: bool,
1312 inner: O,
1315}
1316
1317fn walk_rules<
1331 I: IpLayerIpExt,
1332 BT: IpRoutingBindingsTypes + MatcherBindingsTypes,
1333 CC: IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>,
1334 O,
1335 State,
1336 F: FnMut(
1337 State,
1338 &mut CC::IpDeviceIdCtx<'_>,
1339 &RoutingTable<I, CC::DeviceId>,
1340 ) -> ControlFlow<O, State>,
1341>(
1342 core_ctx: &mut CC,
1343 rules: &RulesTable<I, CC::DeviceId, BT>,
1344 init: State,
1345 rule_input: &RuleInput<'_, I, CC::DeviceId>,
1346 mut lookup_table: F,
1347) -> ControlFlow<RuleAction<RuleWalkInfo<O>>, RuleWalkInfo<State>> {
1348 rules.iter().try_fold(
1349 RuleWalkInfo { inner: init, observed_source_address_matcher: false },
1350 |RuleWalkInfo { inner: state, observed_source_address_matcher },
1351 Rule { action, matcher }| {
1352 let observed_source_address_matcher =
1353 observed_source_address_matcher || matcher.source_address_matcher.is_some();
1354 if !matcher.matches(rule_input) {
1355 return ControlFlow::Continue(RuleWalkInfo {
1356 inner: state,
1357 observed_source_address_matcher,
1358 });
1359 }
1360 match action {
1361 RuleAction::Unreachable => return ControlFlow::Break(RuleAction::Unreachable),
1362 RuleAction::Lookup(table_id) => core_ctx.with_ip_routing_table(
1363 &table_id,
1364 |core_ctx, table| match lookup_table(state, core_ctx, table) {
1365 ControlFlow::Break(out) => {
1366 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1367 inner: out,
1368 observed_source_address_matcher,
1369 }))
1370 }
1371 ControlFlow::Continue(state) => ControlFlow::Continue(RuleWalkInfo {
1372 inner: state,
1373 observed_source_address_matcher,
1374 }),
1375 },
1376 ),
1377 }
1378 },
1379 )
1380}
1381
1382pub fn resolve_output_route_to_destination<
1393 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1394 BC: IpDeviceBindingsContext<I, CC::DeviceId> + IpLayerBindingsContext<I, CC::DeviceId>,
1395 CC: IpStateContext<I, BC> + IpDeviceContext<I> + device::IpDeviceConfigurationContext<I, BC>,
1396>(
1397 core_ctx: &mut CC,
1398 device: Option<&CC::DeviceId>,
1399 src_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1400 dst_ip: Option<RoutableIpAddr<I::Addr>>,
1401 marks: &Marks,
1402) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1403 enum LocalDelivery<A, D> {
1404 WeakLoopback { dst_ip: A, device: D },
1405 StrongForDevice(D),
1406 }
1407
1408 let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1425 let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1426 match (device, dst_ip) {
1427 (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1428 .then_some(LocalDelivery::StrongForDevice(device.clone())),
1429 (None, Some(dst_ip)) => {
1430 get_device_with_assigned_address(core_ctx, dst_ip).map(
1431 |(dst_device, _addr_status)| {
1432 if src_ip_and_policy
1437 .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1438 || dst_ip.as_ref().must_have_zone()
1439 {
1440 LocalDelivery::StrongForDevice(dst_device)
1441 } else {
1442 LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1443 }
1444 },
1445 )
1446 }
1447 (_, None) => None,
1448 }
1449 };
1450
1451 if let Some(local_delivery) = local_delivery_instructions {
1452 let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1453
1454 let (src_addr, dest_device) = match local_delivery {
1455 LocalDelivery::WeakLoopback { dst_ip, device } => {
1456 let src_ip = match src_ip_and_policy {
1457 Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1458 let _device = get_device_with_assigned_address(core_ctx, src_ip)
1459 .ok_or(ResolveRouteError::NoSrcAddr)?;
1460 src_ip
1461 }
1462 Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1463 None => dst_ip,
1464 };
1465 (src_ip, device)
1466 }
1467 LocalDelivery::StrongForDevice(device) => {
1468 (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1469 }
1470 };
1471 return Ok(ResolvedRoute {
1472 src_addr,
1473 local_delivery_device: Some(dest_device),
1474 device: loopback,
1475 next_hop: NextHop::RemoteAsNeighbor,
1476 internal_forwarding: InternalForwarding::NotUsed,
1477 });
1478 }
1479 let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1480 let rule_input = RuleInput {
1481 packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1482 marks,
1483 };
1484 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
1485 let mut walk_rules = |rule_input, src_ip_and_policy| {
1486 walk_rules(
1487 core_ctx,
1488 rules,
1489 None, rule_input,
1491 |first_error, core_ctx, table| {
1492 let mut matching_with_addr = table.lookup_filter_map(
1493 core_ctx,
1494 device,
1495 dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1496 |core_ctx, d| {
1497 Some(get_local_addr_with_internal_forwarding(
1498 core_ctx,
1499 src_ip_and_policy,
1500 d,
1501 dst_ip,
1502 ))
1503 },
1504 );
1505
1506 let first_error_in_this_table = match matching_with_addr.next() {
1507 Some((
1508 Destination { device, next_hop },
1509 Ok((local_addr, internal_forwarding)),
1510 )) => {
1511 return ControlFlow::Break(Ok((
1512 Destination { device: device.clone(), next_hop },
1513 local_addr,
1514 internal_forwarding,
1515 )));
1516 }
1517 Some((_, Err(e))) => e,
1518 None => return ControlFlow::Continue(first_error),
1522 };
1523
1524 matching_with_addr
1525 .filter_map(|(destination, local_addr)| {
1526 local_addr.ok_checked::<ResolveRouteError>().map(
1529 |(local_addr, internal_forwarding)| {
1530 (destination, local_addr, internal_forwarding)
1531 },
1532 )
1533 })
1534 .next()
1535 .map_or(
1536 ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1537 |(
1538 Destination { device, next_hop },
1539 local_addr,
1540 internal_forwarding,
1541 )| {
1542 ControlFlow::Break(Ok((
1543 Destination { device: device.clone(), next_hop },
1544 local_addr,
1545 internal_forwarding,
1546 )))
1547 },
1548 )
1549 },
1550 )
1551 };
1552
1553 let result = match walk_rules(&rule_input, src_ip_and_policy) {
1554 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1561 inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1562 observed_source_address_matcher: true,
1563 })) if src_ip_and_policy.is_none() => walk_rules(
1564 &RuleInput {
1565 packet_origin: PacketOrigin::Local {
1566 bound_address: Some(selected_src_addr.into()),
1567 bound_device: device,
1568 },
1569 marks,
1570 },
1571 Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1572 ),
1573 result => result,
1574 };
1575
1576 match result {
1577 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1578 inner: result,
1579 observed_source_address_matcher: _,
1580 })) => {
1581 result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1582 ResolvedRoute {
1583 src_addr,
1584 device,
1585 local_delivery_device: None,
1586 next_hop,
1587 internal_forwarding,
1588 }
1589 })
1590 }
1591 ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1592 ControlFlow::Continue(RuleWalkInfo {
1593 inner: first_error,
1594 observed_source_address_matcher: _,
1595 }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1596 }
1597 })
1598}
1599
1600pub trait UseIpSocketContextBlanket {}
1605
1606impl<I, BC, CC> IpSocketContext<I, BC> for CC
1607where
1608 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1609 BC: IpDeviceBindingsContext<I, CC::DeviceId>
1610 + IpLayerBindingsContext<I, CC::DeviceId>
1611 + IpSocketBindingsContext<CC::DeviceId>,
1612 CC: IpLayerEgressContext<I, BC>
1613 + IpStateContext<I, BC>
1614 + IpDeviceContext<I>
1615 + IpDeviceConfirmReachableContext<I, BC>
1616 + IpDeviceMtuContext<I>
1617 + device::IpDeviceConfigurationContext<I, BC>
1618 + IcmpErrorHandler<I, BC>
1619 + UseIpSocketContextBlanket,
1620{
1621 fn lookup_route(
1622 &mut self,
1623 _bindings_ctx: &mut BC,
1624 device: Option<&CC::DeviceId>,
1625 local_ip: Option<IpDeviceAddr<I::Addr>>,
1626 addr: RoutableIpAddr<I::Addr>,
1627 transparent: bool,
1628 marks: &Marks,
1629 ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1630 let src_ip_and_policy = local_ip.map(|local_ip| {
1631 (
1632 local_ip,
1633 if transparent {
1634 NonLocalSrcAddrPolicy::Allow
1635 } else {
1636 NonLocalSrcAddrPolicy::Deny
1637 },
1638 )
1639 });
1640 let res =
1641 resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1642 trace!(
1643 "lookup_route(\
1644 device={device:?}, \
1645 local_ip={local_ip:?}, \
1646 addr={addr:?}, \
1647 transparent={transparent:?}, \
1648 marks={marks:?}) => {res:?}"
1649 );
1650 res
1651 }
1652
1653 fn send_ip_packet<S>(
1654 &mut self,
1655 bindings_ctx: &mut BC,
1656 meta: SendIpPacketMeta<
1657 I,
1658 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1659 SpecifiedAddr<I::Addr>,
1660 >,
1661 body: S,
1662 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1663 ) -> Result<(), IpSendFrameError<S>>
1664 where
1665 S: TransportPacketSerializer<I>,
1666 S::Buffer: BufferMut,
1667 {
1668 send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1669 }
1670
1671 fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1672 device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1673 }
1674
1675 fn confirm_reachable(
1676 &mut self,
1677 bindings_ctx: &mut BC,
1678 dst: SpecifiedAddr<I::Addr>,
1679 input: RuleInput<'_, I, Self::DeviceId>,
1680 ) {
1681 match lookup_route_table(self, dst.get(), input) {
1682 Some(Destination { next_hop, device }) => {
1683 let neighbor = match next_hop {
1684 NextHop::RemoteAsNeighbor => dst,
1685 NextHop::Gateway(gateway) => gateway,
1686 NextHop::Broadcast(marker) => {
1687 I::map_ip::<_, ()>(
1688 WrapBroadcastMarker(marker),
1689 |WrapBroadcastMarker(())| {
1690 debug!(
1691 "can't confirm {dst:?}@{device:?} as reachable: \
1692 dst is a broadcast address"
1693 );
1694 },
1695 |WrapBroadcastMarker(never)| match never {},
1696 );
1697 return;
1698 }
1699 };
1700 IpDeviceConfirmReachableContext::confirm_reachable(
1701 self,
1702 bindings_ctx,
1703 &device,
1704 neighbor,
1705 );
1706 }
1707 None => {
1708 debug!("can't confirm {dst:?} as reachable: no route");
1709 }
1710 }
1711 }
1712}
1713
1714pub trait SocketMetadata<CC>
1717where
1718 CC: ?Sized,
1719{
1720 fn socket_info(&self, core_ctx: &mut CC) -> SocketInfo;
1722 fn marks(&self, _core_ctx: &mut CC) -> Marks;
1724}
1725
1726impl<T, O, CC> SocketMetadata<CC> for EitherStack<T, O>
1727where
1728 CC: ?Sized,
1729 T: SocketMetadata<CC>,
1730 O: SocketMetadata<CC>,
1731{
1732 fn socket_info(&self, core_ctx: &mut CC) -> SocketInfo {
1733 match self {
1734 Self::ThisStack(t) => t.socket_info(core_ctx),
1735 Self::OtherStack(o) => o.socket_info(core_ctx),
1736 }
1737 }
1738
1739 fn marks(&self, core_ctx: &mut CC) -> Marks {
1740 match self {
1741 Self::ThisStack(t) => t.marks(core_ctx),
1742 Self::OtherStack(o) => o.marks(core_ctx),
1743 }
1744 }
1745}
1746
1747pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1752 type EarlyDemuxSocket: SocketMetadata<Self>;
1754
1755 fn early_demux<B: ParseBuffer>(
1757 &mut self,
1758 device: &Self::DeviceId,
1759 frame_dst: Option<LocalFrameDestination>,
1760 src_ip: I::Addr,
1761 dst_ip: I::Addr,
1762 proto: I::Proto,
1763 body: B,
1764 ) -> Option<Self::EarlyDemuxSocket>;
1765
1766 fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1770 &mut self,
1771 bindings_ctx: &mut BC,
1772 device: &Self::DeviceId,
1773 src_ip: I::RecvSrcAddr,
1774 dst_ip: SpecifiedAddr<I::Addr>,
1775 proto: I::Proto,
1776 body: B,
1777 info: &mut LocalDeliveryPacketInfo<I, H>,
1778 early_demux_socket: Option<Self::EarlyDemuxSocket>,
1779 ) -> Result<(), I::IcmpError>;
1780}
1781
1782pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1784 IpTransportDispatchContext<
1785 I,
1786 BC,
1787 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1788 > + IpDeviceIngressStateContext<I>
1789 + IpDeviceMtuContext<I>
1790 + IpDeviceSendContext<I, BC>
1791 + IcmpErrorHandler<I, BC>
1792 + IpLayerContext<I, BC>
1793 + FragmentHandler<I, BC>
1794 + FilterHandlerProvider<I, BC>
1795 + RawIpSocketHandler<I, BC>
1796{
1797}
1798
1799impl<
1800 I: IpLayerIpExt,
1801 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1802 CC: IpTransportDispatchContext<
1803 I,
1804 BC,
1805 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1806 > + IpDeviceIngressStateContext<I>
1807 + IpDeviceMtuContext<I>
1808 + IpDeviceSendContext<I, BC>
1809 + IcmpErrorHandler<I, BC>
1810 + IpLayerContext<I, BC>
1811 + FragmentHandler<I, BC>
1812 + FilterHandlerProvider<I, BC>
1813 + RawIpSocketHandler<I, BC>,
1814> IpLayerIngressContext<I, BC> for CC
1815{
1816}
1817
1818pub trait IpLayerEgressContext<I, BC>:
1820 IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1821 + FilterHandlerProvider<I, BC>
1822 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1823where
1824 I: IpLayerIpExt,
1825 BC: FilterBindingsContext<Self::DeviceId> + TxMetadataBindingsTypes,
1826{
1827}
1828
1829impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1830where
1831 I: IpLayerIpExt,
1832 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes,
1833 CC: IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1834 + FilterHandlerProvider<I, BC>
1835 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
1836{
1837}
1838
1839pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1841 IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
1842{
1843}
1844
1845impl<
1846 I: IpLayerIpExt,
1847 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1848 CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
1849> IpLayerForwardingContext<I, BC> for CC
1850{
1851}
1852
1853#[derive(Copy, Clone, Default)]
1855pub struct Ipv4StateBuilder {
1856 icmp: Icmpv4StateBuilder,
1857}
1858
1859impl Ipv4StateBuilder {
1860 #[cfg(any(test, feature = "testutils"))]
1862 pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
1863 &mut self.icmp
1864 }
1865
1866 pub fn build<
1868 CC: CoreTimerContext<IpLayerTimerId, BC>,
1869 StrongDeviceId: StrongDeviceIdentifier,
1870 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1871 >(
1872 self,
1873 bindings_ctx: &mut BC,
1874 ) -> Ipv4State<StrongDeviceId, BC> {
1875 let Ipv4StateBuilder { icmp } = self;
1876
1877 Ipv4State {
1878 inner: IpStateInner::new::<CC>(bindings_ctx),
1879 icmp: icmp.build(),
1880 next_packet_id: Default::default(),
1881 }
1882 }
1883}
1884
1885#[derive(Copy, Clone)]
1889pub struct Ipv6StateBuilder {
1890 icmp: Icmpv6StateBuilder,
1891 slaac_stable_secret_key: Option<IidSecret>,
1892}
1893
1894impl Ipv6StateBuilder {
1895 pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
1900 self.slaac_stable_secret_key = Some(secret_key);
1901 self
1902 }
1903
1904 pub fn build<
1910 CC: CoreTimerContext<IpLayerTimerId, BC>,
1911 StrongDeviceId: StrongDeviceIdentifier,
1912 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1913 >(
1914 self,
1915 bindings_ctx: &mut BC,
1916 ) -> Ipv6State<StrongDeviceId, BC> {
1917 let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
1918
1919 let slaac_stable_secret_key = slaac_stable_secret_key
1920 .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
1921
1922 Ipv6State {
1923 inner: IpStateInner::new::<CC>(bindings_ctx),
1924 icmp: icmp.build(),
1925 slaac_counters: Default::default(),
1926 slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
1927 slaac_stable_secret_key,
1928 }
1929 }
1930}
1931
1932impl Default for Ipv6StateBuilder {
1933 fn default() -> Self {
1934 #[cfg(any(test, feature = "testutils"))]
1935 let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
1936
1937 #[cfg(not(any(test, feature = "testutils")))]
1938 let slaac_stable_secret_key = None;
1939
1940 Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
1941 }
1942}
1943
1944pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1946 pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
1948 pub icmp: Icmpv4State<BT>,
1950 pub next_packet_id: AtomicU16,
1952}
1953
1954impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1955 AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
1956{
1957 fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
1958 &self.inner
1959 }
1960}
1961
1962pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
1966 core_ctx: &mut CC,
1967) -> I::PacketId {
1968 core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
1969}
1970
1971pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1973 pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
1975 pub icmp: Icmpv6State<BT>,
1977 pub slaac_counters: SlaacCounters,
1979 pub slaac_temp_secret_key: IidSecret,
1981 pub slaac_stable_secret_key: IidSecret,
1986}
1987
1988impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1989 AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
1990{
1991 fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
1992 &self.inner
1993 }
1994}
1995
1996impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1997 OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
1998{
1999 type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
2000 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2001 OrderedLockRef::new(&self.fragment_cache)
2002 }
2003}
2004
2005impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2006 OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
2007{
2008 type Lock = Mutex<PmtuCache<I, BT>>;
2009 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2010 OrderedLockRef::new(&self.pmtu_cache)
2011 }
2012}
2013
2014impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2015 OrderedLockAccess<RulesTable<I, D, BT>> for IpStateInner<I, D, BT>
2016{
2017 type Lock = RwLock<RulesTable<I, D, BT>>;
2018 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2019 OrderedLockRef::new(&self.rules_table)
2020 }
2021}
2022
2023impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2024 OrderedLockAccess<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>
2025 for IpStateInner<I, D, BT>
2026{
2027 type Lock =
2028 Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>;
2029 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2030 OrderedLockRef::new(&self.tables)
2031 }
2032}
2033
2034impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpRoutingBindingsTypes>
2035 OrderedLockAccess<RoutingTable<I, D>> for RoutingTableId<I, D, BT>
2036{
2037 type Lock = RwLock<RoutingTable<I, D>>;
2038 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2039 let Self(inner) = self;
2040 OrderedLockRef::new(&inner.routing_table)
2041 }
2042}
2043
2044impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2045 OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
2046{
2047 type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
2048 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2049 OrderedLockRef::new(&self.multicast_forwarding)
2050 }
2051}
2052
2053impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2054 OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
2055{
2056 type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
2057 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2058 OrderedLockRef::new(&self.raw_sockets)
2059 }
2060}
2061
2062impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2063 OrderedLockAccess<filter::State<I, WeakAddressId<I, BT>, BT>> for IpStateInner<I, D, BT>
2064{
2065 type Lock = RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>;
2066 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2067 OrderedLockRef::new(&self.filter)
2068 }
2069}
2070
2071pub trait IpStateBindingsTypes:
2073 PmtuBindingsTypes
2074 + FragmentBindingsTypes
2075 + RawIpSocketsBindingsTypes
2076 + FilterBindingsTypes
2077 + MulticastForwardingBindingsTypes
2078 + IpDeviceStateBindingsTypes
2079 + IpRoutingBindingsTypes
2080{
2081}
2082impl<BT> IpStateBindingsTypes for BT where
2083 BT: PmtuBindingsTypes
2084 + FragmentBindingsTypes
2085 + RawIpSocketsBindingsTypes
2086 + FilterBindingsTypes
2087 + MulticastForwardingBindingsTypes
2088 + IpDeviceStateBindingsTypes
2089 + IpRoutingBindingsTypes
2090{
2091}
2092
2093#[derive(Derivative)]
2095#[derivative(Debug(bound = ""))]
2096#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2097pub enum RoutingTableCookie<BT: IpRoutingBindingsTypes> {
2098 Main,
2100 BindingsId(BT::RoutingTableId),
2102}
2103
2104#[derive(Derivative)]
2106#[derivative(Debug(bound = "D: Debug"))]
2107pub struct BaseRoutingTableState<I: Ip, D, BT: IpRoutingBindingsTypes> {
2108 routing_table: RwLock<RoutingTable<I, D>>,
2109 bindings_id: RoutingTableCookie<BT>,
2110}
2111
2112impl<I: Ip, D, BT: IpRoutingBindingsTypes> BaseRoutingTableState<I, D, BT> {
2113 pub(crate) fn with_bindings_id(bindings_id: RoutingTableCookie<BT>) -> Self {
2114 Self { bindings_id, routing_table: Default::default() }
2115 }
2116}
2117
2118#[derive(Derivative)]
2120#[derivative(PartialEq(bound = ""))]
2121#[derivative(Eq(bound = ""))]
2122#[derivative(Hash(bound = ""))]
2123#[derivative(Clone(bound = ""))]
2124pub struct RoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes>(
2125 StrongRc<BaseRoutingTableState<I, D, BT>>,
2126);
2127
2128impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for RoutingTableId<I, D, BT> {
2129 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2130 let Self(rc) = self;
2131 f.debug_tuple("RoutingTableId").field(&I::NAME).field(&rc.bindings_id).finish()
2132 }
2133}
2134
2135impl<I: Ip, D, BT: IpRoutingBindingsTypes> RoutingTableId<I, D, BT> {
2136 pub(crate) fn new(rc: StrongRc<BaseRoutingTableState<I, D, BT>>) -> Self {
2138 Self(rc)
2139 }
2140
2141 #[cfg(any(test, feature = "testutils"))]
2143 pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
2144 let Self(inner) = self;
2145 &inner.routing_table
2146 }
2147
2148 pub fn downgrade(&self) -> WeakRoutingTableId<I, D, BT>
2150 where
2151 BT::RoutingTableId: Clone,
2152 {
2153 let Self(rc) = self;
2154 WeakRoutingTableId { rc: StrongRc::downgrade(rc), bindings_id: rc.bindings_id.clone() }
2155 }
2156
2157 #[cfg(test)]
2158 fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2159 let Self(rc) = self;
2160 rc.routing_table.write()
2161 }
2162
2163 pub fn bindings_id(&self) -> &RoutingTableCookie<BT> {
2165 let Self(rc) = self;
2166 &rc.bindings_id
2167 }
2168}
2169
2170#[derive(Derivative)]
2172#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2173#[derivative(PartialEq, Eq, Hash)]
2174pub struct WeakRoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes> {
2175 rc: WeakRc<BaseRoutingTableState<I, D, BT>>,
2176 #[derivative(PartialEq = "ignore")]
2177 #[derivative(Hash = "ignore")]
2178 bindings_id: RoutingTableCookie<BT>,
2179}
2180
2181impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for WeakRoutingTableId<I, D, BT> {
2182 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2183 let Self { bindings_id, .. } = self;
2184 f.debug_tuple("WeakRoutingTableId").field(&I::NAME).field(bindings_id).finish()
2185 }
2186}
2187
2188#[derive(GenericOverIp)]
2190#[generic_over_ip(I, Ip)]
2191pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2192 rules_table: RwLock<RulesTable<I, D, BT>>,
2193 main_table_id: RoutingTableId<I, D, BT>,
2195 multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2196 multicast_forwarding_counters: MulticastForwardingCounters<I>,
2197 fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2198 pmtu_cache: Mutex<PmtuCache<I, BT>>,
2199 counters: IpCounters<I>,
2200 raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2201 raw_socket_counters: RawIpSocketCounters<I>,
2202 filter: RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>,
2203 tables: Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>,
2209 igmp_counters: IgmpCounters,
2210 mld_counters: MldCounters,
2211}
2212
2213impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2214 pub fn counters(&self) -> &IpCounters<I> {
2216 &self.counters
2217 }
2218
2219 pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2221 &self.multicast_forwarding_counters
2222 }
2223
2224 pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2226 &self.raw_socket_counters
2227 }
2228
2229 pub fn main_table_id(&self) -> &RoutingTableId<I, D, BT> {
2231 &self.main_table_id
2232 }
2233
2234 #[cfg(any(test, feature = "testutils"))]
2236 pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2237 &self.pmtu_cache
2238 }
2239
2240 #[cfg(any(test, feature = "testutils"))]
2242 pub fn filter(&self) -> &RwLock<filter::State<I, WeakAddressId<I, BT>, BT>> {
2243 &self.filter
2244 }
2245
2246 pub fn igmp_counters(&self) -> &IgmpCounters {
2248 &self.igmp_counters
2249 }
2250
2251 pub fn mld_counters(&self) -> &MldCounters {
2253 &self.mld_counters
2254 }
2255}
2256
2257impl<
2258 I: IpLayerIpExt,
2259 D: StrongDeviceIdentifier,
2260 BC: TimerContext + RngContext + IpStateBindingsTypes + IpRoutingBindingsTypes,
2261> IpStateInner<I, D, BC>
2262{
2263 fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2265 let main_table: PrimaryRc<BaseRoutingTableState<I, D, BC>> =
2266 PrimaryRc::new(BaseRoutingTableState::with_bindings_id(RoutingTableCookie::Main));
2267 let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2268 Self {
2269 rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2270 tables: Mutex::new(HashMap::from_iter(core::iter::once((
2271 main_table_id.clone(),
2272 main_table,
2273 )))),
2274 main_table_id,
2275 multicast_forwarding: Default::default(),
2276 multicast_forwarding_counters: Default::default(),
2277 fragment_cache: Mutex::new(
2278 IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2279 ),
2280 pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2281 counters: Default::default(),
2282 raw_sockets: Default::default(),
2283 raw_socket_counters: Default::default(),
2284 filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2285 igmp_counters: Default::default(),
2286 mld_counters: Default::default(),
2287 }
2288 }
2289}
2290
2291#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2293#[generic_over_ip()]
2294pub enum IpLayerTimerId {
2295 ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2297 ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2299 PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2301 PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2303 FilterTimerv4(FilterTimerId<Ipv4>),
2305 FilterTimerv6(FilterTimerId<Ipv6>),
2307 MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2309 MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2311}
2312
2313impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2314 fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2315 I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2316 }
2317}
2318
2319impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2320 fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2321 I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2322 }
2323}
2324
2325impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2326 fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2327 I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2328 }
2329}
2330
2331impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2332 fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2333 I::map_ip(
2334 timer,
2335 IpLayerTimerId::MulticastForwardingTimerv4,
2336 IpLayerTimerId::MulticastForwardingTimerv6,
2337 )
2338 }
2339}
2340
2341impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2342where
2343 CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2344 + TimerHandler<BC, FragmentTimerId<Ipv6>>
2345 + TimerHandler<BC, PmtuTimerId<Ipv4>>
2346 + TimerHandler<BC, PmtuTimerId<Ipv6>>
2347 + TimerHandler<BC, FilterTimerId<Ipv4>>
2348 + TimerHandler<BC, FilterTimerId<Ipv6>>
2349 + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2350 + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2351 BC: TimerBindingsTypes,
2352{
2353 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2354 match self {
2355 IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2356 core_ctx.handle_timer(bindings_ctx, id, timer)
2357 }
2358 IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2359 core_ctx.handle_timer(bindings_ctx, id, timer)
2360 }
2361 IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2362 IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2363 IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2364 IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2365 IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2366 core_ctx.handle_timer(bindings_ctx, id, timer)
2367 }
2368 IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2369 core_ctx.handle_timer(bindings_ctx, id, timer)
2370 }
2371 }
2372 }
2373}
2374
2375pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2382 err: I::IcmpError,
2384 src_ip: SocketIpAddr<I::Addr>,
2387 dst_ip: SocketIpAddr<I::Addr>,
2390 frame_dst: Option<LocalFrameDestination>,
2392 device: &'a D,
2394 meta: ParseMetadata,
2397 marks: Marks,
2399 proto: I::Proto,
2401}
2402
2403impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2404 pub fn new<CC, B>(
2405 core_ctx: &mut CC,
2406 err: I::IcmpError,
2407 packet: &I::Packet<B>,
2408 frame_dst: Option<LocalFrameDestination>,
2409 device: &'a D,
2410 marks: Marks,
2411 ) -> Option<Self>
2412 where
2413 I: IpCountersIpExt,
2414 CC: ResourceCounterContext<D, IpCounters<I>>,
2415 B: SplitByteSlice,
2416 {
2417 let Some(src_ip) = SocketIpAddr::new(packet.src_ip()) else {
2418 core_ctx.increment_both(device, |c| &c.unspecified_source);
2419 return None;
2420 };
2421 let Some(dst_ip) = SocketIpAddr::new(packet.dst_ip()) else {
2422 return None;
2423 };
2424
2425 let is_ipv4_fragment = I::map_ip_in(
2427 packet,
2428 |p| {
2429 packet_formats::ipv4::Ipv4Header::fragment_type(p)
2430 == Ipv4FragmentType::NonInitialFragment
2431 },
2432 |_| false,
2433 );
2434 if is_ipv4_fragment {
2435 return None;
2436 }
2437
2438 let meta = packet.parse_metadata();
2439 let proto = packet.proto();
2440 Some(Self { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto })
2441 }
2442
2443 pub fn send<B, BC, CC>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, mut body: B)
2450 where
2451 B: BufferMut,
2452 CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2453 {
2454 let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto } = self;
2455 let header_len = meta.header_len();
2456
2457 body.undo_parse(meta);
2461
2462 core_ctx.send_icmp_error_message(
2463 bindings_ctx,
2464 Some(device),
2465 frame_dst,
2466 src_ip,
2467 dst_ip,
2468 body,
2469 err,
2470 header_len,
2471 proto,
2472 &marks,
2473 );
2474 }
2475}
2476
2477#[derive(PartialEq, Eq)]
2483struct EarlyDemuxResult<I: Ip, S> {
2484 socket: S,
2485 src_addr: I::Addr,
2486 src_port: Option<u16>,
2487}
2488
2489impl<I: FilterIpExt, S> EarlyDemuxResult<I, S> {
2490 fn new<P: IpPacket<I>>(socket: S, packet: &P) -> Self {
2491 let src_port =
2492 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port());
2493 Self { socket, src_addr: packet.src_addr(), src_port }
2494 }
2495
2496 fn take_socket<P: IpPacket<I>>(self, packet: &P) -> Option<S> {
2498 let src_port =
2499 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port());
2500 (self.src_addr == packet.src_addr() && self.src_port == src_port).then_some(self.socket)
2501 }
2502
2503 fn update_packet_metadata<CC, BC>(
2504 &self,
2505 core_ctx: &mut CC,
2506 packet_metadata: &mut IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2507 ) where
2508 I: IpLayerIpExt,
2509 S: SocketMetadata<CC>,
2510 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2511 CC: IpLayerIngressContext<I, BC>,
2512 {
2513 packet_metadata.socket_info = Some(self.socket.socket_info(core_ctx));
2514 for mark in BC::marks_to_set_on_ingress() {
2515 *packet_metadata.marks.get_mut(*mark) = self.socket.marks(core_ctx).get(*mark).clone();
2516 }
2517 }
2518}
2519
2520pub(crate) fn reject_type_to_icmpv4_error(reject_type: RejectType) -> Option<Icmpv4Error> {
2521 let error = match reject_type {
2522 RejectType::NetUnreachable => Icmpv4Error::NetUnreachable,
2523 RejectType::ProtoUnreachable => Icmpv4Error::ProtocolUnreachable,
2524 RejectType::PortUnreachable => Icmpv4Error::PortUnreachable,
2525 RejectType::HostUnreachable => Icmpv4Error::HostUnreachable,
2526 RejectType::RoutePolicyFail => Icmpv4Error::NetworkProhibited,
2527 RejectType::RejectRoute => Icmpv4Error::HostProhibited,
2528 RejectType::AdminProhibited => Icmpv4Error::AdminProhibited,
2529 RejectType::TcpReset => return None,
2531 };
2532 Some(error)
2533}
2534
2535pub(crate) fn reject_type_to_icmpv6_error(reject_type: RejectType) -> Option<Icmpv6Error> {
2536 let error = match reject_type {
2537 RejectType::NetUnreachable => Icmpv6Error::NetUnreachable,
2538 RejectType::PortUnreachable => Icmpv6Error::PortUnreachable,
2539 RejectType::HostUnreachable => Icmpv6Error::AddressUnreachable,
2540 RejectType::AdminProhibited => Icmpv6Error::AdminProhibited,
2541 RejectType::RoutePolicyFail => Icmpv6Error::SourceAddressPolicyFailed,
2542 RejectType::RejectRoute => Icmpv6Error::RejectRoute,
2543 RejectType::TcpReset | RejectType::ProtoUnreachable => return None,
2545 };
2546 Some(error)
2547}
2548fn dispatch_receive_ipv4_packet<
2569 'a,
2570 'b,
2571 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2572 CC: IpLayerIngressContext<Ipv4, BC>,
2573>(
2574 core_ctx: &'a mut CC,
2575 bindings_ctx: &'a mut BC,
2576 device: &'b CC::DeviceId,
2577 frame_dst: Option<LocalFrameDestination>,
2578 mut packet: Ipv4Packet<&'a mut [u8]>,
2579 mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2580 receive_meta: ReceiveIpPacketMeta<Ipv4>,
2581) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2582 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2583
2584 let early_demux_result = receive_meta
2587 .transparent_override
2588 .is_none()
2589 .then(|| {
2590 core_ctx.early_demux(
2591 device,
2592 frame_dst,
2593 packet.src_ip(),
2594 packet.dst_ip(),
2595 packet.proto(),
2596 packet.body(),
2597 )
2598 })
2599 .flatten()
2600 .map(|socket| {
2601 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2602 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2603 early_demux_result
2604 });
2605
2606 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2607 bindings_ctx,
2608 &mut packet,
2609 device,
2610 &mut packet_metadata,
2611 );
2612
2613 let marks = packet_metadata.marks;
2614 packet_metadata.acknowledge_drop();
2615
2616 match filter_verdict {
2617 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2618 return Ok(());
2619 }
2620 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2621 return match reject_type_to_icmpv4_error(reject_type) {
2622 Some(icmp_error) => {
2623 match IcmpErrorSender::new(
2624 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2625 ) {
2626 Some(icmp_sender) => Err(icmp_sender),
2627 None => Ok(()),
2628 }
2629 }
2630 None => {
2631 debug!("Unsupported reject type: {:?}", reject_type);
2632 return Ok(());
2633 }
2634 };
2635 }
2636 filter::Verdict::Proceed(filter::Accept) => (),
2637 };
2638
2639 let Some(src_ip) = packet.src_ipv4() else {
2643 debug!(
2644 "dispatch_receive_ipv4_packet: received packet from invalid source {} after the \
2645 LOCAL_INGRESS hook; dropping",
2646 packet.src_ip()
2647 );
2648 core_ctx.increment_both(device, |c| &c.invalid_source);
2649 return Ok(());
2650 };
2651 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2652 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2653 debug!(
2654 "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2655 after the LOCAL_INGRESS hook; dropping"
2656 );
2657 return Ok(());
2658 };
2659
2660 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2661
2662 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2664
2665 let proto = packet.proto();
2666 let (prefix, options, body) = packet.parts_with_body_mut();
2667 let buffer = Buf::new(body, ..);
2668 let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2669 let mut receive_info = LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks };
2670
2671 core_ctx
2672 .dispatch_receive_ip_packet(
2673 bindings_ctx,
2674 device,
2675 src_ip,
2676 dst_ip,
2677 proto,
2678 buffer,
2679 &mut receive_info,
2680 early_demux_socket,
2681 )
2682 .or_else(|icmp_error| {
2683 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2684 Some(icmp_sender) => Err(icmp_sender),
2685 None => Ok(()),
2686 }
2687 })
2688}
2689
2690fn dispatch_receive_ipv6_packet<
2695 'a,
2696 'b,
2697 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2698 CC: IpLayerIngressContext<Ipv6, BC>,
2699>(
2700 core_ctx: &'a mut CC,
2701 bindings_ctx: &'a mut BC,
2702 device: &'b CC::DeviceId,
2703 frame_dst: Option<LocalFrameDestination>,
2704 mut packet: Ipv6Packet<&'a mut [u8]>,
2705 mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2706 meta: ReceiveIpPacketMeta<Ipv6>,
2707) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2708 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2715
2716 let early_demux_result = meta
2719 .transparent_override
2720 .is_none()
2721 .then(|| {
2722 core_ctx.early_demux(
2723 device,
2724 frame_dst,
2725 packet.src_ip(),
2726 packet.dst_ip(),
2727 packet.proto(),
2728 packet.body(),
2729 )
2730 })
2731 .flatten()
2732 .map(|socket| {
2733 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2734 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2735 early_demux_result
2736 });
2737
2738 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2739 bindings_ctx,
2740 &mut packet,
2741 device,
2742 &mut packet_metadata,
2743 );
2744
2745 let marks = packet_metadata.marks;
2746 packet_metadata.acknowledge_drop();
2747
2748 match filter_verdict {
2749 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2750 return Ok(());
2751 }
2752 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2753 return match reject_type_to_icmpv6_error(reject_type) {
2754 Some(icmp_error) => {
2755 match IcmpErrorSender::new(
2756 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2757 ) {
2758 Some(icmp_sender) => Err(icmp_sender),
2759 None => Ok(()),
2760 }
2761 }
2762 None => {
2763 debug!("Unsupported reject type: {:?}", reject_type);
2764 return Ok(());
2765 }
2766 };
2767 }
2768 filter::Verdict::Proceed(filter::Accept) => {}
2769 }
2770
2771 let Some(src_ip) = packet.src_ipv6() else {
2775 debug!(
2776 "dispatch_receive_ipv6_packet: received packet from invalid source {} after the \
2777 LOCAL_INGRESS hook; dropping",
2778 packet.src_ip()
2779 );
2780
2781 core_ctx.increment_both(device, |c| &c.invalid_source);
2782 return Ok(());
2783 };
2784 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2785 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2786 debug!(
2787 "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2788 after the LOCAL_INGRESS hook; dropping"
2789 );
2790 return Ok(());
2791 };
2792
2793 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2794
2795 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2797
2798 let proto = packet.proto();
2799 let (fixed, extension, body) = packet.parts_with_body_mut();
2800 let buffer = Buf::new(body, ..);
2801 let header_info = Ipv6HeaderInfo { fixed, extension };
2802 let mut receive_info = LocalDeliveryPacketInfo { meta, header_info, marks };
2803
2804 core_ctx
2805 .dispatch_receive_ip_packet(
2806 bindings_ctx,
2807 device,
2808 src_ip,
2809 dst_ip,
2810 proto,
2811 buffer,
2812 &mut receive_info,
2813 early_demux_socket,
2814 )
2815 .or_else(|icmp_error| {
2816 let marks = receive_info.marks;
2817 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2818 Some(icmp_sender) => Err(icmp_sender),
2819 None => Ok(()),
2820 }
2821 })
2822}
2823
2824pub(crate) struct IpPacketForwarder<
2831 'a,
2832 I: IpLayerIpExt,
2833 D,
2834 A,
2835 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2836> {
2837 inbound_device: &'a D,
2838 outbound_device: &'a D,
2839 packet_meta: IpLayerPacketMetadata<I, A, BT>,
2840 src_ip: I::RecvSrcAddr,
2841 dst_ip: SpecifiedAddr<I::Addr>,
2842 destination: IpPacketDestination<I, &'a D>,
2843 proto: I::Proto,
2844 parse_meta: ParseMetadata,
2845 frame_dst: Option<LocalFrameDestination>,
2846}
2847
2848impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
2849where
2850 I: IpLayerIpExt,
2851 BC: IpLayerBindingsContext<I, D>,
2852{
2853 fn forward_with_buffer<CC, B>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B)
2855 where
2856 B: BufferMut,
2857 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2858 {
2859 let Self {
2860 inbound_device,
2861 outbound_device,
2862 packet_meta,
2863 src_ip,
2864 dst_ip,
2865 destination,
2866 proto,
2867 parse_meta,
2868 frame_dst,
2869 } = self;
2870
2871 let packet = ForwardedPacket::new(src_ip.get(), dst_ip.get(), proto, parse_meta, buffer);
2872
2873 trace!("forward_with_buffer: forwarding {} packet", I::NAME);
2874
2875 let marks = packet_meta.marks;
2876 match send_ip_frame(
2877 core_ctx,
2878 bindings_ctx,
2879 outbound_device,
2880 destination,
2881 packet,
2882 packet_meta,
2883 Mtu::no_limit(),
2884 ) {
2885 Ok(()) => (),
2886 Err(IpSendFrameError { serializer, error }) => {
2887 match error {
2888 IpSendFrameErrorReason::Device(
2889 SendFrameErrorReason::SizeConstraintsViolation,
2890 ) => {
2891 debug!("failed to forward {} packet: MTU exceeded", I::NAME);
2892 core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
2893 let mtu = core_ctx.get_mtu(inbound_device);
2894 let Some(err) = I::IcmpError::mtu_exceeded(mtu) else {
2896 return;
2897 };
2898 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2901 return;
2902 };
2903
2904 let Some(dst_ip) = SocketIpAddr::new(dst_ip.get()) else {
2905 return;
2906 };
2907
2908 core_ctx.send_icmp_error_message(
2918 bindings_ctx,
2919 Some(inbound_device),
2920 frame_dst,
2921 src_ip,
2922 dst_ip,
2923 serializer.into_buffer(),
2924 err,
2925 parse_meta.header_len(),
2926 proto,
2927 &marks,
2928 );
2929 }
2930 IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
2931 | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
2932 | IpSendFrameErrorReason::Device(
2933 SendFrameErrorReason::AddressResolutionFailed,
2934 )
2935 | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
2936 }
2937 debug!("failed to forward {} packet: {error:?}", I::NAME);
2938 }
2939 }
2940 }
2941}
2942
2943pub(crate) enum ForwardingAction<
2945 'a,
2946 I: IpLayerIpExt,
2947 D,
2948 A,
2949 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2950> {
2951 SilentlyDrop,
2953 Forward(IpPacketForwarder<'a, I, D, A, BT>),
2955 DropWithIcmpError(IcmpErrorSender<'a, I, D>),
2958}
2959
2960impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
2961where
2962 I: IpLayerIpExt,
2963 BC: IpLayerBindingsContext<I, D>,
2964{
2965 pub(crate) fn perform_action_with_buffer<CC, B>(
2967 self,
2968 core_ctx: &mut CC,
2969 bindings_ctx: &mut BC,
2970 buffer: B,
2971 ) where
2972 B: BufferMut,
2973 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2974 {
2975 match self {
2976 ForwardingAction::SilentlyDrop => {}
2977 ForwardingAction::Forward(forwarder) => {
2978 forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer)
2979 }
2980 ForwardingAction::DropWithIcmpError(icmp_sender) => {
2981 icmp_sender.send(core_ctx, bindings_ctx, buffer)
2982 }
2983 }
2984 }
2985}
2986
2987pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
2989 core_ctx: &'a mut CC,
2990 mut packet: I::Packet<&'a mut [u8]>,
2991 mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2992 minimum_ttl: Option<NonZeroU8>,
2993 inbound_device: &'b CC::DeviceId,
2994 outbound_device: &'b CC::DeviceId,
2995 destination: IpPacketDestination<I, &'b CC::DeviceId>,
2996 frame_dst: Option<LocalFrameDestination>,
2997 src_ip: I::RecvSrcAddr,
2998 dst_ip: SpecifiedAddr<I::Addr>,
2999) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
3000where
3001 I: IpLayerIpExt,
3002 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3003 CC: IpLayerForwardingContext<I, BC>,
3004{
3005 const DEFAULT_MIN_TTL: u8 = 1;
3010 let minimum_ttl = minimum_ttl.map(NonZeroU8::get).unwrap_or(DEFAULT_MIN_TTL);
3011 let ttl = packet.ttl();
3012 if ttl <= minimum_ttl {
3013 debug!(
3014 "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
3015 I::NAME
3016 );
3017 if ttl > 1 {
3029 packet_meta.acknowledge_drop();
3030 return ForwardingAction::SilentlyDrop;
3031 }
3032
3033 core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
3034
3035 let marks = packet_meta.marks;
3036 packet_meta.acknowledge_drop();
3037
3038 match IcmpErrorSender::new(
3040 core_ctx,
3041 I::IcmpError::ttl_expired(),
3042 &packet,
3043 frame_dst,
3044 inbound_device,
3045 marks,
3046 ) {
3047 Some(icmp_sender) => return ForwardingAction::DropWithIcmpError(icmp_sender),
3048 None => return ForwardingAction::SilentlyDrop,
3049 }
3050 }
3051
3052 trace!("determine_ip_packet_forwarding_action: adequate TTL");
3053
3054 let maybe_ipv6_packet_action = I::map_ip_in(
3060 &packet,
3061 |_packet| None,
3062 |packet| {
3063 Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
3064 },
3065 );
3066 match maybe_ipv6_packet_action {
3067 None => {} Some(Ipv6PacketAction::_Discard) => {
3069 core_ctx.increment_both(inbound_device, |c| {
3070 #[derive(GenericOverIp)]
3071 #[generic_over_ip(I, Ip)]
3072 struct InCounters<'a, I: IpLayerIpExt>(
3073 &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<Counter>,
3074 );
3075 I::map_ip_in::<_, _>(
3076 InCounters(&c.version_rx),
3077 |_counters| {
3078 unreachable!(
3079 "`I` must be `Ipv6` because we're handling IPv6 extension headers"
3080 )
3081 },
3082 |InCounters(counters)| &counters.extension_header_discard,
3083 )
3084 });
3085 trace!(
3086 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3087 discarding packet"
3088 );
3089 packet_meta.acknowledge_drop();
3090 return ForwardingAction::SilentlyDrop;
3091 }
3092 Some(Ipv6PacketAction::Continue) => {
3093 trace!(
3094 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3095 forwarding packet"
3096 );
3097 }
3098 Some(Ipv6PacketAction::ProcessFragment) => {
3099 unreachable!(
3100 "When forwarding packets, we should only ever look at the hop by hop \
3101 options extension header (if present)"
3102 )
3103 }
3104 };
3105
3106 match core_ctx.filter_handler().forwarding_hook(
3107 I::as_filter_packet(&mut packet),
3108 inbound_device,
3109 outbound_device,
3110 &mut packet_meta,
3111 ) {
3112 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3113 packet_meta.acknowledge_drop();
3114 trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
3115 return ForwardingAction::SilentlyDrop;
3116 }
3117 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
3118 packet_meta.acknowledge_drop();
3120 trace!(
3121 "determine_ip_packet_forwarding_action: filter verdict: Reject({:?})",
3122 reject_type
3123 );
3124 return ForwardingAction::SilentlyDrop;
3125 }
3126 filter::Verdict::Proceed(filter::Accept) => {}
3127 }
3128
3129 packet.set_ttl(ttl - 1);
3130 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
3131 ForwardingAction::Forward(IpPacketForwarder {
3132 inbound_device,
3133 outbound_device,
3134 packet_meta,
3135 src_ip,
3136 dst_ip,
3137 destination,
3138 proto,
3139 parse_meta,
3140 frame_dst,
3141 })
3142}
3143
3144pub(crate) fn send_ip_frame<I, CC, BC, S>(
3145 core_ctx: &mut CC,
3146 bindings_ctx: &mut BC,
3147 device: &CC::DeviceId,
3148 destination: IpPacketDestination<I, &CC::DeviceId>,
3149 mut body: S,
3150 mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3151 limit_mtu: Mtu,
3152) -> Result<(), IpSendFrameError<S>>
3153where
3154 I: IpLayerIpExt,
3155 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3156 CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
3157 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>,
3158{
3159 let (verdict, proof) = core_ctx.filter_handler().egress_hook(
3160 bindings_ctx,
3161 &mut body,
3162 device,
3163 &mut packet_metadata,
3164 );
3165 match verdict {
3166 filter::Verdict::Stop(filter::DropPacket) => {
3167 packet_metadata.acknowledge_drop();
3168 return Ok(());
3169 }
3170 filter::Verdict::Proceed(filter::Accept) => {}
3171 }
3172
3173 let (conntrack_connection_and_direction, tx_metadata, marks, _socket_cookie) =
3177 packet_metadata.into_parts();
3178 let conntrack_entry = if device.is_loopback() {
3179 conntrack_connection_and_direction
3180 .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
3181 } else {
3182 None
3183 };
3184
3185 let mut device_layer_marks = Marks::default();
3186 for mark in BC::marks_to_keep_on_egress() {
3187 *device_layer_marks.get_mut(*mark) = *marks.get(*mark);
3188 }
3189
3190 let device_ip_layer_metadata =
3191 DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks: device_layer_marks };
3192
3193 if !device.is_loopback()
3197 && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
3198 || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
3199 {
3200 core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
3201 return Err(IpSendFrameError {
3202 serializer: body,
3203 error: IpSendFrameErrorReason::IllegalLoopbackAddress,
3204 });
3205 }
3206
3207 let mtu = limit_mtu.min(core_ctx.get_mtu(device));
3209
3210 let body = body.with_size_limit(mtu.into());
3211
3212 let fits_mtu = match body.serialize_new_buf(
3213 &mut NetworkSerializationContext::default(),
3214 PacketConstraints::UNCONSTRAINED,
3215 AlwaysFailBufferAlloc,
3216 ) {
3217 Err(SerializeError::Alloc(())) => true,
3220 Err(SerializeError::SizeLimitExceeded) => false,
3222 };
3223
3224 if fits_mtu {
3225 return core_ctx
3226 .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
3227 .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
3228 serializer: serializer.into_inner(),
3229 error: error.into(),
3230 });
3231 }
3232
3233 core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
3236
3237 let mut device_ip_layer_metadata = Some(device_ip_layer_metadata);
3239 let body = body.into_inner();
3240 let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
3241 Ok(mut fragmenter) => loop {
3242 let (fragment, has_more) = match fragmenter.next() {
3243 None => break Ok(()),
3244 Some(f) => f,
3245 };
3246
3247 let device_ip_layer_metadata = if has_more {
3252 let device_ip_layer_metadata = device_ip_layer_metadata.as_ref().unwrap();
3254 DeviceIpLayerMetadata {
3255 conntrack_entry: device_ip_layer_metadata.conntrack_entry.clone(),
3256 tx_metadata: Default::default(),
3257 marks: device_ip_layer_metadata.marks,
3258 }
3259 } else {
3260 device_ip_layer_metadata.take().unwrap()
3262 };
3263
3264 match core_ctx.send_ip_frame(
3265 bindings_ctx,
3266 device,
3267 destination.clone(),
3268 device_ip_layer_metadata,
3269 fragment,
3270 proof.clone_for_fragmentation(),
3271 ) {
3272 Ok(()) => {
3273 core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
3274 }
3275 Err(ErrorAndSerializer { serializer: _, error }) => {
3276 core_ctx
3277 .increment_both(device, |c| &c.fragmentation.error_fragmented_serializer);
3278 break Err(error);
3279 }
3280 }
3281 },
3282 Err(e) => {
3283 core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
3284 Err(SendFrameErrorReason::SizeConstraintsViolation)
3285 }
3286 };
3287 result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
3288}
3289
3290struct AlwaysFailBufferAlloc;
3295
3296impl LayoutBufferAlloc<Never> for AlwaysFailBufferAlloc {
3297 type Error = ();
3298 fn layout_alloc(
3299 self,
3300 _prefix: usize,
3301 _body: usize,
3302 _suffix: usize,
3303 ) -> Result<Never, Self::Error> {
3304 Err(())
3305 }
3306}
3307
3308macro_rules! drop_packet_and_undo_parse {
3317 ($packet:expr, $buffer:expr) => {{
3318 let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
3319 $buffer.undo_parse(meta);
3320 (src_ip, dst_ip, proto, meta)
3321 }};
3322}
3323
3324enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
3327 Done,
3330
3331 NotNeeded(I::Packet<&'a mut [u8]>),
3334
3335 Reassembled(Vec<u8>),
3338}
3339
3340fn process_fragment<'a, I, CC, BC>(
3346 core_ctx: &mut CC,
3347 bindings_ctx: &mut BC,
3348 device: &CC::DeviceId,
3349 packet: I::Packet<&'a mut [u8]>,
3350) -> ProcessFragmentResult<'a, I>
3351where
3352 I: IpLayerIpExt,
3353 for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3354 CC: IpLayerIngressContext<I, BC>,
3355 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3356{
3357 match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3358 FragmentProcessingState::NotNeeded(packet) => {
3360 trace!("receive_ip_packet: not fragmented");
3361 ProcessFragmentResult::NotNeeded(packet)
3362 }
3363 FragmentProcessingState::Ready { key, packet_len } => {
3365 trace!("receive_ip_packet: fragmented, ready for reassembly");
3366 let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3368
3369 let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3371 core_ctx,
3372 bindings_ctx,
3373 &key,
3374 buffer.buffer_view_mut(),
3375 ) {
3376 Ok(()) => ProcessFragmentResult::Reassembled(buffer.into_inner()),
3378 Err(e) => {
3379 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3380 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3381 ProcessFragmentResult::Done
3382 }
3383 };
3384 reassemble_result
3385 }
3386 FragmentProcessingState::NeedMoreFragments => {
3389 core_ctx.increment_both(device, |c| &c.need_more_fragments);
3390 trace!("receive_ip_packet: fragmented, need more before reassembly");
3391 ProcessFragmentResult::Done
3392 }
3393 FragmentProcessingState::InvalidFragment => {
3395 core_ctx.increment_both(device, |c| &c.invalid_fragment);
3396 trace!("receive_ip_packet: fragmented, invalid");
3397 ProcessFragmentResult::Done
3398 }
3399 FragmentProcessingState::OutOfMemory => {
3400 core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3401 trace!("receive_ip_packet: fragmented, dropped because OOM");
3402 ProcessFragmentResult::Done
3403 }
3404 }
3405}
3406
3407macro_rules! try_parse_ip_packet {
3417 ($buffer:expr) => {{
3418 let p_len = $buffer.prefix_len();
3419 let s_len = $buffer.suffix_len();
3420
3421 let result = $buffer.parse_mut();
3422
3423 if let Err(err) = result {
3424 let n_p_len = $buffer.prefix_len();
3426 let n_s_len = $buffer.suffix_len();
3427
3428 if n_p_len > p_len {
3429 $buffer.grow_front(n_p_len - p_len);
3430 }
3431
3432 if n_s_len > s_len {
3433 $buffer.grow_back(n_s_len - s_len);
3434 }
3435
3436 Err(err)
3437 } else {
3438 result
3439 }
3440 }};
3441}
3442
3443macro_rules! clone_packet_for_mcast_forwarding {
3461 {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3462 let mut $new_data = $packet.to_vec();
3463 let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3464 let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3465 };
3466}
3467
3468pub fn receive_ipv4_packet<
3473 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3474 B: BufferMut,
3475 CC: IpLayerIngressContext<Ipv4, BC>,
3476>(
3477 core_ctx: &mut CC,
3478 bindings_ctx: &mut BC,
3479 device: &CC::DeviceId,
3480 frame_dst: Option<LocalFrameDestination>,
3481 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3482 parsing_context: NetworkParsingContext,
3483 buffer: B,
3484) {
3485 if !core_ctx.is_ip_device_enabled(&device) {
3486 return;
3487 }
3488
3489 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3492
3493 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3494 trace!("receive_ip_packet({device:?})");
3495
3496 let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3497 Ok(packet) => packet,
3498 Err(ParseError::Format)
3499 | Err(ParseError::Checksum)
3500 | Err(ParseError::NotSupported)
3501 | Err(ParseError::NotExpected) => {
3502 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3503 return;
3504 }
3505 };
3506
3507 if packet.src_ipv4().is_none() {
3511 debug!(
3512 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3513 packet.src_ip()
3514 );
3515 core_ctx.increment_both(device, |c| &c.invalid_source);
3516 return;
3517 };
3518 if !packet.dst_ip().is_specified() {
3519 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3520 debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3521 return;
3522 };
3523
3524 if !device.is_loopback()
3528 && (Ipv4::LOOPBACK_SUBNET.contains(&packet.src_ip())
3529 || Ipv4::LOOPBACK_SUBNET.contains(&packet.dst_ip()))
3530 {
3531 debug!(
3532 "receive_ipv4_packet: received loopback packet (src={}, dst={}) \
3533 on non-loopback interface; dropping",
3534 packet.src_ip(),
3535 packet.dst_ip(),
3536 );
3537 return;
3538 }
3539
3540 let mut packet = match process_fragment(core_ctx, bindings_ctx, device, packet) {
3553 ProcessFragmentResult::Done => return,
3554 ProcessFragmentResult::NotNeeded(packet) => packet,
3555 ProcessFragmentResult::Reassembled(buf) => {
3556 let buf = Buf::new(buf, ..);
3557 buffer = packet::Either::B(buf);
3558
3559 match buffer.parse_mut() {
3560 Ok(packet) => packet,
3561 Err(err) => {
3562 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3563 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3564 return;
3565 }
3566 }
3567 }
3568 };
3569
3570 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3573 core_ctx,
3574 device,
3575 device_ip_layer_metadata,
3576 );
3577 let mut filter = core_ctx.filter_handler();
3578 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3579 filter::Verdict::Proceed(filter::Accept) => {}
3580 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
3581 packet_metadata.acknowledge_drop();
3582 return;
3583 }
3584 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
3585 addr,
3586 port,
3587 }) => {
3588 drop(filter);
3591
3592 let Some(addr) = SpecifiedAddr::new(addr) else {
3593 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3594 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3595 return;
3596 };
3597
3598 let receive_meta = ReceiveIpPacketMeta {
3599 broadcast: None,
3603 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3604 parsing_context,
3605 };
3606
3607 dispatch_receive_ipv4_packet(
3611 core_ctx,
3612 bindings_ctx,
3613 device,
3614 frame_dst,
3615 packet,
3616 packet_metadata,
3617 receive_meta,
3618 )
3619 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3620 return;
3621 }
3622 }
3623 drop(filter);
3626
3627 let Some(src_ip) = packet.src_ipv4() else {
3628 core_ctx.increment_both(device, |c| &c.invalid_source);
3629 debug!(
3630 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3631 packet.src_ip()
3632 );
3633 return;
3634 };
3635
3636 let action = receive_ipv4_packet_action(
3637 core_ctx,
3638 bindings_ctx,
3639 device,
3640 &packet,
3641 frame_dst,
3642 &packet_metadata.marks,
3643 );
3644 match action {
3645 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3646 let mut packet_metadata = Some(packet_metadata);
3653 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3654 clone_packet_for_mcast_forwarding! {
3655 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3656 };
3657 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3658 core_ctx,
3659 copy_of_packet,
3660 packet_metadata.take().unwrap_or_default(),
3661 Some(*min_ttl),
3662 device,
3663 &output_interface,
3664 IpPacketDestination::from_addr(dst_ip),
3665 frame_dst,
3666 src_ip,
3667 dst_ip,
3668 )
3669 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3670 }
3671
3672 if let Some(address_status) = address_status {
3674 let receive_meta = ReceiveIpPacketMeta {
3675 broadcast: address_status.to_broadcast_marker(),
3676 transparent_override: None,
3677 parsing_context,
3678 };
3679 dispatch_receive_ipv4_packet(
3680 core_ctx,
3681 bindings_ctx,
3682 device,
3683 frame_dst,
3684 packet,
3685 packet_metadata.take().unwrap_or_default(),
3686 receive_meta,
3687 )
3688 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3689 }
3690 }
3691 ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
3692 match internal_forwarding {
3695 InternalForwarding::Used(outbound_device) => {
3696 core_ctx.increment_both(device, |c| &c.forward);
3697 match core_ctx.filter_handler().forwarding_hook(
3698 &mut packet,
3699 device,
3700 &outbound_device,
3701 &mut packet_metadata,
3702 ) {
3703 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3704 packet_metadata.acknowledge_drop();
3705 return;
3706 }
3707 filter::Verdict::Stop(filter::DropOrReject::Reject(_reject_type)) => {
3708 packet_metadata.acknowledge_drop();
3710 return;
3711 }
3712 filter::Verdict::Proceed(filter::Accept) => {}
3713 }
3714 }
3715 InternalForwarding::NotUsed => {}
3716 }
3717
3718 let receive_meta = ReceiveIpPacketMeta {
3719 broadcast: address_status.to_broadcast_marker(),
3720 transparent_override: None,
3721 parsing_context,
3722 };
3723 dispatch_receive_ipv4_packet(
3724 core_ctx,
3725 bindings_ctx,
3726 device,
3727 frame_dst,
3728 packet,
3729 packet_metadata,
3730 receive_meta,
3731 )
3732 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3733 }
3734 ReceivePacketAction::Forward {
3735 original_dst,
3736 dst: Destination { device: dst_device, next_hop },
3737 } => {
3738 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3739 core_ctx,
3740 packet,
3741 packet_metadata,
3742 None,
3743 device,
3744 &dst_device,
3745 IpPacketDestination::from_next_hop(next_hop, original_dst),
3746 frame_dst,
3747 src_ip,
3748 original_dst,
3749 )
3750 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3751 }
3752 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3753 debug!("received IPv4 packet with no known route to destination {}", dst_ip);
3754
3755 let marks = packet_metadata.marks;
3756 packet_metadata.acknowledge_drop();
3757
3758 if let Some(sender) = IcmpErrorSender::new(
3759 core_ctx,
3760 Icmpv4Error::NetUnreachable,
3761 &packet,
3762 frame_dst,
3763 device,
3764 marks,
3765 ) {
3766 sender.send(core_ctx, bindings_ctx, buffer);
3767 }
3768 }
3769 ReceivePacketAction::Drop { reason } => {
3770 let src_ip = packet.src_ip();
3771 let dst_ip = packet.dst_ip();
3772 packet_metadata.acknowledge_drop();
3773 core_ctx.increment_both(device, |c| &c.dropped);
3774 debug!(
3775 "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
3776 {device:?}: {reason:?}",
3777 );
3778 }
3779 }
3780}
3781
3782fn handle_ipv6_parse_error<BC, B, CC>(
3783 core_ctx: &mut CC,
3784 bindings_ctx: &mut BC,
3785 device: &CC::DeviceId,
3786 frame_dst: Option<LocalFrameDestination>,
3787 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3788 mut buffer: B,
3789 error: Ipv6ParseError,
3790) where
3791 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3792 B: BufferMut,
3793 CC: IpLayerIngressContext<Ipv6, BC>,
3794{
3795 let Ipv6ParseError::ParameterProblem { src_ip, dst_ip, code, pointer, must_send_icmp, action } =
3801 error
3802 else {
3803 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3804 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
3805 return;
3806 };
3807 if !must_send_icmp || !action.should_send_icmp(&dst_ip) {
3808 return;
3809 }
3810 core_ctx.increment_both(device, |c| &c.parameter_problem);
3811 let dst_ip = match SocketIpAddr::new(dst_ip) {
3812 Some(ip) => ip,
3813 None => {
3814 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3815 debug!("receive_ipv6_packet: Dropping packet with unspecified destination IP");
3816 return;
3817 }
3818 };
3819
3820 let src_ip = match Ipv6SourceAddr::new(src_ip) {
3821 None => {
3822 core_ctx.increment_both(device, |c| &c.invalid_source);
3823 return;
3824 }
3825 Some(Ipv6SourceAddr::Unspecified) => {
3826 core_ctx.increment_both(device, |c| &c.unspecified_source);
3827 return;
3828 }
3829 Some(Ipv6SourceAddr::Unicast(src_ip)) => {
3830 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
3831 }
3832 };
3833
3834 let raw_packet: Ipv6PacketRaw<_> = match try_parse_ip_packet!(buffer) {
3837 Ok(packet) => packet,
3838 Err(error) => {
3839 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3840 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
3841 return;
3842 }
3843 };
3844 let proto = match raw_packet.proto() {
3845 Ok(proto) => proto,
3846 Err(error) => {
3847 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3848 debug!("receive_ipv6_packet: Failed to get protocol from IPv6 packet: {:?}", error);
3849 return;
3850 }
3851 };
3852 let parse_metadata = raw_packet.parse_metadata();
3853 let header_len = parse_metadata.header_len();
3854 buffer.undo_parse(parse_metadata);
3855
3856 let err = Icmpv6Error::ParameterProblem {
3857 code,
3858 pointer,
3859 allow_dst_multicast: action.should_send_icmp_to_multicast(),
3860 };
3861
3862 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3863 core_ctx,
3864 bindings_ctx,
3865 Some(device),
3866 frame_dst,
3867 src_ip,
3868 dst_ip,
3869 buffer,
3870 err,
3871 header_len,
3872 proto,
3873 &device_ip_layer_metadata.marks,
3874 );
3875}
3876
3877pub fn receive_ipv6_packet<
3882 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3883 B: BufferMut,
3884 CC: IpLayerIngressContext<Ipv6, BC>,
3885>(
3886 core_ctx: &mut CC,
3887 bindings_ctx: &mut BC,
3888 device: &CC::DeviceId,
3889 frame_dst: Option<LocalFrameDestination>,
3890 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3891 parsing_context: NetworkParsingContext,
3892 buffer: B,
3893) {
3894 if !core_ctx.is_ip_device_enabled(&device) {
3895 return;
3896 }
3897
3898 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3901
3902 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3903 trace!("receive_ipv6_packet({:?})", device);
3904
3905 let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
3906 Ok(packet) => packet,
3907 Err(error) => {
3908 handle_ipv6_parse_error(
3909 core_ctx,
3910 bindings_ctx,
3911 device,
3912 frame_dst,
3913 device_ip_layer_metadata,
3914 buffer,
3915 error,
3916 );
3917 return;
3918 }
3919 };
3920
3921 trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
3922
3923 if packet.src_ipv6().is_none() {
3929 debug!(
3930 "receive_ipv6_packet: received packet from invalid source {}; dropping",
3931 packet.src_ip()
3932 );
3933 core_ctx.increment_both(device, |c| &c.invalid_source);
3934 return;
3935 };
3936 if !packet.dst_ip().is_specified() {
3937 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3938 debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
3939 return;
3940 };
3941
3942 if !device.is_loopback()
3950 && (Ipv6::LOOPBACK_SUBNET.contains(&packet.src_ip())
3951 || Ipv6::LOOPBACK_SUBNET.contains(&packet.dst_ip()))
3952 {
3953 debug!(
3954 "receive_ipv6_packet: received loopback packet (src={}, dst={}) \
3955 on non-loopback interface; dropping",
3956 packet.src_ip(),
3957 packet.dst_ip(),
3958 );
3959 return;
3960 }
3961
3962 let (mut packet, delivery_extension_header_action) =
3973 match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
3974 Ipv6PacketAction::_Discard => {
3975 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3976 trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
3977 return;
3978 }
3979 Ipv6PacketAction::Continue => {
3980 trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
3981 (packet, Some(Ipv6PacketAction::Continue))
3982 }
3983 Ipv6PacketAction::ProcessFragment => {
3984 trace!(
3985 "receive_ipv6_packet: handled IPv6 extension headers: handling \
3986 fragmented packet"
3987 );
3988
3989 match process_fragment(core_ctx, bindings_ctx, device, packet) {
4001 ProcessFragmentResult::Done => return,
4002 ProcessFragmentResult::NotNeeded(packet) => {
4003 (packet, Some(Ipv6PacketAction::Continue))
4018 }
4019 ProcessFragmentResult::Reassembled(buf) => {
4020 let buf = Buf::new(buf, ..);
4021 buffer = packet::Either::B(buf);
4022
4023 match buffer.parse_mut() {
4024 Ok(packet) => (packet, None),
4025 Err(err) => {
4026 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4027 debug!(
4028 "receive_ip_packet: fragmented, failed to reassemble: {:?}",
4029 err
4030 );
4031 return;
4032 }
4033 }
4034 }
4035 }
4036 }
4037 };
4038
4039 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
4040 core_ctx,
4041 device,
4042 device_ip_layer_metadata,
4043 );
4044 let mut filter = core_ctx.filter_handler();
4045
4046 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
4047 filter::Verdict::Proceed(filter::Accept) => {}
4048 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
4049 packet_metadata.acknowledge_drop();
4050 return;
4051 }
4052 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
4053 addr,
4054 port,
4055 }) => {
4056 drop(filter);
4059
4060 let Some(addr) = SpecifiedAddr::new(addr) else {
4061 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4062 debug!("cannot perform transparent delivery to unspecified destination; dropping");
4063 return;
4064 };
4065
4066 let receive_meta = ReceiveIpPacketMeta {
4067 broadcast: None,
4068 transparent_override: Some(TransparentLocalDelivery { addr, port }),
4069 parsing_context,
4070 };
4071
4072 dispatch_receive_ipv6_packet(
4076 core_ctx,
4077 bindings_ctx,
4078 device,
4079 frame_dst,
4080 packet,
4081 packet_metadata,
4082 receive_meta,
4083 )
4084 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4085 return;
4086 }
4087 }
4088 drop(filter);
4091
4092 let Some(src_ip) = packet.src_ipv6() else {
4093 debug!(
4094 "receive_ipv6_packet: received packet from invalid source {}; dropping",
4095 packet.src_ip()
4096 );
4097 core_ctx.increment_both(device, |c| &c.invalid_source);
4098 return;
4099 };
4100
4101 match receive_ipv6_packet_action(
4102 core_ctx,
4103 bindings_ctx,
4104 device,
4105 &packet,
4106 frame_dst,
4107 &packet_metadata.marks,
4108 ) {
4109 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
4110 let mut packet_metadata = Some(packet_metadata);
4117 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
4118 clone_packet_for_mcast_forwarding! {
4119 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
4120 };
4121 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4122 core_ctx,
4123 copy_of_packet,
4124 packet_metadata.take().unwrap_or_default(),
4125 Some(*min_ttl),
4126 device,
4127 &output_interface,
4128 IpPacketDestination::from_addr(dst_ip),
4129 frame_dst,
4130 src_ip,
4131 dst_ip,
4132 )
4133 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
4134 }
4135
4136 if let Some(_) = address_status {
4138 let receive_meta = ReceiveIpPacketMeta {
4139 broadcast: None,
4140 transparent_override: None,
4141 parsing_context,
4142 };
4143
4144 dispatch_receive_ipv6_packet(
4145 core_ctx,
4146 bindings_ctx,
4147 device,
4148 frame_dst,
4149 packet,
4150 packet_metadata.take().unwrap_or_default(),
4151 receive_meta,
4152 )
4153 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4154 }
4155 }
4156 ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
4157 trace!("receive_ipv6_packet: delivering locally");
4158
4159 let action = if let Some(action) = delivery_extension_header_action {
4160 action
4161 } else {
4162 ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
4163 };
4164 match action {
4165 Ipv6PacketAction::_Discard => {
4166 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4167 trace!(
4168 "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
4169 );
4170 packet_metadata.acknowledge_drop();
4171 }
4172 Ipv6PacketAction::Continue => {
4173 trace!(
4174 "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
4175 );
4176
4177 match internal_forwarding {
4180 InternalForwarding::Used(outbound_device) => {
4181 core_ctx.increment_both(device, |c| &c.forward);
4182 match core_ctx.filter_handler().forwarding_hook(
4183 &mut packet,
4184 device,
4185 &outbound_device,
4186 &mut packet_metadata,
4187 ) {
4188 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
4189 packet_metadata.acknowledge_drop();
4190 return;
4191 }
4192 filter::Verdict::Stop(filter::DropOrReject::Reject(
4193 _reject_type,
4194 )) => {
4195 packet_metadata.acknowledge_drop();
4197 return;
4198 }
4199 filter::Verdict::Proceed(filter::Accept) => {}
4200 }
4201 }
4202 InternalForwarding::NotUsed => {}
4203 }
4204
4205 let meta = ReceiveIpPacketMeta {
4206 broadcast: None,
4207 transparent_override: None,
4208 parsing_context,
4209 };
4210 dispatch_receive_ipv6_packet(
4211 core_ctx,
4212 bindings_ctx,
4213 device,
4214 frame_dst,
4215 packet,
4216 packet_metadata,
4217 meta,
4218 )
4219 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4220 }
4221 Ipv6PacketAction::ProcessFragment => {
4222 debug!("receive_ipv6_packet: found fragment header after reassembly; dropping");
4223 packet_metadata.acknowledge_drop();
4224 }
4225 }
4226 }
4227 ReceivePacketAction::Forward {
4228 original_dst,
4229 dst: Destination { device: dst_device, next_hop },
4230 } => {
4231 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4232 core_ctx,
4233 packet,
4234 packet_metadata,
4235 None,
4236 device,
4237 &dst_device,
4238 IpPacketDestination::from_next_hop(next_hop, original_dst),
4239 frame_dst,
4240 src_ip,
4241 original_dst,
4242 )
4243 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
4244 }
4245 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
4246 let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
4247 drop_packet_and_undo_parse!(packet, buffer);
4248 debug!("received IPv6 packet with no known route to destination {}", dst_ip);
4249 let marks = packet_metadata.marks;
4250 packet_metadata.acknowledge_drop();
4251
4252 let src_ip = match src_ip {
4253 Ipv6SourceAddr::Unspecified => {
4254 core_ctx.increment_both(device, |c| &c.unspecified_source);
4255 return;
4256 }
4257 Ipv6SourceAddr::Unicast(src_ip) => {
4258 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
4259 }
4260 };
4261
4262 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
4263 core_ctx,
4264 bindings_ctx,
4265 Some(device),
4266 frame_dst,
4267 src_ip,
4268 SocketIpAddr::new_from_witness(dst_ip),
4269 buffer,
4270 Icmpv6Error::NetUnreachable,
4271 meta.header_len(),
4272 proto,
4273 &marks,
4274 );
4275 }
4276 ReceivePacketAction::Drop { reason } => {
4277 core_ctx.increment_both(device, |c| &c.dropped);
4278 let src_ip = packet.src_ip();
4279 let dst_ip = packet.dst_ip();
4280 packet_metadata.acknowledge_drop();
4281 debug!(
4282 "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
4283 {device:?}: {reason:?}",
4284 );
4285 }
4286 }
4287}
4288
4289#[derive(Debug, PartialEq)]
4291pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
4292 Deliver {
4294 address_status: I::AddressStatus,
4296 internal_forwarding: InternalForwarding<DeviceId>,
4299 },
4300
4301 Forward {
4303 original_dst: SpecifiedAddr<I::Addr>,
4305 dst: Destination<I::Addr, DeviceId>,
4307 },
4308
4309 MulticastForward {
4317 targets: MulticastRouteTargets<DeviceId>,
4319 address_status: Option<I::AddressStatus>,
4322 dst_ip: SpecifiedAddr<I::Addr>,
4324 },
4325
4326 SendNoRouteToDest {
4332 dst: NonMappedAddr<SpecifiedAddr<I::Addr>>,
4334 },
4335
4336 #[allow(missing_docs)]
4340 Drop { reason: DropReason },
4341}
4342
4343fn choose_highest_priority_address_status<I: IpLayerIpExt>(
4346 address_statuses: impl Iterator<Item = I::AddressStatus>,
4347) -> Option<I::AddressStatus> {
4348 address_statuses.max_by_key(|status| {
4349 #[derive(GenericOverIp)]
4350 #[generic_over_ip(I, Ip)]
4351 struct Wrap<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
4352 I::map_ip_in(
4353 Wrap(status),
4354 |Wrap(v4_status)| match v4_status {
4355 Ipv4PresentAddressStatus::UnicastTentative => 0,
4356 _ => 1,
4357 },
4358 |Wrap(v6_status)| match v6_status {
4359 Ipv6PresentAddressStatus::UnicastTentative => 0,
4360 _ => 1,
4361 },
4362 )
4363 })
4364}
4365
4366#[derive(Debug, PartialEq)]
4368pub enum DropReason {
4369 Tentative,
4371 UnspecifiedDestination,
4373 InvalidDestination,
4375 ForwardUnspecifiedSource,
4377 ForwardLinkLocal,
4379 ForwardingDisabledInboundIface,
4382 MulticastNoInterest,
4388}
4389
4390pub fn receive_ipv4_packet_action<BC, CC, B>(
4392 core_ctx: &mut CC,
4393 bindings_ctx: &mut BC,
4394 device: &CC::DeviceId,
4395 packet: &Ipv4Packet<B>,
4396 frame_dst: Option<LocalFrameDestination>,
4397 marks: &Marks,
4398) -> ReceivePacketAction<Ipv4, CC::DeviceId>
4399where
4400 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
4401 CC: IpLayerContext<Ipv4, BC>,
4402 B: SplitByteSlice,
4403{
4404 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4405 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4406 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4407 };
4408
4409 let highest_priority = if device.is_loopback() {
4422 core_ctx.with_address_statuses(dst_ip, |it| {
4423 let it = it.map(|(_device, status)| status);
4424 choose_highest_priority_address_status::<Ipv4>(it)
4425 })
4426 } else {
4427 core_ctx.address_status_for_device(dst_ip, device).into_present()
4428 };
4429 match highest_priority {
4430 Some(
4431 address_status @ (Ipv4PresentAddressStatus::UnicastAssigned
4432 | Ipv4PresentAddressStatus::LoopbackSubnet),
4433 ) => {
4434 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4435 ReceivePacketAction::Deliver {
4436 address_status,
4437 internal_forwarding: InternalForwarding::NotUsed,
4438 }
4439 }
4440 Some(Ipv4PresentAddressStatus::UnicastTentative) => {
4441 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4447 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4448 }
4449
4450 Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4451 receive_ip_multicast_packet_action(
4452 core_ctx,
4453 bindings_ctx,
4454 device,
4455 packet,
4456 Some(address_status),
4457 dst_ip,
4458 frame_dst,
4459 )
4460 }
4461 Some(
4462 address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4463 | Ipv4PresentAddressStatus::SubnetBroadcast),
4464 ) => {
4465 core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
4466 ReceivePacketAction::Deliver {
4467 address_status,
4468 internal_forwarding: InternalForwarding::NotUsed,
4469 }
4470 }
4471 None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4472 core_ctx,
4473 bindings_ctx,
4474 dst_ip,
4475 device,
4476 packet,
4477 frame_dst,
4478 marks,
4479 ),
4480 }
4481}
4482
4483pub fn receive_ipv6_packet_action<BC, CC, B>(
4485 core_ctx: &mut CC,
4486 bindings_ctx: &mut BC,
4487 device: &CC::DeviceId,
4488 packet: &Ipv6Packet<B>,
4489 frame_dst: Option<LocalFrameDestination>,
4490 marks: &Marks,
4491) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4492where
4493 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4494 CC: IpLayerContext<Ipv6, BC>,
4495 B: SplitByteSlice,
4496{
4497 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4498 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4499 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4500 };
4501
4502 let highest_priority = if device.is_loopback() {
4515 core_ctx.with_address_statuses(dst_ip, |it| {
4516 let it = it.map(|(_device, status)| status);
4517 choose_highest_priority_address_status::<Ipv6>(it)
4518 })
4519 } else {
4520 core_ctx.address_status_for_device(dst_ip, device).into_present()
4521 };
4522 match highest_priority {
4523 Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
4524 receive_ip_multicast_packet_action(
4525 core_ctx,
4526 bindings_ctx,
4527 device,
4528 packet,
4529 Some(address_status),
4530 dst_ip,
4531 frame_dst,
4532 )
4533 }
4534 Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
4535 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4536 ReceivePacketAction::Deliver {
4537 address_status,
4538 internal_forwarding: InternalForwarding::NotUsed,
4539 }
4540 }
4541 Some(Ipv6PresentAddressStatus::UnicastTentative) => {
4542 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4573 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4574 }
4575 None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
4576 core_ctx,
4577 bindings_ctx,
4578 dst_ip,
4579 device,
4580 packet,
4581 frame_dst,
4582 marks,
4583 ),
4584 }
4585}
4586
4587fn receive_ip_multicast_packet_action<
4590 I: IpLayerIpExt,
4591 B: SplitByteSlice,
4592 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4593 CC: IpLayerContext<I, BC>,
4594>(
4595 core_ctx: &mut CC,
4596 bindings_ctx: &mut BC,
4597 device: &CC::DeviceId,
4598 packet: &I::Packet<B>,
4599 address_status: Option<I::AddressStatus>,
4600 dst_ip: SpecifiedAddr<I::Addr>,
4601 frame_dst: Option<LocalFrameDestination>,
4602) -> ReceivePacketAction<I, CC::DeviceId> {
4603 let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
4604 core_ctx,
4605 bindings_ctx,
4606 packet,
4607 device,
4608 frame_dst,
4609 );
4610 match (targets, address_status) {
4611 (Some(targets), address_status) => {
4612 if address_status.is_some() {
4613 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4614 }
4615 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
4616 }
4617 (None, Some(address_status)) => {
4618 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4621 ReceivePacketAction::Deliver {
4622 address_status,
4623 internal_forwarding: InternalForwarding::NotUsed,
4624 }
4625 }
4626 (None, None) => {
4627 core_ctx.increment_both(device, |c| &c.multicast_no_interest);
4636 ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
4637 }
4638 }
4639}
4640
4641fn receive_ip_packet_action_common<
4644 I: IpLayerIpExt,
4645 B: SplitByteSlice,
4646 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4647 CC: IpLayerContext<I, BC>,
4648>(
4649 core_ctx: &mut CC,
4650 bindings_ctx: &mut BC,
4651 dst_ip: SpecifiedAddr<I::Addr>,
4652 device_id: &CC::DeviceId,
4653 packet: &I::Packet<B>,
4654 frame_dst: Option<LocalFrameDestination>,
4655 marks: &Marks,
4656) -> ReceivePacketAction<I, CC::DeviceId> {
4657 if dst_ip.is_multicast() {
4658 return receive_ip_multicast_packet_action(
4659 core_ctx,
4660 bindings_ctx,
4661 device_id,
4662 packet,
4663 None,
4664 dst_ip,
4665 frame_dst,
4666 );
4667 }
4668
4669 let Some(dst_ip) = NonMappedAddr::new(dst_ip) else {
4671 return ReceivePacketAction::Drop { reason: DropReason::InvalidDestination };
4672 };
4673
4674 if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
4676 core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
4689 return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
4690 }
4691 let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
4698 return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
4699 };
4700
4701 if let Some(dst_ip) = NonMulticastAddr::new(dst_ip) {
4708 if let Some((outbound_device, address_status)) =
4709 get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
4710 {
4711 return ReceivePacketAction::Deliver {
4712 address_status,
4713 internal_forwarding: InternalForwarding::Used(outbound_device),
4714 };
4715 }
4716 }
4717
4718 if I::map_ip_in(
4733 &packet,
4734 |_| false,
4735 |packet| packet.src_ip().is_link_local() || packet.dst_ip().is_link_local(),
4736 ) {
4737 return ReceivePacketAction::Drop { reason: DropReason::ForwardLinkLocal };
4738 }
4739
4740 match lookup_route_table(
4741 core_ctx,
4742 dst_ip.get(),
4743 RuleInput {
4744 packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
4745 marks,
4746 },
4747 ) {
4748 Some(dst) => {
4749 core_ctx.increment_both(device_id, |c| &c.forward);
4750 ReceivePacketAction::Forward { original_dst: *dst_ip, dst }
4751 }
4752 None => {
4753 core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
4754 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
4755 }
4756 }
4757}
4758
4759fn lookup_route_table<
4761 I: IpLayerIpExt,
4762 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4763 CC: IpStateContext<I, BC>,
4764>(
4765 core_ctx: &mut CC,
4766 dst_ip: I::Addr,
4767 rule_input: RuleInput<'_, I, CC::DeviceId>,
4768) -> Option<Destination<I::Addr, CC::DeviceId>> {
4769 let bound_device = match rule_input.packet_origin {
4770 PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
4771 PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
4772 };
4773 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
4774 match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
4775 match table.lookup(core_ctx, bound_device, dst_ip) {
4776 Some(dst) => ControlFlow::Break(Some(dst)),
4777 None => ControlFlow::Continue(()),
4778 }
4779 }) {
4780 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
4781 inner: dst,
4782 observed_source_address_matcher: _,
4783 })) => dst,
4784 ControlFlow::Break(RuleAction::Unreachable) => None,
4785 ControlFlow::Continue(RuleWalkInfo {
4786 inner: (),
4787 observed_source_address_matcher: _,
4788 }) => None,
4789 }
4790 })
4791}
4792
4793#[derive(Debug, Derivative, Clone)]
4795#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
4796pub enum IpPacketDestination<I: BroadcastIpExt, D> {
4797 Broadcast(I::BroadcastMarker),
4799
4800 Multicast(MulticastAddr<I::Addr>),
4802
4803 Neighbor(SpecifiedAddr<I::Addr>),
4806
4807 Loopback(D),
4810}
4811
4812impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
4813 pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
4815 match MulticastAddr::new(addr.into_addr()) {
4816 Some(mc_addr) => Self::Multicast(mc_addr),
4817 None => Self::Neighbor(addr),
4818 }
4819 }
4820
4821 pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
4823 match next_hop {
4824 NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
4825 NextHop::Gateway(gateway) => Self::Neighbor(gateway),
4826 NextHop::Broadcast(marker) => Self::Broadcast(marker),
4827 }
4828 }
4829}
4830
4831#[derive(Debug, Clone)]
4833pub struct SendIpPacketMeta<I: IpExt, D, Src> {
4834 pub device: D,
4836
4837 pub src_ip: Src,
4839
4840 pub dst_ip: SpecifiedAddr<I::Addr>,
4842
4843 pub destination: IpPacketDestination<I, D>,
4845
4846 pub proto: I::Proto,
4848
4849 pub ttl: Option<NonZeroU8>,
4853
4854 pub mtu: Mtu,
4859
4860 pub dscp_and_ecn: DscpAndEcn,
4862}
4863
4864impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4865 for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
4866{
4867 fn from(
4868 SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
4869 I,
4870 D,
4871 SpecifiedAddr<I::Addr>,
4872 >,
4873 ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
4874 SendIpPacketMeta {
4875 device,
4876 src_ip: Some(src_ip),
4877 dst_ip,
4878 destination,
4879 proto,
4880 ttl,
4881 mtu,
4882 dscp_and_ecn,
4883 }
4884 }
4885}
4886
4887pub trait IpLayerHandler<I: IpExt + FragmentationIpExt + FilterIpExt, BC>:
4893 DeviceIdContext<AnyDevice>
4894{
4895 fn send_ip_packet_from_device<S>(
4898 &mut self,
4899 bindings_ctx: &mut BC,
4900 meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4901 body: S,
4902 ) -> Result<(), IpSendFrameError<S>>
4903 where
4904 S: TransportPacketSerializer<I>,
4905 S::Buffer: BufferMut;
4906
4907 fn send_ip_frame<S>(
4914 &mut self,
4915 bindings_ctx: &mut BC,
4916 device: &Self::DeviceId,
4917 destination: IpPacketDestination<I, &Self::DeviceId>,
4918 body: S,
4919 ) -> Result<(), IpSendFrameError<S>>
4920 where
4921 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>;
4922}
4923
4924impl<
4925 I: IpLayerIpExt,
4926 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
4927 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4928> IpLayerHandler<I, BC> for CC
4929{
4930 fn send_ip_packet_from_device<S>(
4931 &mut self,
4932 bindings_ctx: &mut BC,
4933 meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4934 body: S,
4935 ) -> Result<(), IpSendFrameError<S>>
4936 where
4937 S: TransportPacketSerializer<I>,
4938 S::Buffer: BufferMut,
4939 {
4940 send_ip_packet_from_device(self, bindings_ctx, meta, body, IpLayerPacketMetadata::default())
4941 }
4942
4943 fn send_ip_frame<S>(
4944 &mut self,
4945 bindings_ctx: &mut BC,
4946 device: &Self::DeviceId,
4947 destination: IpPacketDestination<I, &Self::DeviceId>,
4948 body: S,
4949 ) -> Result<(), IpSendFrameError<S>>
4950 where
4951 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>,
4952 {
4953 send_ip_frame(
4954 self,
4955 bindings_ctx,
4956 device,
4957 destination,
4958 body,
4959 IpLayerPacketMetadata::default(),
4960 Mtu::no_limit(),
4961 )
4962 }
4963}
4964
4965pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
4972 core_ctx: &mut CC,
4973 bindings_ctx: &mut BC,
4974 meta: SendIpPacketMeta<
4975 I,
4976 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
4977 Option<SpecifiedAddr<I::Addr>>,
4978 >,
4979 body: S,
4980 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
4981) -> Result<(), IpSendFrameError<S>>
4982where
4983 I: IpLayerIpExt,
4984 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
4985 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4986 S: TransportPacketSerializer<I>,
4987 S::Buffer: BufferMut,
4988{
4989 let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
4990 meta;
4991 core_ctx.increment_both(device, |c| &c.send_ip_packet);
4992 let next_packet_id = gen_ip_packet_id(core_ctx);
4993 let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
4994 let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
4995 let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
4996
4997 #[derive(GenericOverIp)]
4998 #[generic_over_ip(I, Ip)]
4999 struct Wrap<'a, I: IpLayerIpExt> {
5000 builder: &'a mut I::PacketBuilder<NetworkSerializationContext>,
5001 next_packet_id: I::PacketId,
5002 }
5003
5004 I::map_ip::<_, ()>(
5005 Wrap { builder: &mut builder, next_packet_id },
5006 |Wrap { builder, next_packet_id }| {
5007 builder.id(next_packet_id);
5008 },
5009 |Wrap { builder: _, next_packet_id: () }| {
5010 },
5012 );
5013
5014 builder.set_dscp_and_ecn(dscp_and_ecn);
5015
5016 let ip_frame = builder.wrap_body(body);
5017 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
5018 .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
5019}
5020
5021pub trait FilterHandlerProvider<I: FilterIpExt, BT: FilterBindingsTypes>:
5023 IpDeviceAddressIdContext<I, DeviceId: netstack3_base::InterfaceProperties<BT::DeviceClass>>
5024{
5025 type Handler<'a>: filter::FilterHandler<I, BT, DeviceId = Self::DeviceId, WeakAddressId = Self::WeakAddressId>
5027 where
5028 Self: 'a;
5029
5030 fn filter_handler(&mut self) -> Self::Handler<'_>;
5032}
5033
5034#[cfg(any(test, feature = "testutils"))]
5035pub(crate) mod testutil {
5036 use super::*;
5037
5038 use netstack3_base::testutil::{FakeBindingsCtx, FakeCoreCtx, FakeStrongDeviceId};
5039 use netstack3_base::{
5040 AssignedAddrIpExt, NetworkSerializer, SendFrameContext, SendFrameError, SendableFrameMeta,
5041 };
5042
5043 #[derive(Debug, GenericOverIp)]
5045 #[generic_over_ip()]
5046 #[allow(missing_docs)]
5047 pub enum DualStackSendIpPacketMeta<D> {
5048 V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
5049 V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
5050 }
5051
5052 impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5053 for DualStackSendIpPacketMeta<D>
5054 {
5055 fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
5056 #[derive(GenericOverIp)]
5057 #[generic_over_ip(I, Ip)]
5058 struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
5059 use DualStackSendIpPacketMeta::*;
5060 I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
5061 }
5062 }
5063
5064 impl<I: IpExt, S, DeviceId, BC>
5065 SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
5066 for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
5067 {
5068 fn send_meta<SS>(
5069 self,
5070 core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
5071 bindings_ctx: &mut BC,
5072 frame: SS,
5073 ) -> Result<(), SendFrameError<SS>>
5074 where
5075 SS: NetworkSerializer,
5076 SS::Buffer: BufferMut,
5077 {
5078 SendFrameContext::send_frame(
5079 &mut core_ctx.frames,
5080 bindings_ctx,
5081 DualStackSendIpPacketMeta::from(self),
5082 frame,
5083 )
5084 }
5085 }
5086
5087 #[derive(Debug)]
5089 pub struct WrongIpVersion;
5090
5091 impl<D> DualStackSendIpPacketMeta<D> {
5092 pub fn try_as<I: IpExt>(
5095 &self,
5096 ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
5097 #[derive(GenericOverIp)]
5098 #[generic_over_ip(I, Ip)]
5099 struct Wrap<'a, I: IpExt, D>(
5100 Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
5101 );
5102 use DualStackSendIpPacketMeta::*;
5103 let Wrap(dual_stack) = I::map_ip(
5104 self,
5105 |value| {
5106 Wrap(match value {
5107 V4(meta) => Some(meta),
5108 V6(_) => None,
5109 })
5110 },
5111 |value| {
5112 Wrap(match value {
5113 V4(_) => None,
5114 V6(meta) => Some(meta),
5115 })
5116 },
5117 );
5118 dual_stack.ok_or(WrongIpVersion)
5119 }
5120 }
5121
5122 impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
5123 where
5124 I: AssignedAddrIpExt + FilterIpExt,
5125 BC: FilterBindingsContext<DeviceId>,
5126 DeviceId: FakeStrongDeviceId + netstack3_base::InterfaceProperties<BC::DeviceClass>,
5127 {
5128 type Handler<'a>
5129 = filter::testutil::NoopImpl<DeviceId>
5130 where
5131 Self: 'a;
5132
5133 fn filter_handler(&mut self) -> Self::Handler<'_> {
5134 filter::testutil::NoopImpl::default()
5135 }
5136 }
5137
5138 impl<TimerId, Event: Debug, State, FrameMeta> MarksBindingsContext
5139 for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
5140 {
5141 fn marks_to_keep_on_egress() -> &'static [MarkDomain] {
5142 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark1];
5143 &MARKS
5144 }
5145
5146 fn marks_to_set_on_ingress() -> &'static [MarkDomain] {
5147 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark2];
5148 &MARKS
5149 }
5150 }
5151}
5152
5153#[cfg(test)]
5154mod test {
5155 use super::*;
5156
5157 #[test]
5158 fn highest_priority_address_status_v4() {
5159 assert_eq!(
5161 choose_highest_priority_address_status::<Ipv4>(
5162 [
5163 Ipv4PresentAddressStatus::UnicastAssigned,
5164 Ipv4PresentAddressStatus::UnicastTentative
5165 ]
5166 .into_iter()
5167 ),
5168 Some(Ipv4PresentAddressStatus::UnicastAssigned)
5169 )
5170 }
5171
5172 #[test]
5173 fn highest_priority_address_status_v6() {
5174 assert_eq!(
5176 choose_highest_priority_address_status::<Ipv6>(
5177 [
5178 Ipv6PresentAddressStatus::UnicastAssigned,
5179 Ipv6PresentAddressStatus::UnicastTentative
5180 ]
5181 .into_iter()
5182 ),
5183 Some(Ipv6PresentAddressStatus::UnicastAssigned)
5184 )
5185 }
5186}