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, SocketCookie, 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, FrameDestination,
33 HandleableTimer, InstantContext, InterfaceProperties, IpAddressId, IpDeviceAddr,
34 IpDeviceAddressIdContext, IpExt, 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, TransportPacketSerializer, Tuple, WeakConnectionError,
45 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_cookie: Option<SocketCookie>,
163
164 #[cfg(debug_assertions)]
165 drop_check: IpLayerPacketMetadataDropCheck,
166}
167
168#[cfg(debug_assertions)]
175#[derive(Default)]
176struct IpLayerPacketMetadataDropCheck {
177 okay_to_drop: bool,
178}
179
180#[derive(Derivative)]
183#[derivative(Debug(bound = ""), Default(bound = ""))]
184pub struct DeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
185 conntrack_entry: Option<(WeakConntrackConnection, ConnectionDirection)>,
193 tx_metadata: BT::TxMetadata,
198 marks: Marks,
205}
206
207impl<BT: TxMetadataBindingsTypes> DeviceIpLayerMetadata<BT> {
208 pub fn into_tx_metadata(self) -> BT::TxMetadata {
211 self.tx_metadata
212 }
213 #[cfg(any(test, feature = "testutils"))]
215 pub fn with_marks(marks: Marks) -> Self {
216 Self { conntrack_entry: None, tx_metadata: Default::default(), marks }
217 }
218}
219
220impl<
221 I: IpLayerIpExt,
222 A: WeakIpAddressId<I::Addr>,
223 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
224> IpLayerPacketMetadata<I, A, BT>
225{
226 fn from_device_ip_layer_metadata<CC, D>(
227 core_ctx: &mut CC,
228 device: &D,
229 DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks }: DeviceIpLayerMetadata<BT>,
230 ) -> Self
231 where
232 CC: ResourceCounterContext<D, IpCounters<I>>,
233 {
234 let conntrack_connection_and_direction = match conntrack_entry
235 .map(|(conn, dir)| conn.into_inner().map(|conn| (conn, dir)))
236 .transpose()
237 {
238 Ok(conn_and_dir) => conn_and_dir,
241 Err(WeakConnectionError::EntryRemoved) => None,
243 Err(WeakConnectionError::InvalidEntry) => {
247 core_ctx.increment_both(device, |c| &c.invalid_cached_conntrack_entry);
248 None
249 }
250 };
251
252 let socket_cookie = tx_metadata.socket_cookie();
253
254 Self {
255 conntrack_connection_and_direction,
256 tx_metadata,
257 marks,
258 socket_cookie,
259 #[cfg(debug_assertions)]
260 drop_check: Default::default(),
261 }
262 }
263}
264
265impl<I: IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
266 IpLayerPacketMetadata<I, A, BT>
267{
268 pub(crate) fn from_tx_metadata_and_marks(tx_metadata: BT::TxMetadata, marks: Marks) -> Self {
269 let socket_cookie = tx_metadata.socket_cookie();
270 Self {
271 conntrack_connection_and_direction: None,
272 tx_metadata,
273 marks,
274 socket_cookie,
275 #[cfg(debug_assertions)]
276 drop_check: Default::default(),
277 }
278 }
279
280 pub(crate) fn into_parts(
281 self,
282 ) -> (
283 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
284 BT::TxMetadata,
285 Marks,
286 Option<SocketCookie>,
287 ) {
288 let Self {
289 tx_metadata,
290 marks,
291 conntrack_connection_and_direction,
292 socket_cookie,
293 #[cfg(debug_assertions)]
294 mut drop_check,
295 } = self;
296 #[cfg(debug_assertions)]
297 {
298 drop_check.okay_to_drop = true;
299 }
300 (conntrack_connection_and_direction, tx_metadata, marks, socket_cookie)
301 }
302
303 pub(crate) fn acknowledge_drop(self) {
308 #[cfg(debug_assertions)]
309 {
310 let mut this = self;
311 this.drop_check.okay_to_drop = true;
312 }
313 }
314
315 pub(crate) fn tx_metadata(&self) -> &BT::TxMetadata {
317 &self.tx_metadata
318 }
319
320 pub(crate) fn marks(&self) -> &Marks {
322 &self.marks
323 }
324}
325
326#[cfg(debug_assertions)]
327impl Drop for IpLayerPacketMetadataDropCheck {
328 fn drop(&mut self) {
329 if !self.okay_to_drop {
330 panic!(
331 "IpLayerPacketMetadata dropped without acknowledgement. https://fxbug.dev/334127474"
332 );
333 }
334 }
335}
336
337impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
338 FilterIpMetadata<I, A, BT> for IpLayerPacketMetadata<I, A, BT>
339{
340 fn take_connection_and_direction(
341 &mut self,
342 ) -> Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)> {
343 self.conntrack_connection_and_direction.take()
344 }
345
346 fn replace_connection_and_direction(
347 &mut self,
348 conn: ConntrackConnection<I, A, BT>,
349 direction: ConnectionDirection,
350 ) -> Option<ConntrackConnection<I, A, BT>> {
351 self.conntrack_connection_and_direction.replace((conn, direction)).map(|(conn, _dir)| conn)
352 }
353}
354
355impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
356 FilterPacketMetadata for IpLayerPacketMetadata<I, A, BT>
357{
358 fn apply_mark_action(&mut self, domain: MarkDomain, action: MarkAction) {
359 action.apply(self.marks.get_mut(domain))
360 }
361
362 fn cookie(&self) -> Option<SocketCookie> {
363 self.socket_cookie.clone()
364 }
365
366 fn marks(&self) -> &Marks {
367 &self.marks
368 }
369}
370
371pub type IpSendFrameError<S> = ErrorAndSerializer<IpSendFrameErrorReason, S>;
373
374#[derive(Debug, PartialEq)]
376pub enum IpSendFrameErrorReason {
377 Device(SendFrameErrorReason),
379 IllegalLoopbackAddress,
382}
383
384impl From<SendFrameErrorReason> for IpSendFrameErrorReason {
385 fn from(value: SendFrameErrorReason) -> Self {
386 Self::Device(value)
387 }
388}
389
390pub trait IpTransportContext<I, BC, CC>
396where
397 I: IpLayerIpExt,
398 CC: DeviceIdContext<AnyDevice> + ?Sized,
399{
400 type EarlyDemuxSocket;
402
403 fn early_demux<B: ParseBuffer>(
414 core_ctx: &mut CC,
415 device: &CC::DeviceId,
416 src_ip: I::Addr,
417 dst_ip: I::Addr,
418 buffer: B,
419 ) -> Option<Self::EarlyDemuxSocket>;
420
421 fn receive_icmp_error(
435 core_ctx: &mut CC,
436 bindings_ctx: &mut BC,
437 device: &CC::DeviceId,
438 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
439 original_dst_ip: SpecifiedAddr<I::Addr>,
440 original_body: &[u8],
441 err: I::ErrorCode,
442 );
443
444 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
450 core_ctx: &mut CC,
451 bindings_ctx: &mut BC,
452 device: &CC::DeviceId,
453 src_ip: I::RecvSrcAddr,
454 dst_ip: SpecifiedAddr<I::Addr>,
455 buffer: B,
456 info: &mut LocalDeliveryPacketInfo<I, H>,
457 early_demux_socket: Option<Self::EarlyDemuxSocket>,
458 ) -> Result<(), (B, I::IcmpError)>;
459}
460
461pub trait BaseTransportIpContext<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
464 type DevicesWithAddrIter<'s>: Iterator<Item = Self::DeviceId>;
467
468 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
474 &mut self,
475 addr: SpecifiedAddr<I::Addr>,
476 cb: F,
477 ) -> O;
478
479 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits;
484
485 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)>;
489}
490
491pub trait TransportIpContext<I: IpExt + FilterIpExt, BC: TxMetadataBindingsTypes>:
494 BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>
495{
496}
497
498impl<I, CC, BC> TransportIpContext<I, BC> for CC
499where
500 I: IpExt + FilterIpExt,
501 CC: BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>,
502 BC: TxMetadataBindingsTypes,
503{
504}
505
506pub trait MulticastMembershipHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
508 fn join_multicast_group(
515 &mut self,
516 bindings_ctx: &mut BC,
517 device: &Self::DeviceId,
518 addr: MulticastAddr<I::Addr>,
519 );
520
521 fn leave_multicast_group(
529 &mut self,
530 bindings_ctx: &mut BC,
531 device: &Self::DeviceId,
532 addr: MulticastAddr<I::Addr>,
533 );
534
535 fn select_device_for_multicast_group(
540 &mut self,
541 addr: MulticastAddr<I::Addr>,
542 marks: &Marks,
543 ) -> Result<Self::DeviceId, ResolveRouteError>;
544}
545
546pub trait UseTransportIpContextBlanket {}
558
559pub struct AssignedAddressDeviceIterator<Iter, I, D>(Iter, PhantomData<(I, D)>);
562
563impl<Iter, I, D> Iterator for AssignedAddressDeviceIterator<Iter, I, D>
564where
565 Iter: Iterator<Item = (D, I::AddressStatus)>,
566 I: IpLayerIpExt,
567{
568 type Item = D;
569 fn next(&mut self) -> Option<D> {
570 let Self(iter, PhantomData) = self;
571 iter.by_ref().find_map(|(device, state)| is_unicast_assigned::<I>(&state).then_some(device))
572 }
573}
574
575impl<
576 I: IpLayerIpExt,
577 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + IpRoutingBindingsTypes,
578 CC: IpDeviceContext<I>
579 + IpSocketHandler<I, BC>
580 + IpStateContext<I, BC>
581 + FilterIpContext<I, BC>
582 + UseTransportIpContextBlanket,
583> BaseTransportIpContext<I, BC> for CC
584{
585 type DevicesWithAddrIter<'s> =
586 AssignedAddressDeviceIterator<CC::DeviceAndAddressStatusIter<'s>, I, CC::DeviceId>;
587
588 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
589 &mut self,
590 addr: SpecifiedAddr<I::Addr>,
591 cb: F,
592 ) -> O {
593 self.with_address_statuses(addr, |it| cb(AssignedAddressDeviceIterator(it, PhantomData)))
594 }
595
596 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
597 match device {
598 Some(device) => HopLimits {
599 unicast: IpDeviceEgressStateContext::<I>::get_hop_limit(self, device),
600 ..DEFAULT_HOP_LIMITS
601 },
602 None => DEFAULT_HOP_LIMITS,
603 }
604 }
605
606 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)> {
607 self.with_filter_state(|state| {
608 let conn = state.conntrack.get_connection(&tuple)?;
609
610 if !conn.destination_nat() {
611 return None;
612 }
613
614 let original = conn.original_tuple();
618 Some((original.dst_addr, original.dst_port_or_id))
619 })
620 }
621}
622
623#[derive(Debug, PartialEq)]
625#[allow(missing_docs)]
626pub enum AddressStatus<S> {
627 Present(S),
628 Unassigned,
629}
630
631impl<S> AddressStatus<S> {
632 fn into_present(self) -> Option<S> {
633 match self {
634 Self::Present(s) => Some(s),
635 Self::Unassigned => None,
636 }
637 }
638}
639
640impl AddressStatus<Ipv4PresentAddressStatus> {
641 pub fn from_context_addr_v4<
643 BC: IpDeviceStateBindingsTypes,
644 CC: device::IpDeviceStateContext<Ipv4, BC> + GmpQueryHandler<Ipv4, BC>,
645 >(
646 core_ctx: &mut CC,
647 device: &CC::DeviceId,
648 addr: SpecifiedAddr<Ipv4Addr>,
649 ) -> AddressStatus<Ipv4PresentAddressStatus> {
650 if addr.is_limited_broadcast() {
651 return AddressStatus::Present(Ipv4PresentAddressStatus::LimitedBroadcast);
652 }
653
654 if MulticastAddr::new(addr.get())
655 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
656 {
657 return AddressStatus::Present(Ipv4PresentAddressStatus::Multicast);
658 }
659
660 core_ctx.with_address_ids(device, |mut addrs, core_ctx| {
661 addrs
662 .find_map(|addr_id| {
663 let dev_addr = addr_id.addr_sub();
664 let (dev_addr, subnet) = dev_addr.addr_subnet();
665
666 if **dev_addr == addr {
667 let assigned = core_ctx.with_ip_address_data(
668 device,
669 &addr_id,
670 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| {
671 *assigned
672 },
673 );
674
675 if assigned {
676 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastAssigned))
677 } else {
678 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastTentative))
679 }
680 } else if addr.get() == subnet.broadcast() {
681 Some(AddressStatus::Present(Ipv4PresentAddressStatus::SubnetBroadcast))
682 } else if device.is_loopback() && subnet.contains(addr.as_ref()) {
683 Some(AddressStatus::Present(Ipv4PresentAddressStatus::LoopbackSubnet))
684 } else {
685 None
686 }
687 })
688 .unwrap_or(AddressStatus::Unassigned)
689 })
690 }
691}
692
693impl AddressStatus<Ipv6PresentAddressStatus> {
694 pub fn from_context_addr_v6<
696 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
697 CC: device::Ipv6DeviceContext<BC> + GmpQueryHandler<Ipv6, BC>,
698 >(
699 core_ctx: &mut CC,
700 device: &CC::DeviceId,
701 addr: SpecifiedAddr<Ipv6Addr>,
702 ) -> AddressStatus<Ipv6PresentAddressStatus> {
703 if MulticastAddr::new(addr.get())
704 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
705 {
706 return AddressStatus::Present(Ipv6PresentAddressStatus::Multicast);
707 }
708
709 let addr_id = match core_ctx.get_address_id(device, addr) {
710 Ok(o) => o,
711 Err(NotFoundError) => return AddressStatus::Unassigned,
712 };
713
714 let assigned = core_ctx.with_ip_address_data(
715 device,
716 &addr_id,
717 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
718 );
719
720 if assigned {
721 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned)
722 } else {
723 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastTentative)
724 }
725 }
726}
727
728impl<S: GenericOverIp<I>, I: Ip> GenericOverIp<I> for AddressStatus<S> {
729 type Type = AddressStatus<S::Type>;
730}
731
732#[derive(Debug, PartialEq)]
734#[allow(missing_docs)]
735pub enum Ipv4PresentAddressStatus {
736 LimitedBroadcast,
737 SubnetBroadcast,
738 Multicast,
739 UnicastAssigned,
740 UnicastTentative,
741 LoopbackSubnet,
752}
753
754impl Ipv4PresentAddressStatus {
755 fn to_broadcast_marker(&self) -> Option<<Ipv4 as BroadcastIpExt>::BroadcastMarker> {
756 match self {
757 Self::LimitedBroadcast | Self::SubnetBroadcast => Some(()),
758 Self::Multicast
759 | Self::UnicastAssigned
760 | Self::UnicastTentative
761 | Self::LoopbackSubnet => None,
762 }
763 }
764}
765
766#[derive(Debug, PartialEq)]
768#[allow(missing_docs)]
769pub enum Ipv6PresentAddressStatus {
770 Multicast,
771 UnicastAssigned,
772 UnicastTentative,
773}
774
775pub trait IpLayerIpExt:
777 IpExt
778 + MulticastRouteIpExt
779 + IcmpHandlerIpExt
780 + FilterIpExt
781 + FragmentationIpExt
782 + IpDeviceIpExt
783 + IpCountersIpExt
784 + IcmpCountersIpExt
785 + ReassemblyIpExt
786{
787 type AddressStatus: Debug;
789 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>: AsRef<
791 IpStateInner<Self, StrongDeviceId, BT>,
792 >;
793 type PacketIdState;
795 type PacketId;
797 fn next_packet_id_from_state(state: &Self::PacketIdState) -> Self::PacketId;
799}
800
801impl IpLayerIpExt for Ipv4 {
802 type AddressStatus = Ipv4PresentAddressStatus;
803 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
804 Ipv4State<StrongDeviceId, BT>;
805 type PacketIdState = AtomicU16;
806 type PacketId = u16;
807 fn next_packet_id_from_state(next_packet_id: &Self::PacketIdState) -> Self::PacketId {
808 next_packet_id.fetch_add(1, atomic::Ordering::Relaxed)
812 }
813}
814
815impl IpLayerIpExt for Ipv6 {
816 type AddressStatus = Ipv6PresentAddressStatus;
817 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
818 Ipv6State<StrongDeviceId, BT>;
819 type PacketIdState = ();
820 type PacketId = ();
821 fn next_packet_id_from_state((): &Self::PacketIdState) -> Self::PacketId {
822 ()
823 }
824}
825
826pub trait IpStateContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes + MatcherBindingsTypes>:
828 IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>
829{
830 type IpRouteTablesCtx<'a>: IpRouteTablesContext<I, BT, DeviceId = Self::DeviceId>;
832
833 fn with_rules_table<
835 O,
836 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId, BT>) -> O,
837 >(
838 &mut self,
839 cb: F,
840 ) -> O;
841
842 fn with_rules_table_mut<
844 O,
845 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId, BT>) -> O,
846 >(
847 &mut self,
848 cb: F,
849 ) -> O;
850}
851
852pub trait IpRouteTablesContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
854 IpRouteTableContext<I, BT> + IpDeviceContext<I>
855{
856 type Ctx<'a>: IpRouteTableContext<I, BT, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>;
858
859 fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId, BT>;
861
862 fn with_ip_routing_tables<
864 O,
865 F: FnOnce(
866 &mut Self::Ctx<'_>,
867 &HashMap<
868 RoutingTableId<I, Self::DeviceId, BT>,
869 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
870 >,
871 ) -> O,
872 >(
873 &mut self,
874 cb: F,
875 ) -> O;
876
877 fn with_ip_routing_tables_mut<
879 O,
880 F: FnOnce(
881 &mut HashMap<
882 RoutingTableId<I, Self::DeviceId, BT>,
883 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
884 >,
885 ) -> O,
886 >(
887 &mut self,
888 cb: F,
889 ) -> O;
890
891 fn with_main_ip_routing_table<
895 O,
896 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
897 >(
898 &mut self,
899 cb: F,
900 ) -> O {
901 let main_table_id = self.main_table_id();
902 self.with_ip_routing_table(&main_table_id, cb)
903 }
904
905 fn with_main_ip_routing_table_mut<
909 O,
910 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
911 >(
912 &mut self,
913 cb: F,
914 ) -> O {
915 let main_table_id = self.main_table_id();
916 self.with_ip_routing_table_mut(&main_table_id, cb)
917 }
918}
919
920pub trait IpRouteTableContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
922 IpDeviceContext<I>
923{
924 type IpDeviceIdCtx<'a>: DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
926 + IpRoutingDeviceContext<I>
927 + IpDeviceContext<I>;
928
929 fn with_ip_routing_table<
931 O,
932 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
933 >(
934 &mut self,
935 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
936 cb: F,
937 ) -> O;
938
939 fn with_ip_routing_table_mut<
941 O,
942 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
943 >(
944 &mut self,
945 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
946 cb: F,
947 ) -> O;
948}
949
950pub trait IpDeviceEgressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
952 fn with_next_packet_id<O, F: FnOnce(&I::PacketIdState) -> O>(&self, cb: F) -> O;
954
955 fn get_local_addr_for_remote(
957 &mut self,
958 device_id: &Self::DeviceId,
959 remote: Option<SpecifiedAddr<I::Addr>>,
960 ) -> Option<IpDeviceAddr<I::Addr>>;
961
962 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8;
964}
965
966pub trait IpDeviceIngressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
968 fn address_status_for_device(
974 &mut self,
975 addr: SpecifiedAddr<I::Addr>,
976 device_id: &Self::DeviceId,
977 ) -> AddressStatus<I::AddressStatus>;
978}
979
980pub trait IpDeviceContext<I: IpLayerIpExt>:
982 IpDeviceEgressStateContext<I> + IpDeviceIngressStateContext<I>
983{
984 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
986
987 type DeviceAndAddressStatusIter<'a>: Iterator<Item = (Self::DeviceId, I::AddressStatus)>;
989
990 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
996 &mut self,
997 addr: SpecifiedAddr<I::Addr>,
998 cb: F,
999 ) -> R;
1000
1001 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
1003}
1004
1005pub trait IpDeviceConfirmReachableContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1007 fn confirm_reachable(
1010 &mut self,
1011 bindings_ctx: &mut BC,
1012 device: &Self::DeviceId,
1013 neighbor: SpecifiedAddr<I::Addr>,
1014 );
1015}
1016
1017pub trait IpDeviceMtuContext<I: Ip>: DeviceIdContext<AnyDevice> {
1019 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu;
1023}
1024
1025#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
1027#[generic_over_ip(I, Ip)]
1028pub enum IpLayerEvent<DeviceId, I: IpLayerIpExt> {
1029 AddRoute(types::AddableEntry<I::Addr, DeviceId>),
1031 RemoveRoutes {
1033 subnet: Subnet<I::Addr>,
1035 device: DeviceId,
1037 gateway: Option<SpecifiedAddr<I::Addr>>,
1039 },
1040 MulticastForwarding(MulticastForwardingEvent<I, DeviceId>),
1042}
1043
1044impl<DeviceId, I: IpLayerIpExt> From<MulticastForwardingEvent<I, DeviceId>>
1045 for IpLayerEvent<DeviceId, I>
1046{
1047 fn from(event: MulticastForwardingEvent<I, DeviceId>) -> IpLayerEvent<DeviceId, I> {
1048 IpLayerEvent::MulticastForwarding(event)
1049 }
1050}
1051
1052impl<DeviceId, I: IpLayerIpExt> IpLayerEvent<DeviceId, I> {
1053 pub fn map_device<N, F: Fn(DeviceId) -> N>(self, map: F) -> IpLayerEvent<N, I> {
1055 match self {
1056 IpLayerEvent::AddRoute(types::AddableEntry {
1057 subnet,
1058 device,
1059 gateway,
1060 metric,
1061 route_preference,
1062 }) => IpLayerEvent::AddRoute(types::AddableEntry {
1063 subnet,
1064 device: map(device),
1065 gateway,
1066 metric,
1067 route_preference,
1068 }),
1069 IpLayerEvent::RemoveRoutes { subnet, device, gateway } => {
1070 IpLayerEvent::RemoveRoutes { subnet, device: map(device), gateway }
1071 }
1072 IpLayerEvent::MulticastForwarding(e) => {
1073 IpLayerEvent::MulticastForwarding(e.map_device(map))
1074 }
1075 }
1076 }
1077}
1078
1079#[derive(Derivative, PartialEq, Eq, Clone, Hash)]
1081#[derivative(Debug)]
1082pub struct RouterAdvertisementEvent<D> {
1083 #[derivative(Debug = "ignore")]
1086 pub options_bytes: Box<[u8]>,
1087 pub source: net_types::ip::Ipv6Addr,
1089 pub device: D,
1091}
1092
1093impl<D> RouterAdvertisementEvent<D> {
1094 pub fn map_device<N, F: Fn(D) -> N>(self, map: F) -> RouterAdvertisementEvent<N> {
1096 let Self { options_bytes, source, device } = self;
1097 RouterAdvertisementEvent { options_bytes, source, device: map(device) }
1098 }
1099}
1100
1101pub trait NdpBindingsContext<DeviceId>: EventContext<RouterAdvertisementEvent<DeviceId>> {}
1103impl<DeviceId, BC: EventContext<RouterAdvertisementEvent<DeviceId>>> NdpBindingsContext<DeviceId>
1104 for BC
1105{
1106}
1107
1108pub trait MarksBindingsContext {
1110 fn marks_to_keep_on_egress() -> &'static [MarkDomain];
1115
1116 fn marks_to_set_on_ingress() -> &'static [MarkDomain];
1121}
1122
1123pub trait IpLayerBindingsContext<I: IpLayerIpExt, DeviceId>:
1125 InstantContext
1126 + EventContext<IpLayerEvent<DeviceId, I>>
1127 + FilterBindingsContext<DeviceId>
1128 + TxMetadataBindingsTypes
1129 + IpRoutingBindingsTypes
1130 + MarksBindingsContext
1131{
1132}
1133impl<
1134 I: IpLayerIpExt,
1135 DeviceId,
1136 BC: InstantContext
1137 + EventContext<IpLayerEvent<DeviceId, I>>
1138 + FilterBindingsContext<DeviceId>
1139 + TxMetadataBindingsTypes
1140 + IpRoutingBindingsTypes
1141 + MarksBindingsContext,
1142> IpLayerBindingsContext<I, DeviceId> for BC
1143{
1144}
1145
1146pub trait IpLayerBindingsTypes:
1148 IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes
1149{
1150}
1151impl<BT: IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes> IpLayerBindingsTypes
1152 for BT
1153{
1154}
1155
1156pub trait IpLayerContext<
1158 I: IpLayerIpExt,
1159 BC: IpLayerBindingsContext<I, <Self as DeviceIdContext<AnyDevice>>::DeviceId>,
1160>:
1161 IpStateContext<I, BC>
1162 + IpDeviceContext<I>
1163 + IpDeviceMtuContext<I>
1164 + IpDeviceSendContext<I, BC>
1165 + IcmpErrorHandler<I, BC>
1166 + MulticastForwardingStateContext<I, BC>
1167 + MulticastForwardingDeviceContext<I>
1168 + CounterContext<MulticastForwardingCounters<I>>
1169 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>
1170{
1171}
1172
1173impl<
1174 I: IpLayerIpExt,
1175 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
1176 CC: IpStateContext<I, BC>
1177 + IpDeviceContext<I>
1178 + IpDeviceMtuContext<I>
1179 + IpDeviceSendContext<I, BC>
1180 + IcmpErrorHandler<I, BC>
1181 + MulticastForwardingStateContext<I, BC>
1182 + MulticastForwardingDeviceContext<I>
1183 + CounterContext<MulticastForwardingCounters<I>>
1184 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>,
1185> IpLayerContext<I, BC> for CC
1186{
1187}
1188
1189fn is_unicast_assigned<I: IpLayerIpExt>(status: &I::AddressStatus) -> bool {
1190 #[derive(GenericOverIp)]
1191 #[generic_over_ip(I, Ip)]
1192 struct WrapAddressStatus<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
1193
1194 I::map_ip(
1195 WrapAddressStatus(status),
1196 |WrapAddressStatus(status)| match status {
1197 Ipv4PresentAddressStatus::UnicastAssigned
1198 | Ipv4PresentAddressStatus::LoopbackSubnet => true,
1199 Ipv4PresentAddressStatus::UnicastTentative
1200 | Ipv4PresentAddressStatus::LimitedBroadcast
1201 | Ipv4PresentAddressStatus::SubnetBroadcast
1202 | Ipv4PresentAddressStatus::Multicast => false,
1203 },
1204 |WrapAddressStatus(status)| match status {
1205 Ipv6PresentAddressStatus::UnicastAssigned => true,
1206 Ipv6PresentAddressStatus::Multicast | Ipv6PresentAddressStatus::UnicastTentative => {
1207 false
1208 }
1209 },
1210 )
1211}
1212
1213fn is_local_assigned_address<I: Ip + IpLayerIpExt, CC: IpDeviceIngressStateContext<I>>(
1214 core_ctx: &mut CC,
1215 device: &CC::DeviceId,
1216 addr: IpDeviceAddr<I::Addr>,
1217) -> bool {
1218 match core_ctx.address_status_for_device(addr.into(), device) {
1219 AddressStatus::Present(status) => is_unicast_assigned::<I>(&status),
1220 AddressStatus::Unassigned => false,
1221 }
1222}
1223
1224fn get_device_with_assigned_address<I, CC>(
1225 core_ctx: &mut CC,
1226 addr: IpDeviceAddr<I::Addr>,
1227) -> Option<(CC::DeviceId, I::AddressStatus)>
1228where
1229 I: IpLayerIpExt,
1230 CC: IpDeviceContext<I>,
1231{
1232 core_ctx.with_address_statuses(addr.into(), |mut it| {
1233 it.find_map(|(device, status)| {
1234 is_unicast_assigned::<I>(&status).then_some((device, status))
1235 })
1236 })
1237}
1238
1239fn get_local_addr<I: Ip + IpLayerIpExt, CC: IpDeviceContext<I>>(
1243 core_ctx: &mut CC,
1244 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1245 device: &CC::DeviceId,
1246 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1247) -> Result<IpDeviceAddr<I::Addr>, ResolveRouteError> {
1248 match local_ip_and_policy {
1249 Some((local_ip, NonLocalSrcAddrPolicy::Allow)) => Ok(local_ip),
1250 Some((local_ip, NonLocalSrcAddrPolicy::Deny)) => {
1251 is_local_assigned_address(core_ctx, device, local_ip)
1252 .then_some(local_ip)
1253 .ok_or(ResolveRouteError::NoSrcAddr)
1254 }
1255 None => core_ctx
1256 .get_local_addr_for_remote(device, remote_addr.map(Into::into))
1257 .ok_or(ResolveRouteError::NoSrcAddr),
1258 }
1259}
1260
1261#[derive(Error, Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
1263#[generic_over_ip()]
1264pub enum ResolveRouteError {
1265 #[error("a source address could not be selected")]
1267 NoSrcAddr,
1268 #[error("no route exists to the destination IP address")]
1270 Unreachable,
1271}
1272
1273fn get_local_addr_with_internal_forwarding<I, CC>(
1275 core_ctx: &mut CC,
1276 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1277 device: &CC::DeviceId,
1278 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1279) -> Result<(IpDeviceAddr<I::Addr>, InternalForwarding<CC::DeviceId>), ResolveRouteError>
1280where
1281 I: IpLayerIpExt,
1282 CC: IpDeviceContext<I>,
1283{
1284 match get_local_addr(core_ctx, local_ip_and_policy, device, remote_addr) {
1285 Ok(src_addr) => Ok((src_addr, InternalForwarding::NotUsed)),
1286 Err(e) => {
1287 if let Some((local_ip, _policy)) = local_ip_and_policy {
1295 if let Some((device, _addr_status)) =
1296 get_device_with_assigned_address(core_ctx, local_ip)
1297 {
1298 if core_ctx.is_device_unicast_forwarding_enabled(&device) {
1299 return Ok((local_ip, InternalForwarding::Used(device)));
1300 }
1301 }
1302 }
1303 Err(e)
1304 }
1305 }
1306}
1307
1308#[derive(Debug, PartialEq, Eq)]
1311struct RuleWalkInfo<O> {
1312 observed_source_address_matcher: bool,
1314 inner: O,
1317}
1318
1319fn walk_rules<
1333 I: IpLayerIpExt,
1334 BT: IpRoutingBindingsTypes + MatcherBindingsTypes,
1335 CC: IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>,
1336 O,
1337 State,
1338 F: FnMut(
1339 State,
1340 &mut CC::IpDeviceIdCtx<'_>,
1341 &RoutingTable<I, CC::DeviceId>,
1342 ) -> ControlFlow<O, State>,
1343>(
1344 core_ctx: &mut CC,
1345 rules: &RulesTable<I, CC::DeviceId, BT>,
1346 init: State,
1347 rule_input: &RuleInput<'_, I, CC::DeviceId>,
1348 mut lookup_table: F,
1349) -> ControlFlow<RuleAction<RuleWalkInfo<O>>, RuleWalkInfo<State>> {
1350 rules.iter().try_fold(
1351 RuleWalkInfo { inner: init, observed_source_address_matcher: false },
1352 |RuleWalkInfo { inner: state, observed_source_address_matcher },
1353 Rule { action, matcher }| {
1354 let observed_source_address_matcher =
1355 observed_source_address_matcher || matcher.source_address_matcher.is_some();
1356 if !matcher.matches(rule_input) {
1357 return ControlFlow::Continue(RuleWalkInfo {
1358 inner: state,
1359 observed_source_address_matcher,
1360 });
1361 }
1362 match action {
1363 RuleAction::Unreachable => return ControlFlow::Break(RuleAction::Unreachable),
1364 RuleAction::Lookup(table_id) => core_ctx.with_ip_routing_table(
1365 &table_id,
1366 |core_ctx, table| match lookup_table(state, core_ctx, table) {
1367 ControlFlow::Break(out) => {
1368 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1369 inner: out,
1370 observed_source_address_matcher,
1371 }))
1372 }
1373 ControlFlow::Continue(state) => ControlFlow::Continue(RuleWalkInfo {
1374 inner: state,
1375 observed_source_address_matcher,
1376 }),
1377 },
1378 ),
1379 }
1380 },
1381 )
1382}
1383
1384pub fn resolve_output_route_to_destination<
1395 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1396 BC: IpDeviceBindingsContext<I, CC::DeviceId> + IpLayerBindingsContext<I, CC::DeviceId>,
1397 CC: IpStateContext<I, BC> + IpDeviceContext<I> + device::IpDeviceConfigurationContext<I, BC>,
1398>(
1399 core_ctx: &mut CC,
1400 device: Option<&CC::DeviceId>,
1401 src_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1402 dst_ip: Option<RoutableIpAddr<I::Addr>>,
1403 marks: &Marks,
1404) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1405 enum LocalDelivery<A, D> {
1406 WeakLoopback { dst_ip: A, device: D },
1407 StrongForDevice(D),
1408 }
1409
1410 let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1427 let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1428 match (device, dst_ip) {
1429 (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1430 .then_some(LocalDelivery::StrongForDevice(device.clone())),
1431 (None, Some(dst_ip)) => {
1432 get_device_with_assigned_address(core_ctx, dst_ip).map(
1433 |(dst_device, _addr_status)| {
1434 if src_ip_and_policy
1439 .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1440 || dst_ip.as_ref().must_have_zone()
1441 {
1442 LocalDelivery::StrongForDevice(dst_device)
1443 } else {
1444 LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1445 }
1446 },
1447 )
1448 }
1449 (_, None) => None,
1450 }
1451 };
1452
1453 if let Some(local_delivery) = local_delivery_instructions {
1454 let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1455
1456 let (src_addr, dest_device) = match local_delivery {
1457 LocalDelivery::WeakLoopback { dst_ip, device } => {
1458 let src_ip = match src_ip_and_policy {
1459 Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1460 let _device = get_device_with_assigned_address(core_ctx, src_ip)
1461 .ok_or(ResolveRouteError::NoSrcAddr)?;
1462 src_ip
1463 }
1464 Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1465 None => dst_ip,
1466 };
1467 (src_ip, device)
1468 }
1469 LocalDelivery::StrongForDevice(device) => {
1470 (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1471 }
1472 };
1473 return Ok(ResolvedRoute {
1474 src_addr,
1475 local_delivery_device: Some(dest_device),
1476 device: loopback,
1477 next_hop: NextHop::RemoteAsNeighbor,
1478 internal_forwarding: InternalForwarding::NotUsed,
1479 });
1480 }
1481 let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1482 let rule_input = RuleInput {
1483 packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1484 marks,
1485 };
1486 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
1487 let mut walk_rules = |rule_input, src_ip_and_policy| {
1488 walk_rules(
1489 core_ctx,
1490 rules,
1491 None, rule_input,
1493 |first_error, core_ctx, table| {
1494 let mut matching_with_addr = table.lookup_filter_map(
1495 core_ctx,
1496 device,
1497 dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1498 |core_ctx, d| {
1499 Some(get_local_addr_with_internal_forwarding(
1500 core_ctx,
1501 src_ip_and_policy,
1502 d,
1503 dst_ip,
1504 ))
1505 },
1506 );
1507
1508 let first_error_in_this_table = match matching_with_addr.next() {
1509 Some((
1510 Destination { device, next_hop },
1511 Ok((local_addr, internal_forwarding)),
1512 )) => {
1513 return ControlFlow::Break(Ok((
1514 Destination { device: device.clone(), next_hop },
1515 local_addr,
1516 internal_forwarding,
1517 )));
1518 }
1519 Some((_, Err(e))) => e,
1520 None => return ControlFlow::Continue(first_error),
1524 };
1525
1526 matching_with_addr
1527 .filter_map(|(destination, local_addr)| {
1528 local_addr.ok_checked::<ResolveRouteError>().map(
1531 |(local_addr, internal_forwarding)| {
1532 (destination, local_addr, internal_forwarding)
1533 },
1534 )
1535 })
1536 .next()
1537 .map_or(
1538 ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1539 |(
1540 Destination { device, next_hop },
1541 local_addr,
1542 internal_forwarding,
1543 )| {
1544 ControlFlow::Break(Ok((
1545 Destination { device: device.clone(), next_hop },
1546 local_addr,
1547 internal_forwarding,
1548 )))
1549 },
1550 )
1551 },
1552 )
1553 };
1554
1555 let result = match walk_rules(&rule_input, src_ip_and_policy) {
1556 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1563 inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1564 observed_source_address_matcher: true,
1565 })) if src_ip_and_policy.is_none() => walk_rules(
1566 &RuleInput {
1567 packet_origin: PacketOrigin::Local {
1568 bound_address: Some(selected_src_addr.into()),
1569 bound_device: device,
1570 },
1571 marks,
1572 },
1573 Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1574 ),
1575 result => result,
1576 };
1577
1578 match result {
1579 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1580 inner: result,
1581 observed_source_address_matcher: _,
1582 })) => {
1583 result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1584 ResolvedRoute {
1585 src_addr,
1586 device,
1587 local_delivery_device: None,
1588 next_hop,
1589 internal_forwarding,
1590 }
1591 })
1592 }
1593 ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1594 ControlFlow::Continue(RuleWalkInfo {
1595 inner: first_error,
1596 observed_source_address_matcher: _,
1597 }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1598 }
1599 })
1600}
1601
1602pub trait UseIpSocketContextBlanket {}
1607
1608impl<I, BC, CC> IpSocketContext<I, BC> for CC
1609where
1610 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1611 BC: IpDeviceBindingsContext<I, CC::DeviceId>
1612 + IpLayerBindingsContext<I, CC::DeviceId>
1613 + IpSocketBindingsContext<CC::DeviceId>,
1614 CC: IpLayerEgressContext<I, BC>
1615 + IpStateContext<I, BC>
1616 + IpDeviceContext<I>
1617 + IpDeviceConfirmReachableContext<I, BC>
1618 + IpDeviceMtuContext<I>
1619 + device::IpDeviceConfigurationContext<I, BC>
1620 + IcmpErrorHandler<I, BC>
1621 + UseIpSocketContextBlanket,
1622{
1623 fn lookup_route(
1624 &mut self,
1625 _bindings_ctx: &mut BC,
1626 device: Option<&CC::DeviceId>,
1627 local_ip: Option<IpDeviceAddr<I::Addr>>,
1628 addr: RoutableIpAddr<I::Addr>,
1629 transparent: bool,
1630 marks: &Marks,
1631 ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1632 let src_ip_and_policy = local_ip.map(|local_ip| {
1633 (
1634 local_ip,
1635 if transparent {
1636 NonLocalSrcAddrPolicy::Allow
1637 } else {
1638 NonLocalSrcAddrPolicy::Deny
1639 },
1640 )
1641 });
1642 let res =
1643 resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1644 trace!(
1645 "lookup_route(\
1646 device={device:?}, \
1647 local_ip={local_ip:?}, \
1648 addr={addr:?}, \
1649 transparent={transparent:?}, \
1650 marks={marks:?}) => {res:?}"
1651 );
1652 res
1653 }
1654
1655 fn send_ip_packet<S>(
1656 &mut self,
1657 bindings_ctx: &mut BC,
1658 meta: SendIpPacketMeta<
1659 I,
1660 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1661 SpecifiedAddr<I::Addr>,
1662 >,
1663 body: S,
1664 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1665 ) -> Result<(), IpSendFrameError<S>>
1666 where
1667 S: TransportPacketSerializer<I>,
1668 S::Buffer: BufferMut,
1669 {
1670 send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1671 }
1672
1673 fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1674 device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1675 }
1676
1677 fn confirm_reachable(
1678 &mut self,
1679 bindings_ctx: &mut BC,
1680 dst: SpecifiedAddr<I::Addr>,
1681 input: RuleInput<'_, I, Self::DeviceId>,
1682 ) {
1683 match lookup_route_table(self, dst.get(), input) {
1684 Some(Destination { next_hop, device }) => {
1685 let neighbor = match next_hop {
1686 NextHop::RemoteAsNeighbor => dst,
1687 NextHop::Gateway(gateway) => gateway,
1688 NextHop::Broadcast(marker) => {
1689 I::map_ip::<_, ()>(
1690 WrapBroadcastMarker(marker),
1691 |WrapBroadcastMarker(())| {
1692 debug!(
1693 "can't confirm {dst:?}@{device:?} as reachable: \
1694 dst is a broadcast address"
1695 );
1696 },
1697 |WrapBroadcastMarker(never)| match never {},
1698 );
1699 return;
1700 }
1701 };
1702 IpDeviceConfirmReachableContext::confirm_reachable(
1703 self,
1704 bindings_ctx,
1705 &device,
1706 neighbor,
1707 );
1708 }
1709 None => {
1710 debug!("can't confirm {dst:?} as reachable: no route");
1711 }
1712 }
1713 }
1714}
1715
1716pub trait SocketMetadata<CC>
1719where
1720 CC: ?Sized,
1721{
1722 fn socket_cookie(&self, core_ctx: &mut CC) -> SocketCookie;
1724 fn marks(&self, core_ctx: &mut CC) -> Marks;
1726}
1727
1728impl<T, O, CC> SocketMetadata<CC> for EitherStack<T, O>
1729where
1730 CC: ?Sized,
1731 T: SocketMetadata<CC>,
1732 O: SocketMetadata<CC>,
1733{
1734 fn socket_cookie(&self, core_ctx: &mut CC) -> SocketCookie {
1735 match self {
1736 Self::ThisStack(t) => t.socket_cookie(core_ctx),
1737 Self::OtherStack(o) => o.socket_cookie(core_ctx),
1738 }
1739 }
1740
1741 fn marks(&self, core_ctx: &mut CC) -> Marks {
1742 match self {
1743 Self::ThisStack(t) => t.marks(core_ctx),
1744 Self::OtherStack(o) => o.marks(core_ctx),
1745 }
1746 }
1747}
1748
1749pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1754 type EarlyDemuxSocket: SocketMetadata<Self>;
1756
1757 fn early_demux<B: ParseBuffer>(
1759 &mut self,
1760 device: &Self::DeviceId,
1761 frame_dst: Option<FrameDestination>,
1762 src_ip: I::Addr,
1763 dst_ip: I::Addr,
1764 proto: I::Proto,
1765 body: B,
1766 ) -> Option<Self::EarlyDemuxSocket>;
1767
1768 fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1772 &mut self,
1773 bindings_ctx: &mut BC,
1774 device: &Self::DeviceId,
1775 src_ip: I::RecvSrcAddr,
1776 dst_ip: SpecifiedAddr<I::Addr>,
1777 proto: I::Proto,
1778 body: B,
1779 info: &mut LocalDeliveryPacketInfo<I, H>,
1780 early_demux_socket: Option<Self::EarlyDemuxSocket>,
1781 ) -> Result<(), I::IcmpError>;
1782}
1783
1784pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1786 IpTransportDispatchContext<
1787 I,
1788 BC,
1789 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1790 > + IpDeviceIngressStateContext<I>
1791 + IpDeviceMtuContext<I>
1792 + IpDeviceSendContext<I, BC>
1793 + IcmpErrorHandler<I, BC>
1794 + IpLayerContext<I, BC>
1795 + FragmentHandler<I, BC>
1796 + FilterHandlerProvider<I, BC>
1797 + RawIpSocketHandler<I, BC>
1798{
1799}
1800
1801impl<
1802 I: IpLayerIpExt,
1803 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1804 CC: IpTransportDispatchContext<
1805 I,
1806 BC,
1807 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1808 > + IpDeviceIngressStateContext<I>
1809 + IpDeviceMtuContext<I>
1810 + IpDeviceSendContext<I, BC>
1811 + IcmpErrorHandler<I, BC>
1812 + IpLayerContext<I, BC>
1813 + FragmentHandler<I, BC>
1814 + FilterHandlerProvider<I, BC>
1815 + RawIpSocketHandler<I, BC>,
1816> IpLayerIngressContext<I, BC> for CC
1817{
1818}
1819
1820pub trait IpLayerEgressContext<I, BC>:
1822 IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1823 + FilterHandlerProvider<I, BC>
1824 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1825where
1826 I: IpLayerIpExt,
1827 BC: FilterBindingsContext<Self::DeviceId> + TxMetadataBindingsTypes,
1828{
1829}
1830
1831impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1832where
1833 I: IpLayerIpExt,
1834 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes,
1835 CC: IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1836 + FilterHandlerProvider<I, BC>
1837 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
1838{
1839}
1840
1841pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1843 IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
1844{
1845}
1846
1847impl<
1848 I: IpLayerIpExt,
1849 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1850 CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
1851> IpLayerForwardingContext<I, BC> for CC
1852{
1853}
1854
1855#[derive(Copy, Clone, Default)]
1857pub struct Ipv4StateBuilder {
1858 icmp: Icmpv4StateBuilder,
1859}
1860
1861impl Ipv4StateBuilder {
1862 #[cfg(any(test, feature = "testutils"))]
1864 pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
1865 &mut self.icmp
1866 }
1867
1868 pub fn build<
1870 CC: CoreTimerContext<IpLayerTimerId, BC>,
1871 StrongDeviceId: StrongDeviceIdentifier,
1872 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1873 >(
1874 self,
1875 bindings_ctx: &mut BC,
1876 ) -> Ipv4State<StrongDeviceId, BC> {
1877 let Ipv4StateBuilder { icmp } = self;
1878
1879 Ipv4State {
1880 inner: IpStateInner::new::<CC>(bindings_ctx),
1881 icmp: icmp.build(),
1882 next_packet_id: Default::default(),
1883 }
1884 }
1885}
1886
1887#[derive(Copy, Clone)]
1891pub struct Ipv6StateBuilder {
1892 icmp: Icmpv6StateBuilder,
1893 slaac_stable_secret_key: Option<IidSecret>,
1894}
1895
1896impl Ipv6StateBuilder {
1897 pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
1902 self.slaac_stable_secret_key = Some(secret_key);
1903 self
1904 }
1905
1906 pub fn build<
1912 CC: CoreTimerContext<IpLayerTimerId, BC>,
1913 StrongDeviceId: StrongDeviceIdentifier,
1914 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1915 >(
1916 self,
1917 bindings_ctx: &mut BC,
1918 ) -> Ipv6State<StrongDeviceId, BC> {
1919 let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
1920
1921 let slaac_stable_secret_key = slaac_stable_secret_key
1922 .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
1923
1924 Ipv6State {
1925 inner: IpStateInner::new::<CC>(bindings_ctx),
1926 icmp: icmp.build(),
1927 slaac_counters: Default::default(),
1928 slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
1929 slaac_stable_secret_key,
1930 }
1931 }
1932}
1933
1934impl Default for Ipv6StateBuilder {
1935 fn default() -> Self {
1936 #[cfg(any(test, feature = "testutils"))]
1937 let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
1938
1939 #[cfg(not(any(test, feature = "testutils")))]
1940 let slaac_stable_secret_key = None;
1941
1942 Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
1943 }
1944}
1945
1946pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1948 pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
1950 pub icmp: Icmpv4State<BT>,
1952 pub next_packet_id: AtomicU16,
1954}
1955
1956impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1957 AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
1958{
1959 fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
1960 &self.inner
1961 }
1962}
1963
1964pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
1968 core_ctx: &mut CC,
1969) -> I::PacketId {
1970 core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
1971}
1972
1973pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1975 pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
1977 pub icmp: Icmpv6State<BT>,
1979 pub slaac_counters: SlaacCounters,
1981 pub slaac_temp_secret_key: IidSecret,
1983 pub slaac_stable_secret_key: IidSecret,
1988}
1989
1990impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1991 AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
1992{
1993 fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
1994 &self.inner
1995 }
1996}
1997
1998impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1999 OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
2000{
2001 type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
2002 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2003 OrderedLockRef::new(&self.fragment_cache)
2004 }
2005}
2006
2007impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2008 OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
2009{
2010 type Lock = Mutex<PmtuCache<I, BT>>;
2011 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2012 OrderedLockRef::new(&self.pmtu_cache)
2013 }
2014}
2015
2016impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2017 OrderedLockAccess<RulesTable<I, D, BT>> for IpStateInner<I, D, BT>
2018{
2019 type Lock = RwLock<RulesTable<I, D, BT>>;
2020 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2021 OrderedLockRef::new(&self.rules_table)
2022 }
2023}
2024
2025impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2026 OrderedLockAccess<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>
2027 for IpStateInner<I, D, BT>
2028{
2029 type Lock =
2030 Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>;
2031 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2032 OrderedLockRef::new(&self.tables)
2033 }
2034}
2035
2036impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpRoutingBindingsTypes>
2037 OrderedLockAccess<RoutingTable<I, D>> for RoutingTableId<I, D, BT>
2038{
2039 type Lock = RwLock<RoutingTable<I, D>>;
2040 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2041 let Self(inner) = self;
2042 OrderedLockRef::new(&inner.routing_table)
2043 }
2044}
2045
2046impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2047 OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
2048{
2049 type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
2050 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2051 OrderedLockRef::new(&self.multicast_forwarding)
2052 }
2053}
2054
2055impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2056 OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
2057{
2058 type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
2059 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2060 OrderedLockRef::new(&self.raw_sockets)
2061 }
2062}
2063
2064impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2065 OrderedLockAccess<filter::State<I, WeakAddressId<I, BT>, BT>> for IpStateInner<I, D, BT>
2066{
2067 type Lock = RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>;
2068 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2069 OrderedLockRef::new(&self.filter)
2070 }
2071}
2072
2073pub trait IpStateBindingsTypes:
2075 PmtuBindingsTypes
2076 + FragmentBindingsTypes
2077 + RawIpSocketsBindingsTypes
2078 + FilterBindingsTypes
2079 + MulticastForwardingBindingsTypes
2080 + IpDeviceStateBindingsTypes
2081 + IpRoutingBindingsTypes
2082{
2083}
2084impl<BT> IpStateBindingsTypes for BT where
2085 BT: PmtuBindingsTypes
2086 + FragmentBindingsTypes
2087 + RawIpSocketsBindingsTypes
2088 + FilterBindingsTypes
2089 + MulticastForwardingBindingsTypes
2090 + IpDeviceStateBindingsTypes
2091 + IpRoutingBindingsTypes
2092{
2093}
2094
2095#[derive(Derivative)]
2097#[derivative(Debug(bound = ""))]
2098#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2099pub enum RoutingTableCookie<BT: IpRoutingBindingsTypes> {
2100 Main,
2102 BindingsId(BT::RoutingTableId),
2104}
2105
2106#[derive(Derivative)]
2108#[derivative(Debug(bound = "D: Debug"))]
2109pub struct BaseRoutingTableState<I: Ip, D, BT: IpRoutingBindingsTypes> {
2110 routing_table: RwLock<RoutingTable<I, D>>,
2111 bindings_id: RoutingTableCookie<BT>,
2112}
2113
2114impl<I: Ip, D, BT: IpRoutingBindingsTypes> BaseRoutingTableState<I, D, BT> {
2115 pub(crate) fn with_bindings_id(bindings_id: RoutingTableCookie<BT>) -> Self {
2116 Self { bindings_id, routing_table: Default::default() }
2117 }
2118}
2119
2120#[derive(Derivative)]
2122#[derivative(PartialEq(bound = ""))]
2123#[derivative(Eq(bound = ""))]
2124#[derivative(Hash(bound = ""))]
2125#[derivative(Clone(bound = ""))]
2126pub struct RoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes>(
2127 StrongRc<BaseRoutingTableState<I, D, BT>>,
2128);
2129
2130impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for RoutingTableId<I, D, BT> {
2131 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2132 let Self(rc) = self;
2133 f.debug_tuple("RoutingTableId").field(&I::NAME).field(&rc.bindings_id).finish()
2134 }
2135}
2136
2137impl<I: Ip, D, BT: IpRoutingBindingsTypes> RoutingTableId<I, D, BT> {
2138 pub(crate) fn new(rc: StrongRc<BaseRoutingTableState<I, D, BT>>) -> Self {
2140 Self(rc)
2141 }
2142
2143 #[cfg(any(test, feature = "testutils"))]
2145 pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
2146 let Self(inner) = self;
2147 &inner.routing_table
2148 }
2149
2150 pub fn downgrade(&self) -> WeakRoutingTableId<I, D, BT>
2152 where
2153 BT::RoutingTableId: Clone,
2154 {
2155 let Self(rc) = self;
2156 WeakRoutingTableId { rc: StrongRc::downgrade(rc), bindings_id: rc.bindings_id.clone() }
2157 }
2158
2159 #[cfg(test)]
2160 fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2161 let Self(rc) = self;
2162 rc.routing_table.write()
2163 }
2164
2165 pub fn bindings_id(&self) -> &RoutingTableCookie<BT> {
2167 let Self(rc) = self;
2168 &rc.bindings_id
2169 }
2170}
2171
2172#[derive(Derivative)]
2174#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2175#[derivative(PartialEq, Eq, Hash)]
2176pub struct WeakRoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes> {
2177 rc: WeakRc<BaseRoutingTableState<I, D, BT>>,
2178 #[derivative(PartialEq = "ignore")]
2179 #[derivative(Hash = "ignore")]
2180 bindings_id: RoutingTableCookie<BT>,
2181}
2182
2183impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for WeakRoutingTableId<I, D, BT> {
2184 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2185 let Self { bindings_id, .. } = self;
2186 f.debug_tuple("WeakRoutingTableId").field(&I::NAME).field(bindings_id).finish()
2187 }
2188}
2189
2190#[derive(GenericOverIp)]
2192#[generic_over_ip(I, Ip)]
2193pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2194 rules_table: RwLock<RulesTable<I, D, BT>>,
2195 main_table_id: RoutingTableId<I, D, BT>,
2197 multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2198 multicast_forwarding_counters: MulticastForwardingCounters<I>,
2199 fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2200 pmtu_cache: Mutex<PmtuCache<I, BT>>,
2201 counters: IpCounters<I>,
2202 raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2203 raw_socket_counters: RawIpSocketCounters<I>,
2204 filter: RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>,
2205 tables: Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>,
2211 igmp_counters: IgmpCounters,
2212 mld_counters: MldCounters,
2213}
2214
2215impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2216 pub fn counters(&self) -> &IpCounters<I> {
2218 &self.counters
2219 }
2220
2221 pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2223 &self.multicast_forwarding_counters
2224 }
2225
2226 pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2228 &self.raw_socket_counters
2229 }
2230
2231 pub fn main_table_id(&self) -> &RoutingTableId<I, D, BT> {
2233 &self.main_table_id
2234 }
2235
2236 #[cfg(any(test, feature = "testutils"))]
2238 pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2239 &self.pmtu_cache
2240 }
2241
2242 #[cfg(any(test, feature = "testutils"))]
2244 pub fn filter(&self) -> &RwLock<filter::State<I, WeakAddressId<I, BT>, BT>> {
2245 &self.filter
2246 }
2247
2248 pub fn igmp_counters(&self) -> &IgmpCounters {
2250 &self.igmp_counters
2251 }
2252
2253 pub fn mld_counters(&self) -> &MldCounters {
2255 &self.mld_counters
2256 }
2257}
2258
2259impl<
2260 I: IpLayerIpExt,
2261 D: StrongDeviceIdentifier,
2262 BC: TimerContext + RngContext + IpStateBindingsTypes + IpRoutingBindingsTypes,
2263> IpStateInner<I, D, BC>
2264{
2265 fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2267 let main_table: PrimaryRc<BaseRoutingTableState<I, D, BC>> =
2268 PrimaryRc::new(BaseRoutingTableState::with_bindings_id(RoutingTableCookie::Main));
2269 let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2270 Self {
2271 rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2272 tables: Mutex::new(HashMap::from_iter(core::iter::once((
2273 main_table_id.clone(),
2274 main_table,
2275 )))),
2276 main_table_id,
2277 multicast_forwarding: Default::default(),
2278 multicast_forwarding_counters: Default::default(),
2279 fragment_cache: Mutex::new(
2280 IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2281 ),
2282 pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2283 counters: Default::default(),
2284 raw_sockets: Default::default(),
2285 raw_socket_counters: Default::default(),
2286 filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2287 igmp_counters: Default::default(),
2288 mld_counters: Default::default(),
2289 }
2290 }
2291}
2292
2293#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2295#[generic_over_ip()]
2296pub enum IpLayerTimerId {
2297 ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2299 ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2301 PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2303 PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2305 FilterTimerv4(FilterTimerId<Ipv4>),
2307 FilterTimerv6(FilterTimerId<Ipv6>),
2309 MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2311 MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2313}
2314
2315impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2316 fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2317 I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2318 }
2319}
2320
2321impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2322 fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2323 I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2324 }
2325}
2326
2327impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2328 fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2329 I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2330 }
2331}
2332
2333impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2334 fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2335 I::map_ip(
2336 timer,
2337 IpLayerTimerId::MulticastForwardingTimerv4,
2338 IpLayerTimerId::MulticastForwardingTimerv6,
2339 )
2340 }
2341}
2342
2343impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2344where
2345 CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2346 + TimerHandler<BC, FragmentTimerId<Ipv6>>
2347 + TimerHandler<BC, PmtuTimerId<Ipv4>>
2348 + TimerHandler<BC, PmtuTimerId<Ipv6>>
2349 + TimerHandler<BC, FilterTimerId<Ipv4>>
2350 + TimerHandler<BC, FilterTimerId<Ipv6>>
2351 + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2352 + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2353 BC: TimerBindingsTypes,
2354{
2355 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2356 match self {
2357 IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2358 core_ctx.handle_timer(bindings_ctx, id, timer)
2359 }
2360 IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2361 core_ctx.handle_timer(bindings_ctx, id, timer)
2362 }
2363 IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2364 IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2365 IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2366 IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2367 IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2368 core_ctx.handle_timer(bindings_ctx, id, timer)
2369 }
2370 IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2371 core_ctx.handle_timer(bindings_ctx, id, timer)
2372 }
2373 }
2374 }
2375}
2376
2377pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2384 err: I::IcmpError,
2386 src_ip: SocketIpAddr<I::Addr>,
2389 dst_ip: SocketIpAddr<I::Addr>,
2392 frame_dst: Option<FrameDestination>,
2394 device: &'a D,
2396 meta: ParseMetadata,
2399 marks: Marks,
2401 proto: I::Proto,
2403}
2404
2405impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2406 pub fn new<CC, B>(
2407 core_ctx: &mut CC,
2408 err: I::IcmpError,
2409 packet: &I::Packet<B>,
2410 frame_dst: Option<FrameDestination>,
2411 device: &'a D,
2412 marks: Marks,
2413 ) -> Option<Self>
2414 where
2415 I: IpCountersIpExt,
2416 CC: ResourceCounterContext<D, IpCounters<I>>,
2417 B: SplitByteSlice,
2418 {
2419 let Some(src_ip) = SocketIpAddr::new(packet.src_ip()) else {
2420 core_ctx.increment_both(device, |c| &c.unspecified_source);
2421 return None;
2422 };
2423 let Some(dst_ip) = SocketIpAddr::new(packet.dst_ip()) else {
2424 return None;
2425 };
2426
2427 let is_ipv4_fragment = I::map_ip_in(
2429 packet,
2430 |p| {
2431 packet_formats::ipv4::Ipv4Header::fragment_type(p)
2432 == Ipv4FragmentType::NonInitialFragment
2433 },
2434 |_| false,
2435 );
2436 if is_ipv4_fragment {
2437 return None;
2438 }
2439
2440 let meta = packet.parse_metadata();
2441 let proto = packet.proto();
2442 Some(Self { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto })
2443 }
2444
2445 pub fn send<B, BC, CC>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, mut body: B)
2452 where
2453 B: BufferMut,
2454 CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2455 {
2456 let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto } = self;
2457 let header_len = meta.header_len();
2458
2459 body.undo_parse(meta);
2463
2464 core_ctx.send_icmp_error_message(
2465 bindings_ctx,
2466 Some(device),
2467 frame_dst,
2468 src_ip,
2469 dst_ip,
2470 body,
2471 err,
2472 header_len,
2473 proto,
2474 &marks,
2475 );
2476 }
2477}
2478
2479#[derive(PartialEq, Eq)]
2485struct EarlyDemuxResult<I: Ip, S> {
2486 socket: S,
2487 src_addr: I::Addr,
2488 src_port: Option<u16>,
2489}
2490
2491impl<I: FilterIpExt, S> EarlyDemuxResult<I, S> {
2492 fn new<P: IpPacket<I>>(socket: S, packet: &P) -> Self {
2493 let src_port =
2494 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port());
2495 Self { socket, src_addr: packet.src_addr(), src_port }
2496 }
2497
2498 fn take_socket<P: IpPacket<I>>(self, packet: &P) -> Option<S> {
2500 let src_port =
2501 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port());
2502 (self.src_addr == packet.src_addr() && self.src_port == src_port).then_some(self.socket)
2503 }
2504
2505 fn update_packet_metadata<CC, BC>(
2506 &self,
2507 core_ctx: &mut CC,
2508 packet_metadata: &mut IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2509 ) where
2510 I: IpLayerIpExt,
2511 S: SocketMetadata<CC>,
2512 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2513 CC: IpLayerIngressContext<I, BC>,
2514 {
2515 packet_metadata.socket_cookie = Some(self.socket.socket_cookie(core_ctx));
2516 for mark in BC::marks_to_set_on_ingress() {
2517 *packet_metadata.marks.get_mut(*mark) = self.socket.marks(core_ctx).get(*mark).clone();
2518 }
2519 }
2520}
2521
2522pub(crate) fn reject_type_to_icmpv4_error(reject_type: RejectType) -> Option<Icmpv4Error> {
2523 let error = match reject_type {
2524 RejectType::NetUnreachable => Icmpv4Error::NetUnreachable,
2525 RejectType::ProtoUnreachable => Icmpv4Error::ProtocolUnreachable,
2526 RejectType::PortUnreachable => Icmpv4Error::PortUnreachable,
2527 RejectType::HostUnreachable => Icmpv4Error::HostUnreachable,
2528 RejectType::RoutePolicyFail => Icmpv4Error::NetworkProhibited,
2529 RejectType::RejectRoute => Icmpv4Error::HostProhibited,
2530 RejectType::AdminProhibited => Icmpv4Error::AdminProhibited,
2531 RejectType::TcpReset => return None,
2533 };
2534 Some(error)
2535}
2536
2537pub(crate) fn reject_type_to_icmpv6_error(reject_type: RejectType) -> Option<Icmpv6Error> {
2538 let error = match reject_type {
2539 RejectType::NetUnreachable => Icmpv6Error::NetUnreachable,
2540 RejectType::PortUnreachable => Icmpv6Error::PortUnreachable,
2541 RejectType::HostUnreachable => Icmpv6Error::AddressUnreachable,
2542 RejectType::AdminProhibited => Icmpv6Error::AdminProhibited,
2543 RejectType::RoutePolicyFail => Icmpv6Error::SourceAddressPolicyFailed,
2544 RejectType::RejectRoute => Icmpv6Error::RejectRoute,
2545 RejectType::TcpReset | RejectType::ProtoUnreachable => return None,
2547 };
2548 Some(error)
2549}
2550fn dispatch_receive_ipv4_packet<
2571 'a,
2572 'b,
2573 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2574 CC: IpLayerIngressContext<Ipv4, BC>,
2575>(
2576 core_ctx: &'a mut CC,
2577 bindings_ctx: &'a mut BC,
2578 device: &'b CC::DeviceId,
2579 frame_dst: Option<FrameDestination>,
2580 mut packet: Ipv4Packet<&'a mut [u8]>,
2581 mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2582 receive_meta: ReceiveIpPacketMeta<Ipv4>,
2583) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2584 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2585
2586 match frame_dst {
2587 Some(FrameDestination::Individual { local: false }) => {
2588 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2589 }
2590 Some(FrameDestination::Individual { local: true })
2591 | Some(FrameDestination::Multicast)
2592 | Some(FrameDestination::Broadcast)
2593 | None => (),
2594 };
2595
2596 let early_demux_result = receive_meta
2599 .transparent_override
2600 .is_none()
2601 .then(|| {
2602 core_ctx.early_demux(
2603 device,
2604 frame_dst,
2605 packet.src_ip(),
2606 packet.dst_ip(),
2607 packet.proto(),
2608 packet.body(),
2609 )
2610 })
2611 .flatten()
2612 .map(|socket| {
2613 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2614 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2615 early_demux_result
2616 });
2617
2618 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2619 bindings_ctx,
2620 &mut packet,
2621 device,
2622 &mut packet_metadata,
2623 );
2624
2625 let marks = packet_metadata.marks;
2626 packet_metadata.acknowledge_drop();
2627
2628 match filter_verdict {
2629 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2630 return Ok(());
2631 }
2632 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2633 return match reject_type_to_icmpv4_error(reject_type) {
2634 Some(icmp_error) => {
2635 match IcmpErrorSender::new(
2636 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2637 ) {
2638 Some(icmp_sender) => Err(icmp_sender),
2639 None => Ok(()),
2640 }
2641 }
2642 None => {
2643 debug!("Unsupported reject type: {:?}", reject_type);
2644 return Ok(());
2645 }
2646 };
2647 }
2648 filter::Verdict::Proceed(filter::Accept) => (),
2649 };
2650
2651 let Some(src_ip) = packet.src_ipv4() else {
2655 debug!(
2656 "dispatch_receive_ipv4_packet: received packet from invalid source {} after the \
2657 LOCAL_INGRESS hook; dropping",
2658 packet.src_ip()
2659 );
2660 core_ctx.increment_both(device, |c| &c.invalid_source);
2661 return Ok(());
2662 };
2663 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2664 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2665 debug!(
2666 "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2667 after the LOCAL_INGRESS hook; dropping"
2668 );
2669 return Ok(());
2670 };
2671
2672 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2673
2674 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2676
2677 let proto = packet.proto();
2678 let (prefix, options, body) = packet.parts_with_body_mut();
2679 let buffer = Buf::new(body, ..);
2680 let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2681 let mut receive_info = LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks };
2682
2683 core_ctx
2684 .dispatch_receive_ip_packet(
2685 bindings_ctx,
2686 device,
2687 src_ip,
2688 dst_ip,
2689 proto,
2690 buffer,
2691 &mut receive_info,
2692 early_demux_socket,
2693 )
2694 .or_else(|icmp_error| {
2695 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2696 Some(icmp_sender) => Err(icmp_sender),
2697 None => Ok(()),
2698 }
2699 })
2700}
2701
2702fn dispatch_receive_ipv6_packet<
2707 'a,
2708 'b,
2709 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2710 CC: IpLayerIngressContext<Ipv6, BC>,
2711>(
2712 core_ctx: &'a mut CC,
2713 bindings_ctx: &'a mut BC,
2714 device: &'b CC::DeviceId,
2715 frame_dst: Option<FrameDestination>,
2716 mut packet: Ipv6Packet<&'a mut [u8]>,
2717 mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2718 meta: ReceiveIpPacketMeta<Ipv6>,
2719) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2720 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2727
2728 match frame_dst {
2729 Some(FrameDestination::Individual { local: false }) => {
2730 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2731 }
2732 Some(FrameDestination::Individual { local: true })
2733 | Some(FrameDestination::Multicast)
2734 | Some(FrameDestination::Broadcast)
2735 | None => (),
2736 }
2737
2738 let early_demux_result = meta
2741 .transparent_override
2742 .is_none()
2743 .then(|| {
2744 core_ctx.early_demux(
2745 device,
2746 frame_dst,
2747 packet.src_ip(),
2748 packet.dst_ip(),
2749 packet.proto(),
2750 packet.body(),
2751 )
2752 })
2753 .flatten()
2754 .map(|socket| {
2755 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2756 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2757 early_demux_result
2758 });
2759
2760 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2761 bindings_ctx,
2762 &mut packet,
2763 device,
2764 &mut packet_metadata,
2765 );
2766
2767 let marks = packet_metadata.marks;
2768 packet_metadata.acknowledge_drop();
2769
2770 match filter_verdict {
2771 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2772 return Ok(());
2773 }
2774 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2775 return match reject_type_to_icmpv6_error(reject_type) {
2776 Some(icmp_error) => {
2777 match IcmpErrorSender::new(
2778 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2779 ) {
2780 Some(icmp_sender) => Err(icmp_sender),
2781 None => Ok(()),
2782 }
2783 }
2784 None => {
2785 debug!("Unsupported reject type: {:?}", reject_type);
2786 return Ok(());
2787 }
2788 };
2789 }
2790 filter::Verdict::Proceed(filter::Accept) => {}
2791 }
2792
2793 let Some(src_ip) = packet.src_ipv6() else {
2797 debug!(
2798 "dispatch_receive_ipv6_packet: received packet from invalid source {} after the \
2799 LOCAL_INGRESS hook; dropping",
2800 packet.src_ip()
2801 );
2802
2803 core_ctx.increment_both(device, |c| &c.invalid_source);
2804 return Ok(());
2805 };
2806 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2807 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2808 debug!(
2809 "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2810 after the LOCAL_INGRESS hook; dropping"
2811 );
2812 return Ok(());
2813 };
2814
2815 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2816
2817 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2819
2820 let proto = packet.proto();
2821 let (fixed, extension, body) = packet.parts_with_body_mut();
2822 let buffer = Buf::new(body, ..);
2823 let header_info = Ipv6HeaderInfo { fixed, extension };
2824 let mut receive_info = LocalDeliveryPacketInfo { meta, header_info, marks };
2825
2826 core_ctx
2827 .dispatch_receive_ip_packet(
2828 bindings_ctx,
2829 device,
2830 src_ip,
2831 dst_ip,
2832 proto,
2833 buffer,
2834 &mut receive_info,
2835 early_demux_socket,
2836 )
2837 .or_else(|icmp_error| {
2838 let marks = receive_info.marks;
2839 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2840 Some(icmp_sender) => Err(icmp_sender),
2841 None => Ok(()),
2842 }
2843 })
2844}
2845
2846pub(crate) struct IpPacketForwarder<
2853 'a,
2854 I: IpLayerIpExt,
2855 D,
2856 A,
2857 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2858> {
2859 inbound_device: &'a D,
2860 outbound_device: &'a D,
2861 packet_meta: IpLayerPacketMetadata<I, A, BT>,
2862 src_ip: I::RecvSrcAddr,
2863 dst_ip: SpecifiedAddr<I::Addr>,
2864 destination: IpPacketDestination<I, &'a D>,
2865 proto: I::Proto,
2866 parse_meta: ParseMetadata,
2867 frame_dst: Option<FrameDestination>,
2868}
2869
2870impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
2871where
2872 I: IpLayerIpExt,
2873 BC: IpLayerBindingsContext<I, D>,
2874{
2875 fn forward_with_buffer<CC, B>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B)
2877 where
2878 B: BufferMut,
2879 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2880 {
2881 let Self {
2882 inbound_device,
2883 outbound_device,
2884 packet_meta,
2885 src_ip,
2886 dst_ip,
2887 destination,
2888 proto,
2889 parse_meta,
2890 frame_dst,
2891 } = self;
2892
2893 let packet = ForwardedPacket::new(src_ip.get(), dst_ip.get(), proto, parse_meta, buffer);
2894
2895 trace!("forward_with_buffer: forwarding {} packet", I::NAME);
2896
2897 let marks = packet_meta.marks;
2898 match send_ip_frame(
2899 core_ctx,
2900 bindings_ctx,
2901 outbound_device,
2902 destination,
2903 packet,
2904 packet_meta,
2905 Mtu::no_limit(),
2906 ) {
2907 Ok(()) => (),
2908 Err(IpSendFrameError { serializer, error }) => {
2909 match error {
2910 IpSendFrameErrorReason::Device(
2911 SendFrameErrorReason::SizeConstraintsViolation,
2912 ) => {
2913 debug!("failed to forward {} packet: MTU exceeded", I::NAME);
2914 core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
2915 let mtu = core_ctx.get_mtu(inbound_device);
2916 let Some(err) = I::IcmpError::mtu_exceeded(mtu) else {
2918 return;
2919 };
2920 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2923 return;
2924 };
2925
2926 let Some(dst_ip) = SocketIpAddr::new(dst_ip.get()) else {
2927 return;
2928 };
2929
2930 core_ctx.send_icmp_error_message(
2940 bindings_ctx,
2941 Some(inbound_device),
2942 frame_dst,
2943 src_ip,
2944 dst_ip,
2945 serializer.into_buffer(),
2946 err,
2947 parse_meta.header_len(),
2948 proto,
2949 &marks,
2950 );
2951 }
2952 IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
2953 | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
2954 | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
2955 }
2956 debug!("failed to forward {} packet: {error:?}", I::NAME);
2957 }
2958 }
2959 }
2960}
2961
2962pub(crate) enum ForwardingAction<
2964 'a,
2965 I: IpLayerIpExt,
2966 D,
2967 A,
2968 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2969> {
2970 SilentlyDrop,
2972 Forward(IpPacketForwarder<'a, I, D, A, BT>),
2974 DropWithIcmpError(IcmpErrorSender<'a, I, D>),
2977}
2978
2979impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
2980where
2981 I: IpLayerIpExt,
2982 BC: IpLayerBindingsContext<I, D>,
2983{
2984 pub(crate) fn perform_action_with_buffer<CC, B>(
2986 self,
2987 core_ctx: &mut CC,
2988 bindings_ctx: &mut BC,
2989 buffer: B,
2990 ) where
2991 B: BufferMut,
2992 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2993 {
2994 match self {
2995 ForwardingAction::SilentlyDrop => {}
2996 ForwardingAction::Forward(forwarder) => {
2997 forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer)
2998 }
2999 ForwardingAction::DropWithIcmpError(icmp_sender) => {
3000 icmp_sender.send(core_ctx, bindings_ctx, buffer)
3001 }
3002 }
3003 }
3004}
3005
3006pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
3008 core_ctx: &'a mut CC,
3009 mut packet: I::Packet<&'a mut [u8]>,
3010 mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3011 minimum_ttl: Option<u8>,
3012 inbound_device: &'b CC::DeviceId,
3013 outbound_device: &'b CC::DeviceId,
3014 destination: IpPacketDestination<I, &'b CC::DeviceId>,
3015 frame_dst: Option<FrameDestination>,
3016 src_ip: I::RecvSrcAddr,
3017 dst_ip: SpecifiedAddr<I::Addr>,
3018) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
3019where
3020 I: IpLayerIpExt,
3021 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3022 CC: IpLayerForwardingContext<I, BC>,
3023{
3024 const DEFAULT_MINIMUM_FORWARDING_TTL: u8 = 2;
3029 let minimum_ttl = minimum_ttl.unwrap_or(DEFAULT_MINIMUM_FORWARDING_TTL);
3030
3031 let ttl = packet.ttl();
3032 if ttl < minimum_ttl {
3033 debug!(
3034 "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
3035 I::NAME
3036 );
3037 if ttl > 1 {
3049 packet_meta.acknowledge_drop();
3050 return ForwardingAction::SilentlyDrop;
3051 }
3052
3053 core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
3054
3055 let marks = packet_meta.marks;
3056 packet_meta.acknowledge_drop();
3057
3058 match IcmpErrorSender::new(
3060 core_ctx,
3061 I::IcmpError::ttl_expired(),
3062 &packet,
3063 frame_dst,
3064 inbound_device,
3065 marks,
3066 ) {
3067 Some(icmp_sender) => return ForwardingAction::DropWithIcmpError(icmp_sender),
3068 None => return ForwardingAction::SilentlyDrop,
3069 }
3070 }
3071
3072 trace!("determine_ip_packet_forwarding_action: adequate TTL");
3073
3074 let maybe_ipv6_packet_action = I::map_ip_in(
3080 &packet,
3081 |_packet| None,
3082 |packet| {
3083 Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
3084 },
3085 );
3086 match maybe_ipv6_packet_action {
3087 None => {} Some(Ipv6PacketAction::_Discard) => {
3089 core_ctx.increment_both(inbound_device, |c| {
3090 #[derive(GenericOverIp)]
3091 #[generic_over_ip(I, Ip)]
3092 struct InCounters<'a, I: IpLayerIpExt>(
3093 &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<Counter>,
3094 );
3095 I::map_ip_in::<_, _>(
3096 InCounters(&c.version_rx),
3097 |_counters| {
3098 unreachable!(
3099 "`I` must be `Ipv6` because we're handling IPv6 extension headers"
3100 )
3101 },
3102 |InCounters(counters)| &counters.extension_header_discard,
3103 )
3104 });
3105 trace!(
3106 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3107 discarding packet"
3108 );
3109 packet_meta.acknowledge_drop();
3110 return ForwardingAction::SilentlyDrop;
3111 }
3112 Some(Ipv6PacketAction::Continue) => {
3113 trace!(
3114 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3115 forwarding packet"
3116 );
3117 }
3118 Some(Ipv6PacketAction::ProcessFragment) => {
3119 unreachable!(
3120 "When forwarding packets, we should only ever look at the hop by hop \
3121 options extension header (if present)"
3122 )
3123 }
3124 };
3125
3126 match core_ctx.filter_handler().forwarding_hook(
3127 I::as_filter_packet(&mut packet),
3128 inbound_device,
3129 outbound_device,
3130 &mut packet_meta,
3131 ) {
3132 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3133 packet_meta.acknowledge_drop();
3134 trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
3135 return ForwardingAction::SilentlyDrop;
3136 }
3137 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
3138 packet_meta.acknowledge_drop();
3140 trace!(
3141 "determine_ip_packet_forwarding_action: filter verdict: Reject({:?})",
3142 reject_type
3143 );
3144 return ForwardingAction::SilentlyDrop;
3145 }
3146 filter::Verdict::Proceed(filter::Accept) => {}
3147 }
3148
3149 packet.set_ttl(ttl - 1);
3150 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
3151 ForwardingAction::Forward(IpPacketForwarder {
3152 inbound_device,
3153 outbound_device,
3154 packet_meta,
3155 src_ip,
3156 dst_ip,
3157 destination,
3158 proto,
3159 parse_meta,
3160 frame_dst,
3161 })
3162}
3163
3164pub(crate) fn send_ip_frame<I, CC, BC, S>(
3165 core_ctx: &mut CC,
3166 bindings_ctx: &mut BC,
3167 device: &CC::DeviceId,
3168 destination: IpPacketDestination<I, &CC::DeviceId>,
3169 mut body: S,
3170 mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3171 limit_mtu: Mtu,
3172) -> Result<(), IpSendFrameError<S>>
3173where
3174 I: IpLayerIpExt,
3175 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3176 CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
3177 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>,
3178{
3179 let (verdict, proof) = core_ctx.filter_handler().egress_hook(
3180 bindings_ctx,
3181 &mut body,
3182 device,
3183 &mut packet_metadata,
3184 );
3185 match verdict {
3186 filter::Verdict::Stop(filter::DropPacket) => {
3187 packet_metadata.acknowledge_drop();
3188 return Ok(());
3189 }
3190 filter::Verdict::Proceed(filter::Accept) => {}
3191 }
3192
3193 let (conntrack_connection_and_direction, tx_metadata, marks, _socket_cookie) =
3197 packet_metadata.into_parts();
3198 let conntrack_entry = if device.is_loopback() {
3199 conntrack_connection_and_direction
3200 .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
3201 } else {
3202 None
3203 };
3204
3205 let mut device_layer_marks = Marks::default();
3206 for mark in BC::marks_to_keep_on_egress() {
3207 *device_layer_marks.get_mut(*mark) = *marks.get(*mark);
3208 }
3209
3210 let device_ip_layer_metadata =
3211 DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks: device_layer_marks };
3212
3213 if !device.is_loopback()
3217 && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
3218 || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
3219 {
3220 core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
3221 return Err(IpSendFrameError {
3222 serializer: body,
3223 error: IpSendFrameErrorReason::IllegalLoopbackAddress,
3224 });
3225 }
3226
3227 let mtu = limit_mtu.min(core_ctx.get_mtu(device));
3229
3230 let body = body.with_size_limit(mtu.into());
3231
3232 let fits_mtu = match body.serialize_new_buf(
3233 &mut NetworkSerializationContext::default(),
3234 PacketConstraints::UNCONSTRAINED,
3235 AlwaysFailBufferAlloc,
3236 ) {
3237 Err(SerializeError::Alloc(())) => true,
3240 Err(SerializeError::SizeLimitExceeded) => false,
3242 };
3243
3244 if fits_mtu {
3245 return core_ctx
3246 .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
3247 .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
3248 serializer: serializer.into_inner(),
3249 error: error.into(),
3250 });
3251 }
3252
3253 core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
3256
3257 let mut device_ip_layer_metadata = Some(device_ip_layer_metadata);
3259 let body = body.into_inner();
3260 let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
3261 Ok(mut fragmenter) => loop {
3262 let (fragment, has_more) = match fragmenter.next() {
3263 None => break Ok(()),
3264 Some(f) => f,
3265 };
3266
3267 let device_ip_layer_metadata = if has_more {
3272 let device_ip_layer_metadata = device_ip_layer_metadata.as_ref().unwrap();
3274 DeviceIpLayerMetadata {
3275 conntrack_entry: device_ip_layer_metadata.conntrack_entry.clone(),
3276 tx_metadata: Default::default(),
3277 marks: device_ip_layer_metadata.marks,
3278 }
3279 } else {
3280 device_ip_layer_metadata.take().unwrap()
3282 };
3283
3284 match core_ctx.send_ip_frame(
3285 bindings_ctx,
3286 device,
3287 destination.clone(),
3288 device_ip_layer_metadata,
3289 fragment,
3290 proof.clone_for_fragmentation(),
3291 ) {
3292 Ok(()) => {
3293 core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
3294 }
3295 Err(ErrorAndSerializer { serializer: _, error }) => {
3296 core_ctx
3297 .increment_both(device, |c| &c.fragmentation.error_fragmented_serializer);
3298 break Err(error);
3299 }
3300 }
3301 },
3302 Err(e) => {
3303 core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
3304 Err(SendFrameErrorReason::SizeConstraintsViolation)
3305 }
3306 };
3307 result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
3308}
3309
3310struct AlwaysFailBufferAlloc;
3315
3316impl LayoutBufferAlloc<Never> for AlwaysFailBufferAlloc {
3317 type Error = ();
3318 fn layout_alloc(
3319 self,
3320 _prefix: usize,
3321 _body: usize,
3322 _suffix: usize,
3323 ) -> Result<Never, Self::Error> {
3324 Err(())
3325 }
3326}
3327
3328macro_rules! drop_packet_and_undo_parse {
3337 ($packet:expr, $buffer:expr) => {{
3338 let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
3339 $buffer.undo_parse(meta);
3340 (src_ip, dst_ip, proto, meta)
3341 }};
3342}
3343
3344enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
3347 Done,
3350
3351 NotNeeded(I::Packet<&'a mut [u8]>),
3354
3355 Reassembled(Vec<u8>),
3358}
3359
3360fn process_fragment<'a, I, CC, BC>(
3366 core_ctx: &mut CC,
3367 bindings_ctx: &mut BC,
3368 device: &CC::DeviceId,
3369 packet: I::Packet<&'a mut [u8]>,
3370) -> ProcessFragmentResult<'a, I>
3371where
3372 I: IpLayerIpExt,
3373 for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3374 CC: IpLayerIngressContext<I, BC>,
3375 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3376{
3377 match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3378 FragmentProcessingState::NotNeeded(packet) => {
3380 trace!("receive_ip_packet: not fragmented");
3381 ProcessFragmentResult::NotNeeded(packet)
3382 }
3383 FragmentProcessingState::Ready { key, packet_len } => {
3385 trace!("receive_ip_packet: fragmented, ready for reassembly");
3386 let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3388
3389 let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3391 core_ctx,
3392 bindings_ctx,
3393 &key,
3394 buffer.buffer_view_mut(),
3395 ) {
3396 Ok(()) => ProcessFragmentResult::Reassembled(buffer.into_inner()),
3398 Err(e) => {
3399 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3400 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3401 ProcessFragmentResult::Done
3402 }
3403 };
3404 reassemble_result
3405 }
3406 FragmentProcessingState::NeedMoreFragments => {
3409 core_ctx.increment_both(device, |c| &c.need_more_fragments);
3410 trace!("receive_ip_packet: fragmented, need more before reassembly");
3411 ProcessFragmentResult::Done
3412 }
3413 FragmentProcessingState::InvalidFragment => {
3415 core_ctx.increment_both(device, |c| &c.invalid_fragment);
3416 trace!("receive_ip_packet: fragmented, invalid");
3417 ProcessFragmentResult::Done
3418 }
3419 FragmentProcessingState::OutOfMemory => {
3420 core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3421 trace!("receive_ip_packet: fragmented, dropped because OOM");
3422 ProcessFragmentResult::Done
3423 }
3424 }
3425}
3426
3427macro_rules! try_parse_ip_packet {
3437 ($buffer:expr) => {{
3438 let p_len = $buffer.prefix_len();
3439 let s_len = $buffer.suffix_len();
3440
3441 let result = $buffer.parse_mut();
3442
3443 if let Err(err) = result {
3444 let n_p_len = $buffer.prefix_len();
3446 let n_s_len = $buffer.suffix_len();
3447
3448 if n_p_len > p_len {
3449 $buffer.grow_front(n_p_len - p_len);
3450 }
3451
3452 if n_s_len > s_len {
3453 $buffer.grow_back(n_s_len - s_len);
3454 }
3455
3456 Err(err)
3457 } else {
3458 result
3459 }
3460 }};
3461}
3462
3463macro_rules! clone_packet_for_mcast_forwarding {
3481 {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3482 let mut $new_data = $packet.to_vec();
3483 let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3484 let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3485 };
3486}
3487
3488pub fn receive_ipv4_packet<
3493 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3494 B: BufferMut,
3495 CC: IpLayerIngressContext<Ipv4, BC>,
3496>(
3497 core_ctx: &mut CC,
3498 bindings_ctx: &mut BC,
3499 device: &CC::DeviceId,
3500 frame_dst: Option<FrameDestination>,
3501 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3502 parsing_context: NetworkParsingContext,
3503 buffer: B,
3504) {
3505 if !core_ctx.is_ip_device_enabled(&device) {
3506 return;
3507 }
3508
3509 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3512
3513 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3514 trace!("receive_ip_packet({device:?})");
3515
3516 let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3517 Ok(packet) => packet,
3518 Err(ParseError::Format)
3519 | Err(ParseError::Checksum)
3520 | Err(ParseError::NotSupported)
3521 | Err(ParseError::NotExpected) => {
3522 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3523 return;
3524 }
3525 };
3526
3527 if packet.src_ipv4().is_none() {
3531 debug!(
3532 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3533 packet.src_ip()
3534 );
3535 core_ctx.increment_both(device, |c| &c.invalid_source);
3536 return;
3537 };
3538 if !packet.dst_ip().is_specified() {
3539 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3540 debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3541 return;
3542 };
3543
3544 let mut packet = match process_fragment(core_ctx, bindings_ctx, device, packet) {
3557 ProcessFragmentResult::Done => return,
3558 ProcessFragmentResult::NotNeeded(packet) => packet,
3559 ProcessFragmentResult::Reassembled(buf) => {
3560 let buf = Buf::new(buf, ..);
3561 buffer = packet::Either::B(buf);
3562
3563 match buffer.parse_mut() {
3564 Ok(packet) => packet,
3565 Err(err) => {
3566 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3567 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3568 return;
3569 }
3570 }
3571 }
3572 };
3573
3574 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3577 core_ctx,
3578 device,
3579 device_ip_layer_metadata,
3580 );
3581 let mut filter = core_ctx.filter_handler();
3582 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3583 filter::Verdict::Proceed(filter::Accept) => {}
3584 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
3585 packet_metadata.acknowledge_drop();
3586 return;
3587 }
3588 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
3589 addr,
3590 port,
3591 }) => {
3592 drop(filter);
3595
3596 let Some(addr) = SpecifiedAddr::new(addr) else {
3597 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3598 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3599 return;
3600 };
3601
3602 let receive_meta = ReceiveIpPacketMeta {
3603 broadcast: None,
3607 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3608 parsing_context,
3609 };
3610
3611 dispatch_receive_ipv4_packet(
3615 core_ctx,
3616 bindings_ctx,
3617 device,
3618 frame_dst,
3619 packet,
3620 packet_metadata,
3621 receive_meta,
3622 )
3623 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3624 return;
3625 }
3626 }
3627 drop(filter);
3630
3631 let Some(src_ip) = packet.src_ipv4() else {
3632 core_ctx.increment_both(device, |c| &c.invalid_source);
3633 debug!(
3634 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3635 packet.src_ip()
3636 );
3637 return;
3638 };
3639
3640 let action = receive_ipv4_packet_action(
3641 core_ctx,
3642 bindings_ctx,
3643 device,
3644 &packet,
3645 frame_dst,
3646 &packet_metadata.marks,
3647 );
3648 match action {
3649 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3650 let mut packet_metadata = Some(packet_metadata);
3657 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3658 clone_packet_for_mcast_forwarding! {
3659 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3660 };
3661 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3662 core_ctx,
3663 copy_of_packet,
3664 packet_metadata.take().unwrap_or_default(),
3665 Some(*min_ttl),
3666 device,
3667 &output_interface,
3668 IpPacketDestination::from_addr(dst_ip),
3669 frame_dst,
3670 src_ip,
3671 dst_ip,
3672 )
3673 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3674 }
3675
3676 if let Some(address_status) = address_status {
3678 let receive_meta = ReceiveIpPacketMeta {
3679 broadcast: address_status.to_broadcast_marker(),
3680 transparent_override: None,
3681 parsing_context,
3682 };
3683 dispatch_receive_ipv4_packet(
3684 core_ctx,
3685 bindings_ctx,
3686 device,
3687 frame_dst,
3688 packet,
3689 packet_metadata.take().unwrap_or_default(),
3690 receive_meta,
3691 )
3692 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3693 }
3694 }
3695 ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
3696 match internal_forwarding {
3699 InternalForwarding::Used(outbound_device) => {
3700 core_ctx.increment_both(device, |c| &c.forward);
3701 match core_ctx.filter_handler().forwarding_hook(
3702 &mut packet,
3703 device,
3704 &outbound_device,
3705 &mut packet_metadata,
3706 ) {
3707 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3708 packet_metadata.acknowledge_drop();
3709 return;
3710 }
3711 filter::Verdict::Stop(filter::DropOrReject::Reject(_reject_type)) => {
3712 packet_metadata.acknowledge_drop();
3714 return;
3715 }
3716 filter::Verdict::Proceed(filter::Accept) => {}
3717 }
3718 }
3719 InternalForwarding::NotUsed => {}
3720 }
3721
3722 let receive_meta = ReceiveIpPacketMeta {
3723 broadcast: address_status.to_broadcast_marker(),
3724 transparent_override: None,
3725 parsing_context,
3726 };
3727 dispatch_receive_ipv4_packet(
3728 core_ctx,
3729 bindings_ctx,
3730 device,
3731 frame_dst,
3732 packet,
3733 packet_metadata,
3734 receive_meta,
3735 )
3736 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3737 }
3738 ReceivePacketAction::Forward {
3739 original_dst,
3740 dst: Destination { device: dst_device, next_hop },
3741 } => {
3742 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3743 core_ctx,
3744 packet,
3745 packet_metadata,
3746 None,
3747 device,
3748 &dst_device,
3749 IpPacketDestination::from_next_hop(next_hop, original_dst),
3750 frame_dst,
3751 src_ip,
3752 original_dst,
3753 )
3754 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3755 }
3756 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3757 debug!("received IPv4 packet with no known route to destination {}", dst_ip);
3758
3759 let marks = packet_metadata.marks;
3760 packet_metadata.acknowledge_drop();
3761
3762 if let Some(sender) = IcmpErrorSender::new(
3763 core_ctx,
3764 Icmpv4Error::NetUnreachable,
3765 &packet,
3766 frame_dst,
3767 device,
3768 marks,
3769 ) {
3770 sender.send(core_ctx, bindings_ctx, buffer);
3771 }
3772 }
3773 ReceivePacketAction::Drop { reason } => {
3774 let src_ip = packet.src_ip();
3775 let dst_ip = packet.dst_ip();
3776 packet_metadata.acknowledge_drop();
3777 core_ctx.increment_both(device, |c| &c.dropped);
3778 debug!(
3779 "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
3780 {device:?}: {reason:?}",
3781 );
3782 }
3783 }
3784}
3785
3786fn handle_ipv6_parse_error<BC, B, CC>(
3787 core_ctx: &mut CC,
3788 bindings_ctx: &mut BC,
3789 device: &CC::DeviceId,
3790 frame_dst: Option<FrameDestination>,
3791 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3792 mut buffer: B,
3793 error: Ipv6ParseError,
3794) where
3795 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3796 B: BufferMut,
3797 CC: IpLayerIngressContext<Ipv6, BC>,
3798{
3799 let Ipv6ParseError::ParameterProblem { src_ip, dst_ip, code, pointer, must_send_icmp, action } =
3805 error
3806 else {
3807 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3808 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
3809 return;
3810 };
3811 if !must_send_icmp || !action.should_send_icmp(&dst_ip) {
3812 return;
3813 }
3814 core_ctx.increment_both(device, |c| &c.parameter_problem);
3815 let dst_ip = match SocketIpAddr::new(dst_ip) {
3816 Some(ip) => ip,
3817 None => {
3818 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3819 debug!("receive_ipv6_packet: Dropping packet with unspecified destination IP");
3820 return;
3821 }
3822 };
3823
3824 let src_ip = match Ipv6SourceAddr::new(src_ip) {
3825 None => {
3826 core_ctx.increment_both(device, |c| &c.invalid_source);
3827 return;
3828 }
3829 Some(Ipv6SourceAddr::Unspecified) => {
3830 core_ctx.increment_both(device, |c| &c.unspecified_source);
3831 return;
3832 }
3833 Some(Ipv6SourceAddr::Unicast(src_ip)) => {
3834 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
3835 }
3836 };
3837
3838 let raw_packet: Ipv6PacketRaw<_> = match try_parse_ip_packet!(buffer) {
3841 Ok(packet) => packet,
3842 Err(error) => {
3843 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3844 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
3845 return;
3846 }
3847 };
3848 let proto = match raw_packet.proto() {
3849 Ok(proto) => proto,
3850 Err(error) => {
3851 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3852 debug!("receive_ipv6_packet: Failed to get protocol from IPv6 packet: {:?}", error);
3853 return;
3854 }
3855 };
3856 let parse_metadata = raw_packet.parse_metadata();
3857 let header_len = parse_metadata.header_len();
3858 buffer.undo_parse(parse_metadata);
3859
3860 let err = Icmpv6Error::ParameterProblem {
3861 code,
3862 pointer,
3863 allow_dst_multicast: action.should_send_icmp_to_multicast(),
3864 };
3865
3866 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3867 core_ctx,
3868 bindings_ctx,
3869 Some(device),
3870 frame_dst,
3871 src_ip,
3872 dst_ip,
3873 buffer,
3874 err,
3875 header_len,
3876 proto,
3877 &device_ip_layer_metadata.marks,
3878 );
3879}
3880
3881pub fn receive_ipv6_packet<
3886 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3887 B: BufferMut,
3888 CC: IpLayerIngressContext<Ipv6, BC>,
3889>(
3890 core_ctx: &mut CC,
3891 bindings_ctx: &mut BC,
3892 device: &CC::DeviceId,
3893 frame_dst: Option<FrameDestination>,
3894 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3895 parsing_context: NetworkParsingContext,
3896 buffer: B,
3897) {
3898 if !core_ctx.is_ip_device_enabled(&device) {
3899 return;
3900 }
3901
3902 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3905
3906 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3907 trace!("receive_ipv6_packet({:?})", device);
3908
3909 let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
3910 Ok(packet) => packet,
3911 Err(error) => {
3912 handle_ipv6_parse_error(
3913 core_ctx,
3914 bindings_ctx,
3915 device,
3916 frame_dst,
3917 device_ip_layer_metadata,
3918 buffer,
3919 error,
3920 );
3921 return;
3922 }
3923 };
3924
3925 trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
3926
3927 if packet.src_ipv6().is_none() {
3933 debug!(
3934 "receive_ipv6_packet: received packet from invalid source {}; dropping",
3935 packet.src_ip()
3936 );
3937 core_ctx.increment_both(device, |c| &c.invalid_source);
3938 return;
3939 };
3940 if !packet.dst_ip().is_specified() {
3941 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3942 debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
3943 return;
3944 };
3945
3946 let (mut packet, delivery_extension_header_action) =
3957 match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
3958 Ipv6PacketAction::_Discard => {
3959 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3960 trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
3961 return;
3962 }
3963 Ipv6PacketAction::Continue => {
3964 trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
3965 (packet, Some(Ipv6PacketAction::Continue))
3966 }
3967 Ipv6PacketAction::ProcessFragment => {
3968 trace!(
3969 "receive_ipv6_packet: handled IPv6 extension headers: handling \
3970 fragmented packet"
3971 );
3972
3973 match process_fragment(core_ctx, bindings_ctx, device, packet) {
3985 ProcessFragmentResult::Done => return,
3986 ProcessFragmentResult::NotNeeded(packet) => {
3987 (packet, Some(Ipv6PacketAction::Continue))
4002 }
4003 ProcessFragmentResult::Reassembled(buf) => {
4004 let buf = Buf::new(buf, ..);
4005 buffer = packet::Either::B(buf);
4006
4007 match buffer.parse_mut() {
4008 Ok(packet) => (packet, None),
4009 Err(err) => {
4010 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4011 debug!(
4012 "receive_ip_packet: fragmented, failed to reassemble: {:?}",
4013 err
4014 );
4015 return;
4016 }
4017 }
4018 }
4019 }
4020 }
4021 };
4022
4023 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
4024 core_ctx,
4025 device,
4026 device_ip_layer_metadata,
4027 );
4028 let mut filter = core_ctx.filter_handler();
4029
4030 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
4031 filter::Verdict::Proceed(filter::Accept) => {}
4032 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
4033 packet_metadata.acknowledge_drop();
4034 return;
4035 }
4036 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
4037 addr,
4038 port,
4039 }) => {
4040 drop(filter);
4043
4044 let Some(addr) = SpecifiedAddr::new(addr) else {
4045 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4046 debug!("cannot perform transparent delivery to unspecified destination; dropping");
4047 return;
4048 };
4049
4050 let receive_meta = ReceiveIpPacketMeta {
4051 broadcast: None,
4052 transparent_override: Some(TransparentLocalDelivery { addr, port }),
4053 parsing_context,
4054 };
4055
4056 dispatch_receive_ipv6_packet(
4060 core_ctx,
4061 bindings_ctx,
4062 device,
4063 frame_dst,
4064 packet,
4065 packet_metadata,
4066 receive_meta,
4067 )
4068 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4069 return;
4070 }
4071 }
4072 drop(filter);
4075
4076 let Some(src_ip) = packet.src_ipv6() else {
4077 debug!(
4078 "receive_ipv6_packet: received packet from invalid source {}; dropping",
4079 packet.src_ip()
4080 );
4081 core_ctx.increment_both(device, |c| &c.invalid_source);
4082 return;
4083 };
4084
4085 match receive_ipv6_packet_action(
4086 core_ctx,
4087 bindings_ctx,
4088 device,
4089 &packet,
4090 frame_dst,
4091 &packet_metadata.marks,
4092 ) {
4093 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
4094 let mut packet_metadata = Some(packet_metadata);
4101 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
4102 clone_packet_for_mcast_forwarding! {
4103 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
4104 };
4105 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4106 core_ctx,
4107 copy_of_packet,
4108 packet_metadata.take().unwrap_or_default(),
4109 Some(*min_ttl),
4110 device,
4111 &output_interface,
4112 IpPacketDestination::from_addr(dst_ip),
4113 frame_dst,
4114 src_ip,
4115 dst_ip,
4116 )
4117 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
4118 }
4119
4120 if let Some(_) = address_status {
4122 let receive_meta = ReceiveIpPacketMeta {
4123 broadcast: None,
4124 transparent_override: None,
4125 parsing_context,
4126 };
4127
4128 dispatch_receive_ipv6_packet(
4129 core_ctx,
4130 bindings_ctx,
4131 device,
4132 frame_dst,
4133 packet,
4134 packet_metadata.take().unwrap_or_default(),
4135 receive_meta,
4136 )
4137 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4138 }
4139 }
4140 ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
4141 trace!("receive_ipv6_packet: delivering locally");
4142
4143 let action = if let Some(action) = delivery_extension_header_action {
4144 action
4145 } else {
4146 ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
4147 };
4148 match action {
4149 Ipv6PacketAction::_Discard => {
4150 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4151 trace!(
4152 "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
4153 );
4154 packet_metadata.acknowledge_drop();
4155 }
4156 Ipv6PacketAction::Continue => {
4157 trace!(
4158 "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
4159 );
4160
4161 match internal_forwarding {
4164 InternalForwarding::Used(outbound_device) => {
4165 core_ctx.increment_both(device, |c| &c.forward);
4166 match core_ctx.filter_handler().forwarding_hook(
4167 &mut packet,
4168 device,
4169 &outbound_device,
4170 &mut packet_metadata,
4171 ) {
4172 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
4173 packet_metadata.acknowledge_drop();
4174 return;
4175 }
4176 filter::Verdict::Stop(filter::DropOrReject::Reject(
4177 _reject_type,
4178 )) => {
4179 packet_metadata.acknowledge_drop();
4181 return;
4182 }
4183 filter::Verdict::Proceed(filter::Accept) => {}
4184 }
4185 }
4186 InternalForwarding::NotUsed => {}
4187 }
4188
4189 let meta = ReceiveIpPacketMeta {
4190 broadcast: None,
4191 transparent_override: None,
4192 parsing_context,
4193 };
4194 dispatch_receive_ipv6_packet(
4195 core_ctx,
4196 bindings_ctx,
4197 device,
4198 frame_dst,
4199 packet,
4200 packet_metadata,
4201 meta,
4202 )
4203 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4204 }
4205 Ipv6PacketAction::ProcessFragment => {
4206 debug!("receive_ipv6_packet: found fragment header after reassembly; dropping");
4207 packet_metadata.acknowledge_drop();
4208 }
4209 }
4210 }
4211 ReceivePacketAction::Forward {
4212 original_dst,
4213 dst: Destination { device: dst_device, next_hop },
4214 } => {
4215 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4216 core_ctx,
4217 packet,
4218 packet_metadata,
4219 None,
4220 device,
4221 &dst_device,
4222 IpPacketDestination::from_next_hop(next_hop, original_dst),
4223 frame_dst,
4224 src_ip,
4225 original_dst,
4226 )
4227 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
4228 }
4229 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
4230 let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
4231 drop_packet_and_undo_parse!(packet, buffer);
4232 debug!("received IPv6 packet with no known route to destination {}", dst_ip);
4233 let marks = packet_metadata.marks;
4234 packet_metadata.acknowledge_drop();
4235
4236 let src_ip = match src_ip {
4237 Ipv6SourceAddr::Unspecified => {
4238 core_ctx.increment_both(device, |c| &c.unspecified_source);
4239 return;
4240 }
4241 Ipv6SourceAddr::Unicast(src_ip) => {
4242 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
4243 }
4244 };
4245
4246 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
4247 core_ctx,
4248 bindings_ctx,
4249 Some(device),
4250 frame_dst,
4251 src_ip,
4252 SocketIpAddr::new_from_witness(dst_ip),
4253 buffer,
4254 Icmpv6Error::NetUnreachable,
4255 meta.header_len(),
4256 proto,
4257 &marks,
4258 );
4259 }
4260 ReceivePacketAction::Drop { reason } => {
4261 core_ctx.increment_both(device, |c| &c.dropped);
4262 let src_ip = packet.src_ip();
4263 let dst_ip = packet.dst_ip();
4264 packet_metadata.acknowledge_drop();
4265 debug!(
4266 "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
4267 {device:?}: {reason:?}",
4268 );
4269 }
4270 }
4271}
4272
4273#[derive(Debug, PartialEq)]
4275pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
4276 Deliver {
4278 address_status: I::AddressStatus,
4280 internal_forwarding: InternalForwarding<DeviceId>,
4283 },
4284
4285 Forward {
4287 original_dst: SpecifiedAddr<I::Addr>,
4289 dst: Destination<I::Addr, DeviceId>,
4291 },
4292
4293 MulticastForward {
4301 targets: MulticastRouteTargets<DeviceId>,
4303 address_status: Option<I::AddressStatus>,
4306 dst_ip: SpecifiedAddr<I::Addr>,
4308 },
4309
4310 SendNoRouteToDest {
4316 dst: NonMappedAddr<SpecifiedAddr<I::Addr>>,
4318 },
4319
4320 #[allow(missing_docs)]
4324 Drop { reason: DropReason },
4325}
4326
4327fn choose_highest_priority_address_status<I: IpLayerIpExt>(
4330 address_statuses: impl Iterator<Item = I::AddressStatus>,
4331) -> Option<I::AddressStatus> {
4332 address_statuses.max_by_key(|status| {
4333 #[derive(GenericOverIp)]
4334 #[generic_over_ip(I, Ip)]
4335 struct Wrap<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
4336 I::map_ip_in(
4337 Wrap(status),
4338 |Wrap(v4_status)| match v4_status {
4339 Ipv4PresentAddressStatus::UnicastTentative => 0,
4340 _ => 1,
4341 },
4342 |Wrap(v6_status)| match v6_status {
4343 Ipv6PresentAddressStatus::UnicastTentative => 0,
4344 _ => 1,
4345 },
4346 )
4347 })
4348}
4349
4350#[derive(Debug, PartialEq)]
4352pub enum DropReason {
4353 Tentative,
4355 UnspecifiedDestination,
4357 InvalidDestination,
4359 ForwardUnspecifiedSource,
4361 ForwardLinkLocal,
4363 ForwardingDisabledInboundIface,
4366 MulticastNoInterest,
4372}
4373
4374pub fn receive_ipv4_packet_action<BC, CC, B>(
4376 core_ctx: &mut CC,
4377 bindings_ctx: &mut BC,
4378 device: &CC::DeviceId,
4379 packet: &Ipv4Packet<B>,
4380 frame_dst: Option<FrameDestination>,
4381 marks: &Marks,
4382) -> ReceivePacketAction<Ipv4, CC::DeviceId>
4383where
4384 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
4385 CC: IpLayerContext<Ipv4, BC>,
4386 B: SplitByteSlice,
4387{
4388 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4389 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4390 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4391 };
4392
4393 let highest_priority = if device.is_loopback() {
4406 core_ctx.with_address_statuses(dst_ip, |it| {
4407 let it = it.map(|(_device, status)| status);
4408 choose_highest_priority_address_status::<Ipv4>(it)
4409 })
4410 } else {
4411 core_ctx.address_status_for_device(dst_ip, device).into_present()
4412 };
4413 match highest_priority {
4414 Some(
4415 address_status @ (Ipv4PresentAddressStatus::UnicastAssigned
4416 | Ipv4PresentAddressStatus::LoopbackSubnet),
4417 ) => {
4418 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4419 ReceivePacketAction::Deliver {
4420 address_status,
4421 internal_forwarding: InternalForwarding::NotUsed,
4422 }
4423 }
4424 Some(Ipv4PresentAddressStatus::UnicastTentative) => {
4425 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4431 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4432 }
4433
4434 Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4435 receive_ip_multicast_packet_action(
4436 core_ctx,
4437 bindings_ctx,
4438 device,
4439 packet,
4440 Some(address_status),
4441 dst_ip,
4442 frame_dst,
4443 )
4444 }
4445 Some(
4446 address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4447 | Ipv4PresentAddressStatus::SubnetBroadcast),
4448 ) => {
4449 core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
4450 ReceivePacketAction::Deliver {
4451 address_status,
4452 internal_forwarding: InternalForwarding::NotUsed,
4453 }
4454 }
4455 None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4456 core_ctx,
4457 bindings_ctx,
4458 dst_ip,
4459 device,
4460 packet,
4461 frame_dst,
4462 marks,
4463 ),
4464 }
4465}
4466
4467pub fn receive_ipv6_packet_action<BC, CC, B>(
4469 core_ctx: &mut CC,
4470 bindings_ctx: &mut BC,
4471 device: &CC::DeviceId,
4472 packet: &Ipv6Packet<B>,
4473 frame_dst: Option<FrameDestination>,
4474 marks: &Marks,
4475) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4476where
4477 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4478 CC: IpLayerContext<Ipv6, BC>,
4479 B: SplitByteSlice,
4480{
4481 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4482 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4483 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4484 };
4485
4486 let highest_priority = if device.is_loopback() {
4499 core_ctx.with_address_statuses(dst_ip, |it| {
4500 let it = it.map(|(_device, status)| status);
4501 choose_highest_priority_address_status::<Ipv6>(it)
4502 })
4503 } else {
4504 core_ctx.address_status_for_device(dst_ip, device).into_present()
4505 };
4506 match highest_priority {
4507 Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
4508 receive_ip_multicast_packet_action(
4509 core_ctx,
4510 bindings_ctx,
4511 device,
4512 packet,
4513 Some(address_status),
4514 dst_ip,
4515 frame_dst,
4516 )
4517 }
4518 Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
4519 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4520 ReceivePacketAction::Deliver {
4521 address_status,
4522 internal_forwarding: InternalForwarding::NotUsed,
4523 }
4524 }
4525 Some(Ipv6PresentAddressStatus::UnicastTentative) => {
4526 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4557 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4558 }
4559 None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
4560 core_ctx,
4561 bindings_ctx,
4562 dst_ip,
4563 device,
4564 packet,
4565 frame_dst,
4566 marks,
4567 ),
4568 }
4569}
4570
4571fn receive_ip_multicast_packet_action<
4574 I: IpLayerIpExt,
4575 B: SplitByteSlice,
4576 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4577 CC: IpLayerContext<I, BC>,
4578>(
4579 core_ctx: &mut CC,
4580 bindings_ctx: &mut BC,
4581 device: &CC::DeviceId,
4582 packet: &I::Packet<B>,
4583 address_status: Option<I::AddressStatus>,
4584 dst_ip: SpecifiedAddr<I::Addr>,
4585 frame_dst: Option<FrameDestination>,
4586) -> ReceivePacketAction<I, CC::DeviceId> {
4587 let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
4588 core_ctx,
4589 bindings_ctx,
4590 packet,
4591 device,
4592 frame_dst,
4593 );
4594 match (targets, address_status) {
4595 (Some(targets), address_status) => {
4596 if address_status.is_some() {
4597 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4598 }
4599 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
4600 }
4601 (None, Some(address_status)) => {
4602 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4605 ReceivePacketAction::Deliver {
4606 address_status,
4607 internal_forwarding: InternalForwarding::NotUsed,
4608 }
4609 }
4610 (None, None) => {
4611 core_ctx.increment_both(device, |c| &c.multicast_no_interest);
4620 ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
4621 }
4622 }
4623}
4624
4625fn receive_ip_packet_action_common<
4628 I: IpLayerIpExt,
4629 B: SplitByteSlice,
4630 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4631 CC: IpLayerContext<I, BC>,
4632>(
4633 core_ctx: &mut CC,
4634 bindings_ctx: &mut BC,
4635 dst_ip: SpecifiedAddr<I::Addr>,
4636 device_id: &CC::DeviceId,
4637 packet: &I::Packet<B>,
4638 frame_dst: Option<FrameDestination>,
4639 marks: &Marks,
4640) -> ReceivePacketAction<I, CC::DeviceId> {
4641 if dst_ip.is_multicast() {
4642 return receive_ip_multicast_packet_action(
4643 core_ctx,
4644 bindings_ctx,
4645 device_id,
4646 packet,
4647 None,
4648 dst_ip,
4649 frame_dst,
4650 );
4651 }
4652
4653 let Some(dst_ip) = NonMappedAddr::new(dst_ip) else {
4655 return ReceivePacketAction::Drop { reason: DropReason::InvalidDestination };
4656 };
4657
4658 if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
4660 core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
4673 return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
4674 }
4675 let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
4682 return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
4683 };
4684
4685 if let Some(dst_ip) = NonMulticastAddr::new(dst_ip) {
4692 if let Some((outbound_device, address_status)) =
4693 get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
4694 {
4695 return ReceivePacketAction::Deliver {
4696 address_status,
4697 internal_forwarding: InternalForwarding::Used(outbound_device),
4698 };
4699 }
4700 }
4701
4702 if I::map_ip_in(
4717 &packet,
4718 |_| false,
4719 |packet| packet.src_ip().is_link_local() || packet.dst_ip().is_link_local(),
4720 ) {
4721 return ReceivePacketAction::Drop { reason: DropReason::ForwardLinkLocal };
4722 }
4723
4724 match lookup_route_table(
4725 core_ctx,
4726 dst_ip.get(),
4727 RuleInput {
4728 packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
4729 marks,
4730 },
4731 ) {
4732 Some(dst) => {
4733 core_ctx.increment_both(device_id, |c| &c.forward);
4734 ReceivePacketAction::Forward { original_dst: *dst_ip, dst }
4735 }
4736 None => {
4737 core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
4738 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
4739 }
4740 }
4741}
4742
4743fn lookup_route_table<
4745 I: IpLayerIpExt,
4746 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4747 CC: IpStateContext<I, BC>,
4748>(
4749 core_ctx: &mut CC,
4750 dst_ip: I::Addr,
4751 rule_input: RuleInput<'_, I, CC::DeviceId>,
4752) -> Option<Destination<I::Addr, CC::DeviceId>> {
4753 let bound_device = match rule_input.packet_origin {
4754 PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
4755 PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
4756 };
4757 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
4758 match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
4759 match table.lookup(core_ctx, bound_device, dst_ip) {
4760 Some(dst) => ControlFlow::Break(Some(dst)),
4761 None => ControlFlow::Continue(()),
4762 }
4763 }) {
4764 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
4765 inner: dst,
4766 observed_source_address_matcher: _,
4767 })) => dst,
4768 ControlFlow::Break(RuleAction::Unreachable) => None,
4769 ControlFlow::Continue(RuleWalkInfo {
4770 inner: (),
4771 observed_source_address_matcher: _,
4772 }) => None,
4773 }
4774 })
4775}
4776
4777#[derive(Debug, Derivative, Clone)]
4779#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
4780pub enum IpPacketDestination<I: BroadcastIpExt, D> {
4781 Broadcast(I::BroadcastMarker),
4783
4784 Multicast(MulticastAddr<I::Addr>),
4786
4787 Neighbor(SpecifiedAddr<I::Addr>),
4790
4791 Loopback(D),
4794}
4795
4796impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
4797 pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
4799 match MulticastAddr::new(addr.into_addr()) {
4800 Some(mc_addr) => Self::Multicast(mc_addr),
4801 None => Self::Neighbor(addr),
4802 }
4803 }
4804
4805 pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
4807 match next_hop {
4808 NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
4809 NextHop::Gateway(gateway) => Self::Neighbor(gateway),
4810 NextHop::Broadcast(marker) => Self::Broadcast(marker),
4811 }
4812 }
4813}
4814
4815#[derive(Debug, Clone)]
4817pub struct SendIpPacketMeta<I: IpExt, D, Src> {
4818 pub device: D,
4820
4821 pub src_ip: Src,
4823
4824 pub dst_ip: SpecifiedAddr<I::Addr>,
4826
4827 pub destination: IpPacketDestination<I, D>,
4829
4830 pub proto: I::Proto,
4832
4833 pub ttl: Option<NonZeroU8>,
4837
4838 pub mtu: Mtu,
4843
4844 pub dscp_and_ecn: DscpAndEcn,
4846}
4847
4848impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4849 for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
4850{
4851 fn from(
4852 SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
4853 I,
4854 D,
4855 SpecifiedAddr<I::Addr>,
4856 >,
4857 ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
4858 SendIpPacketMeta {
4859 device,
4860 src_ip: Some(src_ip),
4861 dst_ip,
4862 destination,
4863 proto,
4864 ttl,
4865 mtu,
4866 dscp_and_ecn,
4867 }
4868 }
4869}
4870
4871pub trait IpLayerHandler<I: IpExt + FragmentationIpExt + FilterIpExt, BC>:
4877 DeviceIdContext<AnyDevice>
4878{
4879 fn send_ip_packet_from_device<S>(
4882 &mut self,
4883 bindings_ctx: &mut BC,
4884 meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4885 body: S,
4886 ) -> Result<(), IpSendFrameError<S>>
4887 where
4888 S: TransportPacketSerializer<I>,
4889 S::Buffer: BufferMut;
4890
4891 fn send_ip_frame<S>(
4898 &mut self,
4899 bindings_ctx: &mut BC,
4900 device: &Self::DeviceId,
4901 destination: IpPacketDestination<I, &Self::DeviceId>,
4902 body: S,
4903 ) -> Result<(), IpSendFrameError<S>>
4904 where
4905 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>;
4906}
4907
4908impl<
4909 I: IpLayerIpExt,
4910 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
4911 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4912> IpLayerHandler<I, BC> for CC
4913{
4914 fn send_ip_packet_from_device<S>(
4915 &mut self,
4916 bindings_ctx: &mut BC,
4917 meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4918 body: S,
4919 ) -> Result<(), IpSendFrameError<S>>
4920 where
4921 S: TransportPacketSerializer<I>,
4922 S::Buffer: BufferMut,
4923 {
4924 send_ip_packet_from_device(self, bindings_ctx, meta, body, IpLayerPacketMetadata::default())
4925 }
4926
4927 fn send_ip_frame<S>(
4928 &mut self,
4929 bindings_ctx: &mut BC,
4930 device: &Self::DeviceId,
4931 destination: IpPacketDestination<I, &Self::DeviceId>,
4932 body: S,
4933 ) -> Result<(), IpSendFrameError<S>>
4934 where
4935 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>,
4936 {
4937 send_ip_frame(
4938 self,
4939 bindings_ctx,
4940 device,
4941 destination,
4942 body,
4943 IpLayerPacketMetadata::default(),
4944 Mtu::no_limit(),
4945 )
4946 }
4947}
4948
4949pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
4956 core_ctx: &mut CC,
4957 bindings_ctx: &mut BC,
4958 meta: SendIpPacketMeta<
4959 I,
4960 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
4961 Option<SpecifiedAddr<I::Addr>>,
4962 >,
4963 body: S,
4964 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
4965) -> Result<(), IpSendFrameError<S>>
4966where
4967 I: IpLayerIpExt,
4968 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
4969 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4970 S: TransportPacketSerializer<I>,
4971 S::Buffer: BufferMut,
4972{
4973 let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
4974 meta;
4975 core_ctx.increment_both(device, |c| &c.send_ip_packet);
4976 let next_packet_id = gen_ip_packet_id(core_ctx);
4977 let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
4978 let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
4979 let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
4980
4981 #[derive(GenericOverIp)]
4982 #[generic_over_ip(I, Ip)]
4983 struct Wrap<'a, I: IpLayerIpExt> {
4984 builder: &'a mut I::PacketBuilder<NetworkSerializationContext>,
4985 next_packet_id: I::PacketId,
4986 }
4987
4988 I::map_ip::<_, ()>(
4989 Wrap { builder: &mut builder, next_packet_id },
4990 |Wrap { builder, next_packet_id }| {
4991 builder.id(next_packet_id);
4992 },
4993 |Wrap { builder: _, next_packet_id: () }| {
4994 },
4996 );
4997
4998 builder.set_dscp_and_ecn(dscp_and_ecn);
4999
5000 let ip_frame = builder.wrap_body(body);
5001 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
5002 .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
5003}
5004
5005pub trait FilterHandlerProvider<I: FilterIpExt, BT: FilterBindingsTypes>:
5007 IpDeviceAddressIdContext<I, DeviceId: netstack3_base::InterfaceProperties<BT::DeviceClass>>
5008{
5009 type Handler<'a>: filter::FilterHandler<I, BT, DeviceId = Self::DeviceId, WeakAddressId = Self::WeakAddressId>
5011 where
5012 Self: 'a;
5013
5014 fn filter_handler(&mut self) -> Self::Handler<'_>;
5016}
5017
5018#[cfg(any(test, feature = "testutils"))]
5019pub(crate) mod testutil {
5020 use super::*;
5021
5022 use netstack3_base::testutil::{FakeBindingsCtx, FakeCoreCtx, FakeStrongDeviceId};
5023 use netstack3_base::{
5024 AssignedAddrIpExt, NetworkSerializer, SendFrameContext, SendFrameError, SendableFrameMeta,
5025 };
5026
5027 #[derive(Debug, GenericOverIp)]
5029 #[generic_over_ip()]
5030 #[allow(missing_docs)]
5031 pub enum DualStackSendIpPacketMeta<D> {
5032 V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
5033 V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
5034 }
5035
5036 impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5037 for DualStackSendIpPacketMeta<D>
5038 {
5039 fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
5040 #[derive(GenericOverIp)]
5041 #[generic_over_ip(I, Ip)]
5042 struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
5043 use DualStackSendIpPacketMeta::*;
5044 I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
5045 }
5046 }
5047
5048 impl<I: IpExt, S, DeviceId, BC>
5049 SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
5050 for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
5051 {
5052 fn send_meta<SS>(
5053 self,
5054 core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
5055 bindings_ctx: &mut BC,
5056 frame: SS,
5057 ) -> Result<(), SendFrameError<SS>>
5058 where
5059 SS: NetworkSerializer,
5060 SS::Buffer: BufferMut,
5061 {
5062 SendFrameContext::send_frame(
5063 &mut core_ctx.frames,
5064 bindings_ctx,
5065 DualStackSendIpPacketMeta::from(self),
5066 frame,
5067 )
5068 }
5069 }
5070
5071 #[derive(Debug)]
5073 pub struct WrongIpVersion;
5074
5075 impl<D> DualStackSendIpPacketMeta<D> {
5076 pub fn try_as<I: IpExt>(
5079 &self,
5080 ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
5081 #[derive(GenericOverIp)]
5082 #[generic_over_ip(I, Ip)]
5083 struct Wrap<'a, I: IpExt, D>(
5084 Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
5085 );
5086 use DualStackSendIpPacketMeta::*;
5087 let Wrap(dual_stack) = I::map_ip(
5088 self,
5089 |value| {
5090 Wrap(match value {
5091 V4(meta) => Some(meta),
5092 V6(_) => None,
5093 })
5094 },
5095 |value| {
5096 Wrap(match value {
5097 V4(_) => None,
5098 V6(meta) => Some(meta),
5099 })
5100 },
5101 );
5102 dual_stack.ok_or(WrongIpVersion)
5103 }
5104 }
5105
5106 impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
5107 where
5108 I: AssignedAddrIpExt + FilterIpExt,
5109 BC: FilterBindingsContext<DeviceId>,
5110 DeviceId: FakeStrongDeviceId + netstack3_base::InterfaceProperties<BC::DeviceClass>,
5111 {
5112 type Handler<'a>
5113 = filter::testutil::NoopImpl<DeviceId>
5114 where
5115 Self: 'a;
5116
5117 fn filter_handler(&mut self) -> Self::Handler<'_> {
5118 filter::testutil::NoopImpl::default()
5119 }
5120 }
5121
5122 impl<TimerId, Event: Debug, State, FrameMeta> MarksBindingsContext
5123 for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
5124 {
5125 fn marks_to_keep_on_egress() -> &'static [MarkDomain] {
5126 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark1];
5127 &MARKS
5128 }
5129
5130 fn marks_to_set_on_ingress() -> &'static [MarkDomain] {
5131 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark2];
5132 &MARKS
5133 }
5134 }
5135}
5136
5137#[cfg(test)]
5138mod test {
5139 use super::*;
5140
5141 #[test]
5142 fn highest_priority_address_status_v4() {
5143 assert_eq!(
5145 choose_highest_priority_address_status::<Ipv4>(
5146 [
5147 Ipv4PresentAddressStatus::UnicastAssigned,
5148 Ipv4PresentAddressStatus::UnicastTentative
5149 ]
5150 .into_iter()
5151 ),
5152 Some(Ipv4PresentAddressStatus::UnicastAssigned)
5153 )
5154 }
5155
5156 #[test]
5157 fn highest_priority_address_status_v6() {
5158 assert_eq!(
5160 choose_highest_priority_address_status::<Ipv6>(
5161 [
5162 Ipv6PresentAddressStatus::UnicastAssigned,
5163 Ipv6PresentAddressStatus::UnicastTentative
5164 ]
5165 .into_iter()
5166 ),
5167 Some(Ipv6PresentAddressStatus::UnicastAssigned)
5168 )
5169 }
5170}