1use alloc::boxed::Box;
6use alloc::vec::Vec;
7use core::fmt::Debug;
8use core::hash::Hash;
9use core::marker::PhantomData;
10use core::num::NonZeroU8;
11use core::ops::ControlFlow;
12#[cfg(test)]
13use core::ops::DerefMut;
14use core::sync::atomic::{self, AtomicU16};
15
16use derivative::Derivative;
17use explicit::ResultExt as _;
18use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
19use log::{debug, trace};
20use net_types::ip::{
21 GenericOverIp, Ip, IpVersion, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu, Subnet,
22};
23use net_types::{
24 LinkLocalAddress, MulticastAddr, MulticastAddress, NonMappedAddr, NonMulticastAddr,
25 SpecifiedAddr, SpecifiedAddress as _, Witness,
26};
27use netstack3_base::socket::{EitherStack, SocketIpAddr, SocketIpAddrExt as _};
28use netstack3_base::sync::{Mutex, PrimaryRc, RwLock, StrongRc, WeakRc};
29use netstack3_base::{
30 AnyDevice, BroadcastIpExt, CoreTimerContext, Counter, CounterCollectionSpec, CounterContext,
31 DeviceIdContext, DeviceIdentifier as _, ErrorAndSerializer, EventContext, GsoInfo,
32 HandleableTimer, InstantContext, InterfaceProperties, IpAddressId, IpDeviceAddr,
33 IpDeviceAddressIdContext, IpExt, LocalFrameDestination, MarkDomain, Marks, Matcher as _,
34 MatcherBindingsTypes, NestedIntoCoreTimerCtx, NetworkParsingContext,
35 NetworkSerializationContext, NotFoundError, ResourceCounterContext, RngContext,
36 SendFrameErrorReason, StrongDeviceIdentifier, TimerBindingsTypes, TimerContext, TimerHandler,
37 TxMetadata as _, TxMetadataBindingsTypes, WeakIpAddressId, WrapBroadcastMarker,
38};
39use netstack3_filter::{
40 self as filter, ConnectionDirection, ConntrackConnection, FilterBindingsContext,
41 FilterBindingsTypes, FilterHandler as _, FilterIpContext, FilterIpExt, FilterIpMetadata,
42 FilterIpPacket, FilterPacketMetadata, FilterTimerId, ForwardedPacket, IpPacket, MarkAction,
43 MaybeTransportPacket as _, RejectType, SocketInfo, TransportPacketSerializer, Tuple,
44 WeakConnectionError, WeakConntrackConnection,
45};
46use netstack3_hashmap::HashMap;
47use packet::{
48 Buf, BufferMut, GrowBuffer, LayoutBufferAlloc, NestablePacketBuilder as _, PacketConstraints,
49 ParsablePacket as _, ParseBuffer, ParseBufferMut, ParseMetadata, SerializeError,
50 Serializer as _,
51};
52use packet_formats::error::{Ipv6ParseError, ParseError};
53use packet_formats::ip::{DscpAndEcn, IpPacket as _, IpPacketBuilder as _};
54use packet_formats::ipv4::{Ipv4FragmentType, Ipv4Packet};
55use packet_formats::ipv6::{Ipv6Packet, Ipv6PacketRaw};
56use thiserror::Error;
57use zerocopy::SplitByteSlice;
58
59use crate::internal::counters::{IpCounters, IpCountersIpExt};
60use crate::internal::device::opaque_iid::IidSecret;
61use crate::internal::device::slaac::SlaacCounters;
62use crate::internal::device::state::{
63 IpAddressData, IpAddressFlags, IpDeviceStateBindingsTypes, IpDeviceStateIpExt, WeakAddressId,
64};
65use crate::internal::device::{
66 self, IpDeviceAddressContext, IpDeviceBindingsContext, IpDeviceIpExt, IpDeviceSendContext,
67};
68use crate::internal::fragmentation::{FragmentableIpSerializer, FragmentationIpExt, IpFragmenter};
69use crate::internal::gmp::GmpQueryHandler;
70use crate::internal::gmp::igmp::IgmpCounters;
71use crate::internal::gmp::mld::MldCounters;
72use crate::internal::icmp::counters::IcmpCountersIpExt;
73use crate::internal::icmp::{
74 IcmpBindingsTypes, IcmpError, IcmpErrorHandler, IcmpHandlerIpExt, Icmpv4Error, Icmpv4State,
75 Icmpv4StateBuilder, Icmpv6Error, Icmpv6State, Icmpv6StateBuilder,
76};
77use crate::internal::ipv6::Ipv6PacketAction;
78use crate::internal::local_delivery::{
79 IpHeaderInfo, Ipv4HeaderInfo, Ipv6HeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta,
80 TransparentLocalDelivery,
81};
82use crate::internal::multicast_forwarding::counters::MulticastForwardingCounters;
83use crate::internal::multicast_forwarding::route::{
84 MulticastRouteIpExt, MulticastRouteTarget, MulticastRouteTargets,
85};
86use crate::internal::multicast_forwarding::state::{
87 MulticastForwardingState, MulticastForwardingStateContext,
88};
89use crate::internal::multicast_forwarding::{
90 MulticastForwardingBindingsTypes, MulticastForwardingDeviceContext, MulticastForwardingEvent,
91 MulticastForwardingTimerId,
92};
93use crate::internal::path_mtu::{PmtuBindingsTypes, PmtuCache, PmtuTimerId};
94use crate::internal::raw::counters::RawIpSocketCounters;
95use crate::internal::raw::{RawIpSocketHandler, RawIpSocketMap, RawIpSocketsBindingsTypes};
96use crate::internal::reassembly::{
97 FragmentBindingsTypes, FragmentHandler, FragmentProcessingState, FragmentTimerId,
98 FragmentablePacket, IpPacketFragmentCache, ReassemblyIpExt,
99};
100use crate::internal::routing::rules::{Rule, RuleAction, RuleInput, RulesTable};
101use crate::internal::routing::{
102 IpRoutingBindingsTypes, IpRoutingDeviceContext, NonLocalSrcAddrPolicy, PacketOrigin,
103 RoutingTable,
104};
105use crate::internal::socket::{IpSocketBindingsContext, IpSocketContext, IpSocketHandler};
106use crate::internal::types::{
107 self, Destination, InternalForwarding, NextHop, ResolvedRoute, RoutableIpAddr,
108};
109use crate::internal::{ipv6, multicast_forwarding};
110
111#[cfg(test)]
112mod tests;
113
114pub const DEFAULT_TTL: NonZeroU8 = NonZeroU8::new(64).unwrap();
116
117#[derive(Copy, Clone, Debug, Eq, PartialEq)]
119#[allow(missing_docs)]
120pub struct HopLimits {
121 pub unicast: NonZeroU8,
122 pub multicast: NonZeroU8,
123}
124
125pub const DEFAULT_HOP_LIMITS: HopLimits =
127 HopLimits { unicast: DEFAULT_TTL, multicast: NonZeroU8::new(1).unwrap() };
128
129pub const IPV6_DEFAULT_SUBNET: Subnet<Ipv6Addr> =
132 unsafe { Subnet::new_unchecked(Ipv6::UNSPECIFIED_ADDRESS, 0) };
133
134#[derive(Derivative)]
140#[derivative(Default(bound = ""))]
141pub struct IpLayerPacketMetadata<
142 I: packet_formats::ip::IpExt,
143 A,
144 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
145> {
146 conntrack_connection_and_direction:
147 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
148
149 tx_metadata: BT::TxMetadata,
154
155 marks: Marks,
157
158 socket_info: Option<SocketInfo>,
160
161 gso_info: Option<GsoInfo>,
168
169 #[cfg(debug_assertions)]
170 drop_check: IpLayerPacketMetadataDropCheck,
171}
172
173#[cfg(debug_assertions)]
180#[derive(Default)]
181struct IpLayerPacketMetadataDropCheck {
182 okay_to_drop: bool,
183}
184
185#[derive(Derivative)]
188#[derivative(Debug(bound = ""), Default(bound = ""))]
189pub struct DeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
190 conntrack_entry: Option<(WeakConntrackConnection, ConnectionDirection)>,
198 tx_metadata: BT::TxMetadata,
203 marks: Marks,
210}
211
212impl<BT: TxMetadataBindingsTypes> DeviceIpLayerMetadata<BT> {
213 pub fn into_tx_metadata(self) -> BT::TxMetadata {
216 self.tx_metadata
217 }
218 #[cfg(any(test, feature = "testutils"))]
220 pub fn with_marks(marks: Marks) -> Self {
221 Self { conntrack_entry: None, tx_metadata: Default::default(), marks }
222 }
223}
224
225impl<
226 I: IpLayerIpExt,
227 A: WeakIpAddressId<I::Addr>,
228 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
229> IpLayerPacketMetadata<I, A, BT>
230{
231 fn from_device_ip_layer_metadata<CC, D>(
232 core_ctx: &mut CC,
233 device: &D,
234 DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks }: DeviceIpLayerMetadata<BT>,
235 gso_info: Option<GsoInfo>,
236 ) -> Self
237 where
238 CC: ResourceCounterContext<D, IpCounters<I>>,
239 {
240 let conntrack_connection_and_direction = match conntrack_entry
241 .map(|(conn, dir)| conn.into_inner().map(|conn| (conn, dir)))
242 .transpose()
243 {
244 Ok(conn_and_dir) => conn_and_dir,
247 Err(WeakConnectionError::EntryRemoved) => None,
249 Err(WeakConnectionError::InvalidEntry) => {
253 core_ctx.increment_both(device, |c| &c.invalid_cached_conntrack_entry);
254 None
255 }
256 };
257
258 Self {
259 conntrack_connection_and_direction,
260 tx_metadata,
261 marks,
262 socket_info: None,
266 gso_info,
267 #[cfg(debug_assertions)]
268 drop_check: Default::default(),
269 }
270 }
271}
272
273pub(crate) struct SplitMulticastPacketMetadata<I, A, BT>
276where
277 I: packet_formats::ip::IpExt,
278 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
279{
280 pub(crate) primary: IpLayerPacketMetadata<I, A, BT>,
281 pub(crate) secondary: IpLayerPacketMetadata<I, A, BT>,
282}
283
284impl<I: IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
285 IpLayerPacketMetadata<I, A, BT>
286{
287 pub(crate) fn split_for_multicast(self) -> SplitMulticastPacketMetadata<I, A, BT> {
295 let secondary = Self {
296 conntrack_connection_and_direction: None,
297 tx_metadata: Default::default(),
298 marks: self.marks,
299 socket_info: self.socket_info.clone(),
300 gso_info: self.gso_info,
301 #[cfg(debug_assertions)]
302 drop_check: Default::default(),
303 };
304 SplitMulticastPacketMetadata { primary: self, secondary }
305 }
306
307 pub(crate) fn new_local_tx(
308 tx_metadata: BT::TxMetadata,
309 marks: Marks,
310 gso_info: Option<GsoInfo>,
311 ) -> Self {
312 let socket_info = tx_metadata.socket_info();
313 Self {
314 conntrack_connection_and_direction: None,
315 tx_metadata,
316 marks,
317 socket_info,
318 gso_info,
319 #[cfg(debug_assertions)]
320 drop_check: Default::default(),
321 }
322 }
323
324 pub(crate) fn into_parts(
325 self,
326 ) -> (
327 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
328 BT::TxMetadata,
329 Marks,
330 Option<SocketInfo>,
331 Option<GsoInfo>,
332 ) {
333 let Self {
334 tx_metadata,
335 marks,
336 conntrack_connection_and_direction,
337 socket_info,
338 gso_info,
339 #[cfg(debug_assertions)]
340 mut drop_check,
341 } = self;
342 #[cfg(debug_assertions)]
343 {
344 drop_check.okay_to_drop = true;
345 }
346 (conntrack_connection_and_direction, tx_metadata, marks, socket_info, gso_info)
347 }
348
349 pub(crate) fn acknowledge_drop(self) {
354 #[cfg(debug_assertions)]
355 {
356 let mut this = self;
357 this.drop_check.okay_to_drop = true;
358 }
359 }
360
361 pub(crate) fn tx_metadata(&self) -> &BT::TxMetadata {
363 &self.tx_metadata
364 }
365
366 pub(crate) fn marks(&self) -> &Marks {
368 &self.marks
369 }
370}
371
372#[cfg(debug_assertions)]
373impl Drop for IpLayerPacketMetadataDropCheck {
374 fn drop(&mut self) {
375 if !self.okay_to_drop {
376 panic!(
377 "IpLayerPacketMetadata dropped without acknowledgement. https://fxbug.dev/334127474"
378 );
379 }
380 }
381}
382
383impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
384 FilterIpMetadata<I, A, BT> for IpLayerPacketMetadata<I, A, BT>
385{
386 fn take_connection_and_direction(
387 &mut self,
388 ) -> Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)> {
389 self.conntrack_connection_and_direction.take()
390 }
391
392 fn replace_connection_and_direction(
393 &mut self,
394 conn: ConntrackConnection<I, A, BT>,
395 direction: ConnectionDirection,
396 ) -> Option<ConntrackConnection<I, A, BT>> {
397 self.conntrack_connection_and_direction.replace((conn, direction)).map(|(conn, _dir)| conn)
398 }
399}
400
401impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
402 FilterPacketMetadata for IpLayerPacketMetadata<I, A, BT>
403{
404 fn apply_mark_action(&mut self, domain: MarkDomain, action: MarkAction) {
405 action.apply(self.marks.get_mut(domain))
406 }
407
408 fn socket_info(&self) -> Option<SocketInfo> {
409 self.socket_info.clone()
410 }
411
412 fn marks(&self) -> &Marks {
413 &self.marks
414 }
415}
416
417pub type IpSendFrameError<S> = ErrorAndSerializer<IpSendFrameErrorReason, S>;
419
420#[derive(Debug, PartialEq)]
422pub enum IpSendFrameErrorReason {
423 Device(SendFrameErrorReason),
425 IllegalLoopbackAddress,
428}
429
430impl From<SendFrameErrorReason> for IpSendFrameErrorReason {
431 fn from(value: SendFrameErrorReason) -> Self {
432 Self::Device(value)
433 }
434}
435
436pub trait IpTransportContext<I, BC, CC>
442where
443 I: IpLayerIpExt,
444 CC: DeviceIdContext<AnyDevice> + ?Sized,
445{
446 type EarlyDemuxSocket;
448
449 fn early_demux<B: ParseBuffer>(
460 core_ctx: &mut CC,
461 device: &CC::DeviceId,
462 src_ip: I::Addr,
463 dst_ip: I::Addr,
464 buffer: B,
465 ) -> Option<Self::EarlyDemuxSocket>;
466
467 fn receive_icmp_error(
481 core_ctx: &mut CC,
482 bindings_ctx: &mut BC,
483 device: &CC::DeviceId,
484 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
485 original_dst_ip: SpecifiedAddr<I::Addr>,
486 original_body: &[u8],
487 err: I::ErrorCode,
488 );
489
490 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
496 core_ctx: &mut CC,
497 bindings_ctx: &mut BC,
498 device: &CC::DeviceId,
499 src_ip: I::RecvSrcAddr,
500 dst_ip: SpecifiedAddr<I::Addr>,
501 buffer: B,
502 info: &mut LocalDeliveryPacketInfo<I, H>,
503 early_demux_socket: Option<Self::EarlyDemuxSocket>,
504 ) -> Result<(), (B, I::IcmpError)>;
505}
506
507pub trait BaseTransportIpContext<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
510 type DevicesWithAddrIter<'s>: Iterator<Item = Self::DeviceId>;
513
514 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
520 &mut self,
521 addr: SpecifiedAddr<I::Addr>,
522 cb: F,
523 ) -> O;
524
525 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits;
530
531 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)>;
535}
536
537pub trait TransportIpContext<I: IpExt + FilterIpExt, BC: TxMetadataBindingsTypes>:
540 BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>
541{
542}
543
544impl<I, CC, BC> TransportIpContext<I, BC> for CC
545where
546 I: IpExt + FilterIpExt,
547 CC: BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>,
548 BC: TxMetadataBindingsTypes,
549{
550}
551
552pub trait MulticastMembershipHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
554 fn join_multicast_group(
561 &mut self,
562 bindings_ctx: &mut BC,
563 device: &Self::DeviceId,
564 addr: MulticastAddr<I::Addr>,
565 );
566
567 fn leave_multicast_group(
575 &mut self,
576 bindings_ctx: &mut BC,
577 device: &Self::DeviceId,
578 addr: MulticastAddr<I::Addr>,
579 );
580
581 fn select_device_for_multicast_group(
586 &mut self,
587 addr: MulticastAddr<I::Addr>,
588 marks: &Marks,
589 ) -> Result<Self::DeviceId, ResolveRouteError>;
590}
591
592pub trait UseTransportIpContextBlanket {}
604
605pub struct AssignedAddressDeviceIterator<Iter, I, D>(Iter, PhantomData<(I, D)>);
608
609impl<Iter, I, D> Iterator for AssignedAddressDeviceIterator<Iter, I, D>
610where
611 Iter: Iterator<Item = (D, I::AddressStatus)>,
612 I: IpLayerIpExt,
613{
614 type Item = D;
615 fn next(&mut self) -> Option<D> {
616 let Self(iter, PhantomData) = self;
617 iter.by_ref().find_map(|(device, state)| is_unicast_assigned::<I>(&state).then_some(device))
618 }
619}
620
621impl<
622 I: IpLayerIpExt,
623 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + IpRoutingBindingsTypes,
624 CC: IpDeviceContext<I>
625 + IpSocketHandler<I, BC>
626 + IpStateContext<I, BC>
627 + FilterIpContext<I, BC>
628 + UseTransportIpContextBlanket,
629> BaseTransportIpContext<I, BC> for CC
630{
631 type DevicesWithAddrIter<'s> =
632 AssignedAddressDeviceIterator<CC::DeviceAndAddressStatusIter<'s>, I, CC::DeviceId>;
633
634 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
635 &mut self,
636 addr: SpecifiedAddr<I::Addr>,
637 cb: F,
638 ) -> O {
639 self.with_address_statuses(addr, |it| cb(AssignedAddressDeviceIterator(it, PhantomData)))
640 }
641
642 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
643 match device {
644 Some(device) => HopLimits {
645 unicast: IpDeviceEgressStateContext::<I>::get_hop_limit(self, device),
646 ..DEFAULT_HOP_LIMITS
647 },
648 None => DEFAULT_HOP_LIMITS,
649 }
650 }
651
652 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)> {
653 self.with_filter_state(|state| {
654 let conn = state.conntrack.get_connection(&tuple)?;
655
656 if !conn.destination_nat() {
657 return None;
658 }
659
660 let original = conn.original_tuple();
664 Some((original.dst_addr, original.dst_port_or_id))
665 })
666 }
667}
668
669#[derive(Debug, PartialEq)]
671#[allow(missing_docs)]
672pub enum AddressStatus<S> {
673 Present(S),
674 Unassigned,
675}
676
677impl<S> AddressStatus<S> {
678 fn into_present(self) -> Option<S> {
679 match self {
680 Self::Present(s) => Some(s),
681 Self::Unassigned => None,
682 }
683 }
684}
685
686impl AddressStatus<Ipv4PresentAddressStatus> {
687 pub fn from_context_addr_v4<
689 BC: IpDeviceStateBindingsTypes,
690 CC: device::IpDeviceStateContext<Ipv4, BC> + GmpQueryHandler<Ipv4, BC>,
691 >(
692 core_ctx: &mut CC,
693 device: &CC::DeviceId,
694 addr: SpecifiedAddr<Ipv4Addr>,
695 ) -> AddressStatus<Ipv4PresentAddressStatus> {
696 if addr.is_limited_broadcast() {
697 return AddressStatus::Present(Ipv4PresentAddressStatus::LimitedBroadcast);
698 }
699
700 if MulticastAddr::new(addr.get())
701 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
702 {
703 return AddressStatus::Present(Ipv4PresentAddressStatus::Multicast);
704 }
705
706 core_ctx.with_address_ids(device, |mut addrs, core_ctx| {
707 addrs
708 .find_map(|addr_id| {
709 let dev_addr = addr_id.addr_sub();
710 let (dev_addr, subnet) = dev_addr.addr_subnet();
711
712 if **dev_addr == addr {
713 let assigned = core_ctx.with_ip_address_data(
714 device,
715 &addr_id,
716 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| {
717 *assigned
718 },
719 );
720
721 if assigned {
722 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastAssigned))
723 } else {
724 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastTentative))
725 }
726 } else if addr.get() == subnet.broadcast() {
727 Some(AddressStatus::Present(Ipv4PresentAddressStatus::SubnetBroadcast))
728 } else if device.is_loopback() && subnet.contains(addr.as_ref()) {
729 Some(AddressStatus::Present(Ipv4PresentAddressStatus::LoopbackSubnet))
730 } else {
731 None
732 }
733 })
734 .unwrap_or(AddressStatus::Unassigned)
735 })
736 }
737}
738
739impl AddressStatus<Ipv6PresentAddressStatus> {
740 pub fn from_context_addr_v6<
742 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
743 CC: device::Ipv6DeviceContext<BC> + GmpQueryHandler<Ipv6, BC>,
744 >(
745 core_ctx: &mut CC,
746 device: &CC::DeviceId,
747 addr: SpecifiedAddr<Ipv6Addr>,
748 ) -> AddressStatus<Ipv6PresentAddressStatus> {
749 if MulticastAddr::new(addr.get())
750 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
751 {
752 return AddressStatus::Present(Ipv6PresentAddressStatus::Multicast);
753 }
754
755 let addr_id = match core_ctx.get_address_id(device, addr) {
756 Ok(o) => o,
757 Err(NotFoundError) => return AddressStatus::Unassigned,
758 };
759
760 let assigned = core_ctx.with_ip_address_data(
761 device,
762 &addr_id,
763 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
764 );
765
766 if assigned {
767 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned)
768 } else {
769 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastTentative)
770 }
771 }
772}
773
774impl<S: GenericOverIp<I>, I: Ip> GenericOverIp<I> for AddressStatus<S> {
775 type Type = AddressStatus<S::Type>;
776}
777
778#[derive(Debug, PartialEq)]
780#[allow(missing_docs)]
781pub enum Ipv4PresentAddressStatus {
782 LimitedBroadcast,
783 SubnetBroadcast,
784 Multicast,
785 UnicastAssigned,
786 UnicastTentative,
787 LoopbackSubnet,
798}
799
800impl Ipv4PresentAddressStatus {
801 fn to_broadcast_marker(&self) -> Option<<Ipv4 as BroadcastIpExt>::BroadcastMarker> {
802 match self {
803 Self::LimitedBroadcast | Self::SubnetBroadcast => Some(()),
804 Self::Multicast
805 | Self::UnicastAssigned
806 | Self::UnicastTentative
807 | Self::LoopbackSubnet => None,
808 }
809 }
810}
811
812#[derive(Debug, PartialEq)]
814#[allow(missing_docs)]
815pub enum Ipv6PresentAddressStatus {
816 Multicast,
817 UnicastAssigned,
818 UnicastTentative,
819}
820
821pub trait IpLayerIpExt:
823 IpExt
824 + MulticastRouteIpExt
825 + IcmpHandlerIpExt
826 + FilterIpExt
827 + FragmentationIpExt
828 + IpDeviceIpExt
829 + IpCountersIpExt
830 + IcmpCountersIpExt
831 + ReassemblyIpExt
832{
833 type AddressStatus: Debug;
835 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>: AsRef<
837 IpStateInner<Self, StrongDeviceId, BT>,
838 >;
839 type PacketIdState;
841 type PacketId;
843 fn next_packet_id_from_state(state: &Self::PacketIdState) -> Self::PacketId;
845}
846
847impl IpLayerIpExt for Ipv4 {
848 type AddressStatus = Ipv4PresentAddressStatus;
849 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
850 Ipv4State<StrongDeviceId, BT>;
851 type PacketIdState = AtomicU16;
852 type PacketId = u16;
853 fn next_packet_id_from_state(next_packet_id: &Self::PacketIdState) -> Self::PacketId {
854 next_packet_id.fetch_add(1, atomic::Ordering::Relaxed)
858 }
859}
860
861impl IpLayerIpExt for Ipv6 {
862 type AddressStatus = Ipv6PresentAddressStatus;
863 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
864 Ipv6State<StrongDeviceId, BT>;
865 type PacketIdState = ();
866 type PacketId = ();
867 fn next_packet_id_from_state((): &Self::PacketIdState) -> Self::PacketId {
868 ()
869 }
870}
871
872pub trait IpStateContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes + MatcherBindingsTypes>:
874 IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>
875{
876 type IpRouteTablesCtx<'a>: IpRouteTablesContext<I, BT, DeviceId = Self::DeviceId>;
878
879 fn with_rules_table<
881 O,
882 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId, BT>) -> O,
883 >(
884 &mut self,
885 cb: F,
886 ) -> O;
887
888 fn with_rules_table_mut<
890 O,
891 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId, BT>) -> O,
892 >(
893 &mut self,
894 cb: F,
895 ) -> O;
896}
897
898pub trait IpRouteTablesContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
900 IpRouteTableContext<I, BT> + IpDeviceContext<I>
901{
902 type Ctx<'a>: IpRouteTableContext<I, BT, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>;
904
905 fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId, BT>;
907
908 fn with_ip_routing_tables<
910 O,
911 F: FnOnce(
912 &mut Self::Ctx<'_>,
913 &HashMap<
914 RoutingTableId<I, Self::DeviceId, BT>,
915 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
916 >,
917 ) -> O,
918 >(
919 &mut self,
920 cb: F,
921 ) -> O;
922
923 fn with_ip_routing_tables_mut<
925 O,
926 F: FnOnce(
927 &mut HashMap<
928 RoutingTableId<I, Self::DeviceId, BT>,
929 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
930 >,
931 ) -> O,
932 >(
933 &mut self,
934 cb: F,
935 ) -> O;
936
937 fn with_main_ip_routing_table<
941 O,
942 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
943 >(
944 &mut self,
945 cb: F,
946 ) -> O {
947 let main_table_id = self.main_table_id();
948 self.with_ip_routing_table(&main_table_id, cb)
949 }
950
951 fn with_main_ip_routing_table_mut<
955 O,
956 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
957 >(
958 &mut self,
959 cb: F,
960 ) -> O {
961 let main_table_id = self.main_table_id();
962 self.with_ip_routing_table_mut(&main_table_id, cb)
963 }
964}
965
966pub trait IpRouteTableContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
968 IpDeviceContext<I>
969{
970 type IpDeviceIdCtx<'a>: DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
972 + IpRoutingDeviceContext<I>
973 + IpDeviceContext<I>;
974
975 fn with_ip_routing_table<
977 O,
978 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
979 >(
980 &mut self,
981 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
982 cb: F,
983 ) -> O;
984
985 fn with_ip_routing_table_mut<
987 O,
988 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
989 >(
990 &mut self,
991 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
992 cb: F,
993 ) -> O;
994}
995
996pub trait IpDeviceEgressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
998 fn with_next_packet_id<O, F: FnOnce(&I::PacketIdState) -> O>(&self, cb: F) -> O;
1000
1001 fn get_local_addr_for_remote(
1003 &mut self,
1004 device_id: &Self::DeviceId,
1005 remote: Option<SpecifiedAddr<I::Addr>>,
1006 ) -> Option<IpDeviceAddr<I::Addr>>;
1007
1008 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8;
1010}
1011
1012pub trait IpDeviceIngressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
1014 fn address_status_for_device(
1020 &mut self,
1021 addr: SpecifiedAddr<I::Addr>,
1022 device_id: &Self::DeviceId,
1023 ) -> AddressStatus<I::AddressStatus>;
1024}
1025
1026pub trait IpDeviceContext<I: IpLayerIpExt>:
1028 IpDeviceEgressStateContext<I> + IpDeviceIngressStateContext<I>
1029{
1030 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
1032
1033 type DeviceAndAddressStatusIter<'a>: Iterator<Item = (Self::DeviceId, I::AddressStatus)>;
1035
1036 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
1042 &mut self,
1043 addr: SpecifiedAddr<I::Addr>,
1044 cb: F,
1045 ) -> R;
1046
1047 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
1049}
1050
1051pub trait IpDeviceConfirmReachableContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1053 fn confirm_reachable(
1056 &mut self,
1057 bindings_ctx: &mut BC,
1058 device: &Self::DeviceId,
1059 neighbor: SpecifiedAddr<I::Addr>,
1060 );
1061}
1062
1063pub trait IpDeviceMtuContext<I: Ip>: DeviceIdContext<AnyDevice> {
1065 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu;
1069}
1070
1071#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
1073#[generic_over_ip(I, Ip)]
1074pub enum IpLayerEvent<DeviceId, I: IpLayerIpExt> {
1075 AddRoute(types::AddableEntry<I::Addr, DeviceId>),
1077 RemoveRoutes {
1079 subnet: Subnet<I::Addr>,
1081 device: DeviceId,
1083 gateway: Option<SpecifiedAddr<I::Addr>>,
1085 },
1086 MulticastForwarding(MulticastForwardingEvent<I, DeviceId>),
1088}
1089
1090impl<DeviceId, I: IpLayerIpExt> From<MulticastForwardingEvent<I, DeviceId>>
1091 for IpLayerEvent<DeviceId, I>
1092{
1093 fn from(event: MulticastForwardingEvent<I, DeviceId>) -> IpLayerEvent<DeviceId, I> {
1094 IpLayerEvent::MulticastForwarding(event)
1095 }
1096}
1097
1098impl<DeviceId, I: IpLayerIpExt> IpLayerEvent<DeviceId, I> {
1099 pub fn map_device<N, F: Fn(DeviceId) -> N>(self, map: F) -> IpLayerEvent<N, I> {
1101 match self {
1102 IpLayerEvent::AddRoute(types::AddableEntry {
1103 subnet,
1104 device,
1105 gateway,
1106 metric,
1107 route_preference,
1108 }) => IpLayerEvent::AddRoute(types::AddableEntry {
1109 subnet,
1110 device: map(device),
1111 gateway,
1112 metric,
1113 route_preference,
1114 }),
1115 IpLayerEvent::RemoveRoutes { subnet, device, gateway } => {
1116 IpLayerEvent::RemoveRoutes { subnet, device: map(device), gateway }
1117 }
1118 IpLayerEvent::MulticastForwarding(e) => {
1119 IpLayerEvent::MulticastForwarding(e.map_device(map))
1120 }
1121 }
1122 }
1123}
1124
1125#[derive(Derivative, PartialEq, Eq, Clone, Hash)]
1127#[derivative(Debug)]
1128pub struct RouterAdvertisementEvent<D> {
1129 #[derivative(Debug = "ignore")]
1132 pub options_bytes: Box<[u8]>,
1133 pub source: net_types::ip::Ipv6Addr,
1135 pub device: D,
1137}
1138
1139impl<D> RouterAdvertisementEvent<D> {
1140 pub fn map_device<N, F: Fn(D) -> N>(self, map: F) -> RouterAdvertisementEvent<N> {
1142 let Self { options_bytes, source, device } = self;
1143 RouterAdvertisementEvent { options_bytes, source, device: map(device) }
1144 }
1145}
1146
1147pub trait NdpBindingsContext<DeviceId>: EventContext<RouterAdvertisementEvent<DeviceId>> {}
1149impl<DeviceId, BC: EventContext<RouterAdvertisementEvent<DeviceId>>> NdpBindingsContext<DeviceId>
1150 for BC
1151{
1152}
1153
1154pub trait MarksBindingsContext {
1156 fn marks_to_keep_on_egress() -> &'static [MarkDomain];
1161
1162 fn marks_to_set_on_ingress() -> &'static [MarkDomain];
1167
1168 fn update_ingress_marks(mut packet_marks: Marks, socket_marks: &Marks) -> Marks {
1171 for mark in Self::marks_to_set_on_ingress() {
1172 *packet_marks.get_mut(*mark) = *socket_marks.get(*mark);
1173 }
1174 packet_marks
1175 }
1176}
1177
1178pub trait IpLayerBindingsContext<I: IpLayerIpExt, DeviceId>:
1180 InstantContext
1181 + EventContext<IpLayerEvent<DeviceId, I>>
1182 + FilterBindingsContext<DeviceId>
1183 + TxMetadataBindingsTypes
1184 + IpRoutingBindingsTypes
1185 + MarksBindingsContext
1186{
1187}
1188impl<
1189 I: IpLayerIpExt,
1190 DeviceId,
1191 BC: InstantContext
1192 + EventContext<IpLayerEvent<DeviceId, I>>
1193 + FilterBindingsContext<DeviceId>
1194 + TxMetadataBindingsTypes
1195 + IpRoutingBindingsTypes
1196 + MarksBindingsContext,
1197> IpLayerBindingsContext<I, DeviceId> for BC
1198{
1199}
1200
1201pub trait IpLayerBindingsTypes:
1203 IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes
1204{
1205}
1206impl<BT: IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes> IpLayerBindingsTypes
1207 for BT
1208{
1209}
1210
1211pub trait IpLayerContext<
1213 I: IpLayerIpExt,
1214 BC: IpLayerBindingsContext<I, <Self as DeviceIdContext<AnyDevice>>::DeviceId>,
1215>:
1216 IpStateContext<I, BC>
1217 + IpDeviceContext<I>
1218 + IpDeviceMtuContext<I>
1219 + IpDeviceSendContext<I, BC>
1220 + IcmpErrorHandler<I, BC>
1221 + MulticastForwardingStateContext<I, BC>
1222 + MulticastForwardingDeviceContext<I>
1223 + CounterContext<MulticastForwardingCounters<I>>
1224 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>
1225{
1226}
1227
1228impl<
1229 I: IpLayerIpExt,
1230 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
1231 CC: IpStateContext<I, BC>
1232 + IpDeviceContext<I>
1233 + IpDeviceMtuContext<I>
1234 + IpDeviceSendContext<I, BC>
1235 + IcmpErrorHandler<I, BC>
1236 + MulticastForwardingStateContext<I, BC>
1237 + MulticastForwardingDeviceContext<I>
1238 + CounterContext<MulticastForwardingCounters<I>>
1239 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>,
1240> IpLayerContext<I, BC> for CC
1241{
1242}
1243
1244fn is_unicast_assigned<I: IpLayerIpExt>(status: &I::AddressStatus) -> bool {
1245 #[derive(GenericOverIp)]
1246 #[generic_over_ip(I, Ip)]
1247 struct WrapAddressStatus<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
1248
1249 I::map_ip(
1250 WrapAddressStatus(status),
1251 |WrapAddressStatus(status)| match status {
1252 Ipv4PresentAddressStatus::UnicastAssigned
1253 | Ipv4PresentAddressStatus::LoopbackSubnet => true,
1254 Ipv4PresentAddressStatus::UnicastTentative
1255 | Ipv4PresentAddressStatus::LimitedBroadcast
1256 | Ipv4PresentAddressStatus::SubnetBroadcast
1257 | Ipv4PresentAddressStatus::Multicast => false,
1258 },
1259 |WrapAddressStatus(status)| match status {
1260 Ipv6PresentAddressStatus::UnicastAssigned => true,
1261 Ipv6PresentAddressStatus::Multicast | Ipv6PresentAddressStatus::UnicastTentative => {
1262 false
1263 }
1264 },
1265 )
1266}
1267
1268fn is_local_assigned_address<I: Ip + IpLayerIpExt, CC: IpDeviceIngressStateContext<I>>(
1269 core_ctx: &mut CC,
1270 device: &CC::DeviceId,
1271 addr: IpDeviceAddr<I::Addr>,
1272) -> bool {
1273 match core_ctx.address_status_for_device(addr.into(), device) {
1274 AddressStatus::Present(status) => is_unicast_assigned::<I>(&status),
1275 AddressStatus::Unassigned => false,
1276 }
1277}
1278
1279fn get_device_with_assigned_address<I, CC>(
1280 core_ctx: &mut CC,
1281 addr: IpDeviceAddr<I::Addr>,
1282) -> Option<(CC::DeviceId, I::AddressStatus)>
1283where
1284 I: IpLayerIpExt,
1285 CC: IpDeviceContext<I>,
1286{
1287 core_ctx.with_address_statuses(addr.into(), |mut it| {
1288 it.find_map(|(device, status)| {
1289 is_unicast_assigned::<I>(&status).then_some((device, status))
1290 })
1291 })
1292}
1293
1294fn get_local_addr<I: Ip + IpLayerIpExt, CC: IpDeviceContext<I>>(
1298 core_ctx: &mut CC,
1299 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1300 device: &CC::DeviceId,
1301 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1302) -> Result<IpDeviceAddr<I::Addr>, ResolveRouteError> {
1303 match local_ip_and_policy {
1304 Some((local_ip, NonLocalSrcAddrPolicy::Allow)) => Ok(local_ip),
1305 Some((local_ip, NonLocalSrcAddrPolicy::Deny)) => {
1306 is_local_assigned_address(core_ctx, device, local_ip)
1307 .then_some(local_ip)
1308 .ok_or(ResolveRouteError::NoSrcAddr)
1309 }
1310 None => core_ctx
1311 .get_local_addr_for_remote(device, remote_addr.map(Into::into))
1312 .ok_or(ResolveRouteError::NoSrcAddr),
1313 }
1314}
1315
1316#[derive(Error, Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
1318#[generic_over_ip()]
1319pub enum ResolveRouteError {
1320 #[error("a source address could not be selected")]
1322 NoSrcAddr,
1323 #[error("no route exists to the destination IP address")]
1325 Unreachable,
1326}
1327
1328fn get_local_addr_with_internal_forwarding<I, CC>(
1330 core_ctx: &mut CC,
1331 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1332 device: &CC::DeviceId,
1333 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1334) -> Result<(IpDeviceAddr<I::Addr>, InternalForwarding<CC::DeviceId>), ResolveRouteError>
1335where
1336 I: IpLayerIpExt,
1337 CC: IpDeviceContext<I>,
1338{
1339 match get_local_addr(core_ctx, local_ip_and_policy, device, remote_addr) {
1340 Ok(src_addr) => Ok((src_addr, InternalForwarding::NotUsed)),
1341 Err(e) => {
1342 if let Some((local_ip, _policy)) = local_ip_and_policy {
1350 if let Some((device, _addr_status)) =
1351 get_device_with_assigned_address(core_ctx, local_ip)
1352 {
1353 if core_ctx.is_device_unicast_forwarding_enabled(&device) {
1354 return Ok((local_ip, InternalForwarding::Used(device)));
1355 }
1356 }
1357 }
1358 Err(e)
1359 }
1360 }
1361}
1362
1363#[derive(Debug, PartialEq, Eq)]
1366struct RuleWalkInfo<O> {
1367 observed_source_address_matcher: bool,
1369 inner: O,
1372}
1373
1374fn walk_rules<
1388 I: IpLayerIpExt,
1389 BT: IpRoutingBindingsTypes + MatcherBindingsTypes,
1390 CC: IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>,
1391 O,
1392 State,
1393 F: FnMut(
1394 State,
1395 &mut CC::IpDeviceIdCtx<'_>,
1396 &RoutingTable<I, CC::DeviceId>,
1397 ) -> ControlFlow<O, State>,
1398>(
1399 core_ctx: &mut CC,
1400 rules: &RulesTable<I, CC::DeviceId, BT>,
1401 init: State,
1402 rule_input: &RuleInput<'_, I, CC::DeviceId>,
1403 mut lookup_table: F,
1404) -> ControlFlow<RuleAction<RuleWalkInfo<O>>, RuleWalkInfo<State>> {
1405 rules.iter().try_fold(
1406 RuleWalkInfo { inner: init, observed_source_address_matcher: false },
1407 |RuleWalkInfo { inner: state, observed_source_address_matcher },
1408 Rule { action, matcher }| {
1409 let observed_source_address_matcher =
1410 observed_source_address_matcher || matcher.source_address_matcher.is_some();
1411 if !matcher.matches(rule_input) {
1412 return ControlFlow::Continue(RuleWalkInfo {
1413 inner: state,
1414 observed_source_address_matcher,
1415 });
1416 }
1417 match action {
1418 RuleAction::Unreachable => return ControlFlow::Break(RuleAction::Unreachable),
1419 RuleAction::Lookup(table_id) => core_ctx.with_ip_routing_table(
1420 &table_id,
1421 |core_ctx, table| match lookup_table(state, core_ctx, table) {
1422 ControlFlow::Break(out) => {
1423 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1424 inner: out,
1425 observed_source_address_matcher,
1426 }))
1427 }
1428 ControlFlow::Continue(state) => ControlFlow::Continue(RuleWalkInfo {
1429 inner: state,
1430 observed_source_address_matcher,
1431 }),
1432 },
1433 ),
1434 }
1435 },
1436 )
1437}
1438
1439pub fn resolve_output_route_to_destination<
1450 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1451 BC: IpDeviceBindingsContext<I, CC::DeviceId> + IpLayerBindingsContext<I, CC::DeviceId>,
1452 CC: IpStateContext<I, BC> + IpDeviceContext<I> + device::IpDeviceConfigurationContext<I, BC>,
1453>(
1454 core_ctx: &mut CC,
1455 device: Option<&CC::DeviceId>,
1456 src_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1457 dst_ip: Option<RoutableIpAddr<I::Addr>>,
1458 marks: &Marks,
1459) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1460 enum LocalDelivery<A, D> {
1461 WeakLoopback { dst_ip: A, device: D },
1462 StrongForDevice(D),
1463 }
1464
1465 let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1482 let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1483 match (device, dst_ip) {
1484 (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1485 .then_some(LocalDelivery::StrongForDevice(device.clone())),
1486 (None, Some(dst_ip)) => {
1487 get_device_with_assigned_address(core_ctx, dst_ip).map(
1488 |(dst_device, _addr_status)| {
1489 if src_ip_and_policy
1494 .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1495 || dst_ip.as_ref().must_have_zone()
1496 {
1497 LocalDelivery::StrongForDevice(dst_device)
1498 } else {
1499 LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1500 }
1501 },
1502 )
1503 }
1504 (_, None) => None,
1505 }
1506 };
1507
1508 if let Some(local_delivery) = local_delivery_instructions {
1509 let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1510
1511 let (src_addr, dest_device) = match local_delivery {
1512 LocalDelivery::WeakLoopback { dst_ip, device } => {
1513 let src_ip = match src_ip_and_policy {
1514 Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1515 let _device = get_device_with_assigned_address(core_ctx, src_ip)
1516 .ok_or(ResolveRouteError::NoSrcAddr)?;
1517 src_ip
1518 }
1519 Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1520 None => dst_ip,
1521 };
1522 (src_ip, device)
1523 }
1524 LocalDelivery::StrongForDevice(device) => {
1525 (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1526 }
1527 };
1528 return Ok(ResolvedRoute {
1529 src_addr,
1530 local_delivery_device: Some(dest_device),
1531 device: loopback,
1532 next_hop: NextHop::RemoteAsNeighbor,
1533 internal_forwarding: InternalForwarding::NotUsed,
1534 });
1535 }
1536 let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1537 let rule_input = RuleInput {
1538 packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1539 marks,
1540 };
1541 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
1542 let mut walk_rules = |rule_input, src_ip_and_policy| {
1543 walk_rules(
1544 core_ctx,
1545 rules,
1546 None, rule_input,
1548 |first_error, core_ctx, table| {
1549 let mut matching_with_addr = table.lookup_filter_map(
1550 core_ctx,
1551 device,
1552 dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1553 |core_ctx, d| {
1554 Some(get_local_addr_with_internal_forwarding(
1555 core_ctx,
1556 src_ip_and_policy,
1557 d,
1558 dst_ip,
1559 ))
1560 },
1561 );
1562
1563 let first_error_in_this_table = match matching_with_addr.next() {
1564 Some((
1565 Destination { device, next_hop },
1566 Ok((local_addr, internal_forwarding)),
1567 )) => {
1568 return ControlFlow::Break(Ok((
1569 Destination { device: device.clone(), next_hop },
1570 local_addr,
1571 internal_forwarding,
1572 )));
1573 }
1574 Some((_, Err(e))) => e,
1575 None => return ControlFlow::Continue(first_error),
1579 };
1580
1581 matching_with_addr
1582 .filter_map(|(destination, local_addr)| {
1583 local_addr.ok_checked::<ResolveRouteError>().map(
1586 |(local_addr, internal_forwarding)| {
1587 (destination, local_addr, internal_forwarding)
1588 },
1589 )
1590 })
1591 .next()
1592 .map_or(
1593 ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1594 |(
1595 Destination { device, next_hop },
1596 local_addr,
1597 internal_forwarding,
1598 )| {
1599 ControlFlow::Break(Ok((
1600 Destination { device: device.clone(), next_hop },
1601 local_addr,
1602 internal_forwarding,
1603 )))
1604 },
1605 )
1606 },
1607 )
1608 };
1609
1610 let result = match walk_rules(&rule_input, src_ip_and_policy) {
1611 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1618 inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1619 observed_source_address_matcher: true,
1620 })) if src_ip_and_policy.is_none() => walk_rules(
1621 &RuleInput {
1622 packet_origin: PacketOrigin::Local {
1623 bound_address: Some(selected_src_addr.into()),
1624 bound_device: device,
1625 },
1626 marks,
1627 },
1628 Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1629 ),
1630 result => result,
1631 };
1632
1633 match result {
1634 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1635 inner: result,
1636 observed_source_address_matcher: _,
1637 })) => {
1638 result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1639 ResolvedRoute {
1640 src_addr,
1641 device,
1642 local_delivery_device: None,
1643 next_hop,
1644 internal_forwarding,
1645 }
1646 })
1647 }
1648 ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1649 ControlFlow::Continue(RuleWalkInfo {
1650 inner: first_error,
1651 observed_source_address_matcher: _,
1652 }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1653 }
1654 })
1655}
1656
1657pub trait UseIpSocketContextBlanket {}
1662
1663impl<I, BC, CC> IpSocketContext<I, BC> for CC
1664where
1665 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1666 BC: IpDeviceBindingsContext<I, CC::DeviceId>
1667 + IpLayerBindingsContext<I, CC::DeviceId>
1668 + IpSocketBindingsContext<CC::DeviceId>,
1669 CC: IpLayerEgressContext<I, BC>
1670 + IpStateContext<I, BC>
1671 + IpDeviceContext<I>
1672 + IpDeviceConfirmReachableContext<I, BC>
1673 + IpDeviceMtuContext<I>
1674 + device::IpDeviceConfigurationContext<I, BC>
1675 + IcmpErrorHandler<I, BC>
1676 + UseIpSocketContextBlanket,
1677{
1678 fn lookup_route(
1679 &mut self,
1680 _bindings_ctx: &mut BC,
1681 device: Option<&CC::DeviceId>,
1682 local_ip: Option<IpDeviceAddr<I::Addr>>,
1683 addr: RoutableIpAddr<I::Addr>,
1684 transparent: bool,
1685 marks: &Marks,
1686 ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1687 let src_ip_and_policy = local_ip.map(|local_ip| {
1688 (
1689 local_ip,
1690 if transparent {
1691 NonLocalSrcAddrPolicy::Allow
1692 } else {
1693 NonLocalSrcAddrPolicy::Deny
1694 },
1695 )
1696 });
1697 let res =
1698 resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1699 trace!(
1700 "lookup_route(\
1701 device={device:?}, \
1702 local_ip={local_ip:?}, \
1703 addr={addr:?}, \
1704 transparent={transparent:?}, \
1705 marks={marks:?}) => {res:?}"
1706 );
1707 res
1708 }
1709
1710 fn send_ip_packet<S>(
1711 &mut self,
1712 bindings_ctx: &mut BC,
1713 meta: SendIpPacketMeta<
1714 I,
1715 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1716 SpecifiedAddr<I::Addr>,
1717 >,
1718 body: S,
1719 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1720 ) -> Result<(), IpSendFrameError<S>>
1721 where
1722 S: TransportPacketSerializer<I>,
1723 S::Buffer: BufferMut,
1724 {
1725 send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1726 }
1727
1728 fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1729 device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1730 }
1731
1732 fn confirm_reachable(
1733 &mut self,
1734 bindings_ctx: &mut BC,
1735 dst: SpecifiedAddr<I::Addr>,
1736 input: RuleInput<'_, I, Self::DeviceId>,
1737 ) {
1738 match lookup_route_table(self, dst.get(), input) {
1739 Some(Destination { next_hop, device }) => {
1740 let neighbor = match next_hop {
1741 NextHop::RemoteAsNeighbor => dst,
1742 NextHop::Gateway(gateway) => gateway,
1743 NextHop::Broadcast(marker) => {
1744 I::map_ip::<_, ()>(
1745 WrapBroadcastMarker(marker),
1746 |WrapBroadcastMarker(())| {
1747 debug!(
1748 "can't confirm {dst:?}@{device:?} as reachable: \
1749 dst is a broadcast address"
1750 );
1751 },
1752 |WrapBroadcastMarker(never)| match never {},
1753 );
1754 return;
1755 }
1756 };
1757 IpDeviceConfirmReachableContext::confirm_reachable(
1758 self,
1759 bindings_ctx,
1760 &device,
1761 neighbor,
1762 );
1763 }
1764 None => {
1765 debug!("can't confirm {dst:?} as reachable: no route");
1766 }
1767 }
1768 }
1769}
1770
1771pub trait SocketMetadata<CC>
1774where
1775 CC: ?Sized,
1776{
1777 fn socket_info(&self, core_ctx: &mut CC) -> SocketInfo;
1779 fn marks(&self, _core_ctx: &mut CC) -> Marks;
1781}
1782
1783impl<T, O, CC> SocketMetadata<CC> for EitherStack<T, O>
1784where
1785 CC: ?Sized,
1786 T: SocketMetadata<CC>,
1787 O: SocketMetadata<CC>,
1788{
1789 fn socket_info(&self, core_ctx: &mut CC) -> SocketInfo {
1790 match self {
1791 Self::ThisStack(t) => t.socket_info(core_ctx),
1792 Self::OtherStack(o) => o.socket_info(core_ctx),
1793 }
1794 }
1795
1796 fn marks(&self, core_ctx: &mut CC) -> Marks {
1797 match self {
1798 Self::ThisStack(t) => t.marks(core_ctx),
1799 Self::OtherStack(o) => o.marks(core_ctx),
1800 }
1801 }
1802}
1803
1804pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1809 type EarlyDemuxSocket: SocketMetadata<Self>;
1811
1812 fn early_demux<B: ParseBuffer>(
1814 &mut self,
1815 device: &Self::DeviceId,
1816 frame_dst: Option<LocalFrameDestination>,
1817 src_ip: I::Addr,
1818 dst_ip: I::Addr,
1819 proto: I::Proto,
1820 body: B,
1821 ) -> Option<Self::EarlyDemuxSocket>;
1822
1823 fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1827 &mut self,
1828 bindings_ctx: &mut BC,
1829 device: &Self::DeviceId,
1830 src_ip: I::RecvSrcAddr,
1831 dst_ip: SpecifiedAddr<I::Addr>,
1832 proto: I::Proto,
1833 body: B,
1834 info: &mut LocalDeliveryPacketInfo<I, H>,
1835 early_demux_socket: Option<Self::EarlyDemuxSocket>,
1836 ) -> Result<(), I::IcmpError>;
1837}
1838
1839pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1841 IpTransportDispatchContext<
1842 I,
1843 BC,
1844 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1845 > + IpDeviceIngressStateContext<I>
1846 + IpDeviceMtuContext<I>
1847 + IpDeviceSendContext<I, BC>
1848 + IcmpErrorHandler<I, BC>
1849 + IpLayerContext<I, BC>
1850 + FragmentHandler<I, BC>
1851 + FilterHandlerProvider<I, BC>
1852 + RawIpSocketHandler<I, BC>
1853{
1854}
1855
1856impl<
1857 I: IpLayerIpExt,
1858 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1859 CC: IpTransportDispatchContext<
1860 I,
1861 BC,
1862 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1863 > + IpDeviceIngressStateContext<I>
1864 + IpDeviceMtuContext<I>
1865 + IpDeviceSendContext<I, BC>
1866 + IcmpErrorHandler<I, BC>
1867 + IpLayerContext<I, BC>
1868 + FragmentHandler<I, BC>
1869 + FilterHandlerProvider<I, BC>
1870 + RawIpSocketHandler<I, BC>,
1871> IpLayerIngressContext<I, BC> for CC
1872{
1873}
1874
1875pub trait IpLayerEgressContext<I, BC>:
1877 IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1878 + FilterHandlerProvider<I, BC>
1879 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1880where
1881 I: IpLayerIpExt,
1882 BC: FilterBindingsContext<Self::DeviceId> + TxMetadataBindingsTypes,
1883{
1884}
1885
1886impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1887where
1888 I: IpLayerIpExt,
1889 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes,
1890 CC: IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1891 + FilterHandlerProvider<I, BC>
1892 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
1893{
1894}
1895
1896pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1898 IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
1899{
1900}
1901
1902impl<
1903 I: IpLayerIpExt,
1904 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1905 CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
1906> IpLayerForwardingContext<I, BC> for CC
1907{
1908}
1909
1910#[derive(Copy, Clone, Default)]
1912pub struct Ipv4StateBuilder {
1913 icmp: Icmpv4StateBuilder,
1914}
1915
1916impl Ipv4StateBuilder {
1917 #[cfg(any(test, feature = "testutils"))]
1919 pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
1920 &mut self.icmp
1921 }
1922
1923 pub fn build<
1925 CC: CoreTimerContext<IpLayerTimerId, BC>,
1926 StrongDeviceId: StrongDeviceIdentifier,
1927 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1928 >(
1929 self,
1930 bindings_ctx: &mut BC,
1931 ) -> Ipv4State<StrongDeviceId, BC> {
1932 let Ipv4StateBuilder { icmp } = self;
1933
1934 Ipv4State {
1935 inner: IpStateInner::new::<CC>(bindings_ctx),
1936 icmp: icmp.build(),
1937 next_packet_id: Default::default(),
1938 }
1939 }
1940}
1941
1942#[derive(Copy, Clone)]
1946pub struct Ipv6StateBuilder {
1947 icmp: Icmpv6StateBuilder,
1948 slaac_stable_secret_key: Option<IidSecret>,
1949}
1950
1951impl Ipv6StateBuilder {
1952 pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
1957 self.slaac_stable_secret_key = Some(secret_key);
1958 self
1959 }
1960
1961 pub fn build<
1967 CC: CoreTimerContext<IpLayerTimerId, BC>,
1968 StrongDeviceId: StrongDeviceIdentifier,
1969 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1970 >(
1971 self,
1972 bindings_ctx: &mut BC,
1973 ) -> Ipv6State<StrongDeviceId, BC> {
1974 let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
1975
1976 let slaac_stable_secret_key = slaac_stable_secret_key
1977 .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
1978
1979 Ipv6State {
1980 inner: IpStateInner::new::<CC>(bindings_ctx),
1981 icmp: icmp.build(),
1982 slaac_counters: Default::default(),
1983 slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
1984 slaac_stable_secret_key,
1985 }
1986 }
1987}
1988
1989impl Default for Ipv6StateBuilder {
1990 fn default() -> Self {
1991 #[cfg(any(test, feature = "testutils"))]
1992 let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
1993
1994 #[cfg(not(any(test, feature = "testutils")))]
1995 let slaac_stable_secret_key = None;
1996
1997 Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
1998 }
1999}
2000
2001pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
2003 pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
2005 pub icmp: Icmpv4State<BT>,
2007 pub next_packet_id: AtomicU16,
2009}
2010
2011impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2012 AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
2013{
2014 fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
2015 &self.inner
2016 }
2017}
2018
2019pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
2023 core_ctx: &mut CC,
2024) -> I::PacketId {
2025 core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
2026}
2027
2028pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
2030 pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
2032 pub icmp: Icmpv6State<BT>,
2034 pub slaac_counters: SlaacCounters,
2036 pub slaac_temp_secret_key: IidSecret,
2038 pub slaac_stable_secret_key: IidSecret,
2043}
2044
2045impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2046 AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
2047{
2048 fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
2049 &self.inner
2050 }
2051}
2052
2053impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2054 OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
2055{
2056 type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
2057 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2058 OrderedLockRef::new(&self.fragment_cache)
2059 }
2060}
2061
2062impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2063 OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
2064{
2065 type Lock = Mutex<PmtuCache<I, BT>>;
2066 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2067 OrderedLockRef::new(&self.pmtu_cache)
2068 }
2069}
2070
2071impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2072 OrderedLockAccess<RulesTable<I, D, BT>> for IpStateInner<I, D, BT>
2073{
2074 type Lock = RwLock<RulesTable<I, D, BT>>;
2075 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2076 OrderedLockRef::new(&self.rules_table)
2077 }
2078}
2079
2080impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2081 OrderedLockAccess<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>
2082 for IpStateInner<I, D, BT>
2083{
2084 type Lock =
2085 Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>;
2086 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2087 OrderedLockRef::new(&self.tables)
2088 }
2089}
2090
2091impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpRoutingBindingsTypes>
2092 OrderedLockAccess<RoutingTable<I, D>> for RoutingTableId<I, D, BT>
2093{
2094 type Lock = RwLock<RoutingTable<I, D>>;
2095 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2096 let Self(inner) = self;
2097 OrderedLockRef::new(&inner.routing_table)
2098 }
2099}
2100
2101impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2102 OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
2103{
2104 type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
2105 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2106 OrderedLockRef::new(&self.multicast_forwarding)
2107 }
2108}
2109
2110impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2111 OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
2112{
2113 type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
2114 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2115 OrderedLockRef::new(&self.raw_sockets)
2116 }
2117}
2118
2119impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2120 OrderedLockAccess<filter::State<I, WeakAddressId<I, BT>, BT>> for IpStateInner<I, D, BT>
2121{
2122 type Lock = RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>;
2123 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2124 OrderedLockRef::new(&self.filter)
2125 }
2126}
2127
2128pub trait IpStateBindingsTypes:
2130 PmtuBindingsTypes
2131 + FragmentBindingsTypes
2132 + RawIpSocketsBindingsTypes
2133 + FilterBindingsTypes
2134 + MulticastForwardingBindingsTypes
2135 + IpDeviceStateBindingsTypes
2136 + IpRoutingBindingsTypes
2137{
2138}
2139impl<BT> IpStateBindingsTypes for BT where
2140 BT: PmtuBindingsTypes
2141 + FragmentBindingsTypes
2142 + RawIpSocketsBindingsTypes
2143 + FilterBindingsTypes
2144 + MulticastForwardingBindingsTypes
2145 + IpDeviceStateBindingsTypes
2146 + IpRoutingBindingsTypes
2147{
2148}
2149
2150#[derive(Derivative)]
2152#[derivative(Debug(bound = ""))]
2153#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2154pub enum RoutingTableCookie<BT: IpRoutingBindingsTypes> {
2155 Main,
2157 BindingsId(BT::RoutingTableId),
2159}
2160
2161#[derive(Derivative)]
2163#[derivative(Debug(bound = "D: Debug"))]
2164pub struct BaseRoutingTableState<I: Ip, D, BT: IpRoutingBindingsTypes> {
2165 routing_table: RwLock<RoutingTable<I, D>>,
2166 bindings_id: RoutingTableCookie<BT>,
2167}
2168
2169impl<I: Ip, D, BT: IpRoutingBindingsTypes> BaseRoutingTableState<I, D, BT> {
2170 pub(crate) fn with_bindings_id(bindings_id: RoutingTableCookie<BT>) -> Self {
2171 Self { bindings_id, routing_table: Default::default() }
2172 }
2173}
2174
2175#[derive(Derivative)]
2177#[derivative(PartialEq(bound = ""))]
2178#[derivative(Eq(bound = ""))]
2179#[derivative(Hash(bound = ""))]
2180#[derivative(Clone(bound = ""))]
2181pub struct RoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes>(
2182 StrongRc<BaseRoutingTableState<I, D, BT>>,
2183);
2184
2185impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for RoutingTableId<I, D, BT> {
2186 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2187 let Self(rc) = self;
2188 f.debug_tuple("RoutingTableId").field(&I::NAME).field(&rc.bindings_id).finish()
2189 }
2190}
2191
2192impl<I: Ip, D, BT: IpRoutingBindingsTypes> RoutingTableId<I, D, BT> {
2193 pub(crate) fn new(rc: StrongRc<BaseRoutingTableState<I, D, BT>>) -> Self {
2195 Self(rc)
2196 }
2197
2198 #[cfg(any(test, feature = "testutils"))]
2200 pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
2201 let Self(inner) = self;
2202 &inner.routing_table
2203 }
2204
2205 pub fn downgrade(&self) -> WeakRoutingTableId<I, D, BT>
2207 where
2208 BT::RoutingTableId: Clone,
2209 {
2210 let Self(rc) = self;
2211 WeakRoutingTableId { rc: StrongRc::downgrade(rc), bindings_id: rc.bindings_id.clone() }
2212 }
2213
2214 #[cfg(test)]
2215 fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2216 let Self(rc) = self;
2217 rc.routing_table.write()
2218 }
2219
2220 pub fn bindings_id(&self) -> &RoutingTableCookie<BT> {
2222 let Self(rc) = self;
2223 &rc.bindings_id
2224 }
2225}
2226
2227#[derive(Derivative)]
2229#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2230#[derivative(PartialEq, Eq, Hash)]
2231pub struct WeakRoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes> {
2232 rc: WeakRc<BaseRoutingTableState<I, D, BT>>,
2233 #[derivative(PartialEq = "ignore")]
2234 #[derivative(Hash = "ignore")]
2235 bindings_id: RoutingTableCookie<BT>,
2236}
2237
2238impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for WeakRoutingTableId<I, D, BT> {
2239 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2240 let Self { bindings_id, .. } = self;
2241 f.debug_tuple("WeakRoutingTableId").field(&I::NAME).field(bindings_id).finish()
2242 }
2243}
2244
2245#[derive(GenericOverIp)]
2247#[generic_over_ip(I, Ip)]
2248pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2249 rules_table: RwLock<RulesTable<I, D, BT>>,
2250 main_table_id: RoutingTableId<I, D, BT>,
2252 multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2253 multicast_forwarding_counters: MulticastForwardingCounters<I>,
2254 fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2255 pmtu_cache: Mutex<PmtuCache<I, BT>>,
2256 counters: IpCounters<I>,
2257 raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2258 raw_socket_counters: RawIpSocketCounters<I>,
2259 filter: RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>,
2260 tables: Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>,
2266 igmp_counters: IgmpCounters,
2267 mld_counters: MldCounters,
2268}
2269
2270impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2271 pub fn counters(&self) -> &IpCounters<I> {
2273 &self.counters
2274 }
2275
2276 pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2278 &self.multicast_forwarding_counters
2279 }
2280
2281 pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2283 &self.raw_socket_counters
2284 }
2285
2286 pub fn main_table_id(&self) -> &RoutingTableId<I, D, BT> {
2288 &self.main_table_id
2289 }
2290
2291 #[cfg(any(test, feature = "testutils"))]
2293 pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2294 &self.pmtu_cache
2295 }
2296
2297 #[cfg(any(test, feature = "testutils"))]
2299 pub fn filter(&self) -> &RwLock<filter::State<I, WeakAddressId<I, BT>, BT>> {
2300 &self.filter
2301 }
2302
2303 pub fn igmp_counters(&self) -> &IgmpCounters {
2305 &self.igmp_counters
2306 }
2307
2308 pub fn mld_counters(&self) -> &MldCounters {
2310 &self.mld_counters
2311 }
2312}
2313
2314impl<
2315 I: IpLayerIpExt,
2316 D: StrongDeviceIdentifier,
2317 BC: TimerContext + RngContext + IpStateBindingsTypes + IpRoutingBindingsTypes,
2318> IpStateInner<I, D, BC>
2319{
2320 fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2322 let main_table: PrimaryRc<BaseRoutingTableState<I, D, BC>> =
2323 PrimaryRc::new(BaseRoutingTableState::with_bindings_id(RoutingTableCookie::Main));
2324 let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2325 Self {
2326 rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2327 tables: Mutex::new(HashMap::from_iter(core::iter::once((
2328 main_table_id.clone(),
2329 main_table,
2330 )))),
2331 main_table_id,
2332 multicast_forwarding: Default::default(),
2333 multicast_forwarding_counters: Default::default(),
2334 fragment_cache: Mutex::new(
2335 IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2336 ),
2337 pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2338 counters: Default::default(),
2339 raw_sockets: Default::default(),
2340 raw_socket_counters: Default::default(),
2341 filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2342 igmp_counters: Default::default(),
2343 mld_counters: Default::default(),
2344 }
2345 }
2346}
2347
2348#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2350#[generic_over_ip()]
2351pub enum IpLayerTimerId {
2352 ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2354 ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2356 PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2358 PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2360 FilterTimerv4(FilterTimerId<Ipv4>),
2362 FilterTimerv6(FilterTimerId<Ipv6>),
2364 MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2366 MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2368}
2369
2370impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2371 fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2372 I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2373 }
2374}
2375
2376impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2377 fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2378 I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2379 }
2380}
2381
2382impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2383 fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2384 I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2385 }
2386}
2387
2388impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2389 fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2390 I::map_ip(
2391 timer,
2392 IpLayerTimerId::MulticastForwardingTimerv4,
2393 IpLayerTimerId::MulticastForwardingTimerv6,
2394 )
2395 }
2396}
2397
2398impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2399where
2400 CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2401 + TimerHandler<BC, FragmentTimerId<Ipv6>>
2402 + TimerHandler<BC, PmtuTimerId<Ipv4>>
2403 + TimerHandler<BC, PmtuTimerId<Ipv6>>
2404 + TimerHandler<BC, FilterTimerId<Ipv4>>
2405 + TimerHandler<BC, FilterTimerId<Ipv6>>
2406 + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2407 + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2408 BC: TimerBindingsTypes,
2409{
2410 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2411 match self {
2412 IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2413 core_ctx.handle_timer(bindings_ctx, id, timer)
2414 }
2415 IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2416 core_ctx.handle_timer(bindings_ctx, id, timer)
2417 }
2418 IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2419 IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2420 IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2421 IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2422 IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2423 core_ctx.handle_timer(bindings_ctx, id, timer)
2424 }
2425 IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2426 core_ctx.handle_timer(bindings_ctx, id, timer)
2427 }
2428 }
2429 }
2430}
2431
2432pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2439 err: I::IcmpError,
2441 src_ip: SocketIpAddr<I::Addr>,
2444 dst_ip: SocketIpAddr<I::Addr>,
2447 frame_dst: Option<LocalFrameDestination>,
2449 device: &'a D,
2451 meta: ParseMetadata,
2454 marks: Marks,
2456 proto: I::Proto,
2458}
2459
2460impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2461 pub fn new<CC, B>(
2462 core_ctx: &mut CC,
2463 err: I::IcmpError,
2464 packet: &I::Packet<B>,
2465 frame_dst: Option<LocalFrameDestination>,
2466 device: &'a D,
2467 marks: Marks,
2468 ) -> Option<Self>
2469 where
2470 I: IpCountersIpExt,
2471 CC: ResourceCounterContext<D, IpCounters<I>>,
2472 B: SplitByteSlice,
2473 {
2474 let Some(src_ip) = SocketIpAddr::new(packet.src_ip()) else {
2475 core_ctx.increment_both(device, |c| &c.unspecified_source);
2476 return None;
2477 };
2478 let Some(dst_ip) = SocketIpAddr::new(packet.dst_ip()) else {
2479 return None;
2480 };
2481
2482 let is_ipv4_fragment = I::map_ip_in(
2484 packet,
2485 |p| {
2486 packet_formats::ipv4::Ipv4Header::fragment_type(p)
2487 == Ipv4FragmentType::NonInitialFragment
2488 },
2489 |_| false,
2490 );
2491 if is_ipv4_fragment {
2492 return None;
2493 }
2494
2495 let meta = packet.parse_metadata();
2496 let proto = packet.proto();
2497 Some(Self { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto })
2498 }
2499
2500 pub fn send<B, BC, CC>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, mut body: B)
2507 where
2508 B: BufferMut,
2509 CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2510 {
2511 let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto } = self;
2512 let header_len = meta.header_len();
2513
2514 body.undo_parse(meta);
2518
2519 core_ctx.send_icmp_error_message(
2520 bindings_ctx,
2521 Some(device),
2522 frame_dst,
2523 src_ip,
2524 dst_ip,
2525 body,
2526 err,
2527 header_len,
2528 proto,
2529 &marks,
2530 );
2531 }
2532}
2533
2534#[derive(PartialEq, Eq)]
2540struct EarlyDemuxResult<I: Ip, S> {
2541 socket: S,
2542 src_addr: I::Addr,
2543 src_port: Option<u16>,
2544}
2545
2546impl<I: FilterIpExt, S> EarlyDemuxResult<I, S> {
2547 fn new<P: IpPacket<I>>(socket: S, packet: &P) -> Self {
2548 let src_port =
2549 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port());
2550 Self { socket, src_addr: packet.src_addr(), src_port }
2551 }
2552
2553 fn take_socket<P: IpPacket<I>>(self, packet: &P) -> Option<S> {
2555 let src_port =
2556 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port());
2557 (self.src_addr == packet.src_addr() && self.src_port == src_port).then_some(self.socket)
2558 }
2559
2560 fn update_packet_metadata<CC, BC>(
2561 &self,
2562 core_ctx: &mut CC,
2563 packet_metadata: &mut IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2564 ) where
2565 I: IpLayerIpExt,
2566 S: SocketMetadata<CC>,
2567 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2568 CC: IpLayerIngressContext<I, BC>,
2569 {
2570 packet_metadata.socket_info = Some(self.socket.socket_info(core_ctx));
2571 packet_metadata.marks =
2572 BC::update_ingress_marks(packet_metadata.marks, &self.socket.marks(core_ctx));
2573 }
2574}
2575
2576pub(crate) fn reject_type_to_icmpv4_error(reject_type: RejectType) -> Option<Icmpv4Error> {
2577 let error = match reject_type {
2578 RejectType::NetUnreachable => Icmpv4Error::NetUnreachable,
2579 RejectType::ProtoUnreachable => Icmpv4Error::ProtocolUnreachable,
2580 RejectType::PortUnreachable => Icmpv4Error::PortUnreachable,
2581 RejectType::HostUnreachable => Icmpv4Error::HostUnreachable,
2582 RejectType::RoutePolicyFail => Icmpv4Error::NetworkProhibited,
2583 RejectType::RejectRoute => Icmpv4Error::HostProhibited,
2584 RejectType::AdminProhibited => Icmpv4Error::AdminProhibited,
2585 RejectType::TcpReset => return None,
2587 };
2588 Some(error)
2589}
2590
2591pub(crate) fn reject_type_to_icmpv6_error(reject_type: RejectType) -> Option<Icmpv6Error> {
2592 let error = match reject_type {
2593 RejectType::NetUnreachable => Icmpv6Error::NetUnreachable,
2594 RejectType::PortUnreachable => Icmpv6Error::PortUnreachable,
2595 RejectType::HostUnreachable => Icmpv6Error::AddressUnreachable,
2596 RejectType::AdminProhibited => Icmpv6Error::AdminProhibited,
2597 RejectType::RoutePolicyFail => Icmpv6Error::SourceAddressPolicyFailed,
2598 RejectType::RejectRoute => Icmpv6Error::RejectRoute,
2599 RejectType::TcpReset | RejectType::ProtoUnreachable => return None,
2601 };
2602 Some(error)
2603}
2604fn dispatch_receive_ipv4_packet<
2625 'a,
2626 'b,
2627 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2628 CC: IpLayerIngressContext<Ipv4, BC>,
2629>(
2630 core_ctx: &'a mut CC,
2631 bindings_ctx: &'a mut BC,
2632 device: &'b CC::DeviceId,
2633 frame_dst: Option<LocalFrameDestination>,
2634 mut packet: Ipv4Packet<&'a mut [u8]>,
2635 mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2636 receive_meta: ReceiveIpPacketMeta<Ipv4>,
2637) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2638 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2639
2640 let early_demux_result = receive_meta
2643 .transparent_override
2644 .is_none()
2645 .then(|| {
2646 core_ctx.early_demux(
2647 device,
2648 frame_dst,
2649 packet.src_ip(),
2650 packet.dst_ip(),
2651 packet.proto(),
2652 packet.body(),
2653 )
2654 })
2655 .flatten()
2656 .map(|socket| {
2657 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2658 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2659 early_demux_result
2660 });
2661
2662 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2663 bindings_ctx,
2664 &mut packet,
2665 device,
2666 &mut packet_metadata,
2667 );
2668
2669 let marks = packet_metadata.marks;
2670 packet_metadata.acknowledge_drop();
2671
2672 match filter_verdict {
2673 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2674 return Ok(());
2675 }
2676 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2677 return match reject_type_to_icmpv4_error(reject_type) {
2678 Some(icmp_error) => {
2679 match IcmpErrorSender::new(
2680 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2681 ) {
2682 Some(icmp_sender) => Err(icmp_sender),
2683 None => Ok(()),
2684 }
2685 }
2686 None => {
2687 debug!("Unsupported reject type: {:?}", reject_type);
2688 return Ok(());
2689 }
2690 };
2691 }
2692 filter::Verdict::Proceed(filter::Accept) => (),
2693 };
2694
2695 let Some(src_ip) = packet.src_ipv4() else {
2699 debug!(
2700 "dispatch_receive_ipv4_packet: received packet from invalid source {} after the \
2701 LOCAL_INGRESS hook; dropping",
2702 packet.src_ip()
2703 );
2704 core_ctx.increment_both(device, |c| &c.invalid_source);
2705 return Ok(());
2706 };
2707 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2708 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2709 debug!(
2710 "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2711 after the LOCAL_INGRESS hook; dropping"
2712 );
2713 return Ok(());
2714 };
2715
2716 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2717
2718 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2720
2721 let proto = packet.proto();
2722 let (prefix, options, body) = packet.parts_with_body_mut();
2723 let buffer = Buf::new(body, ..);
2724 let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2725 let mut receive_info = LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks };
2726
2727 core_ctx
2728 .dispatch_receive_ip_packet(
2729 bindings_ctx,
2730 device,
2731 src_ip,
2732 dst_ip,
2733 proto,
2734 buffer,
2735 &mut receive_info,
2736 early_demux_socket,
2737 )
2738 .or_else(|icmp_error| {
2739 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2740 Some(icmp_sender) => Err(icmp_sender),
2741 None => Ok(()),
2742 }
2743 })
2744}
2745
2746fn dispatch_receive_ipv6_packet<
2751 'a,
2752 'b,
2753 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2754 CC: IpLayerIngressContext<Ipv6, BC>,
2755>(
2756 core_ctx: &'a mut CC,
2757 bindings_ctx: &'a mut BC,
2758 device: &'b CC::DeviceId,
2759 frame_dst: Option<LocalFrameDestination>,
2760 mut packet: Ipv6Packet<&'a mut [u8]>,
2761 mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2762 meta: ReceiveIpPacketMeta<Ipv6>,
2763) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2764 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2771
2772 let early_demux_result = meta
2775 .transparent_override
2776 .is_none()
2777 .then(|| {
2778 core_ctx.early_demux(
2779 device,
2780 frame_dst,
2781 packet.src_ip(),
2782 packet.dst_ip(),
2783 packet.proto(),
2784 packet.body(),
2785 )
2786 })
2787 .flatten()
2788 .map(|socket| {
2789 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2790 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2791 early_demux_result
2792 });
2793
2794 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2795 bindings_ctx,
2796 &mut packet,
2797 device,
2798 &mut packet_metadata,
2799 );
2800
2801 let marks = packet_metadata.marks;
2802 packet_metadata.acknowledge_drop();
2803
2804 match filter_verdict {
2805 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2806 return Ok(());
2807 }
2808 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2809 return match reject_type_to_icmpv6_error(reject_type) {
2810 Some(icmp_error) => {
2811 match IcmpErrorSender::new(
2812 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2813 ) {
2814 Some(icmp_sender) => Err(icmp_sender),
2815 None => Ok(()),
2816 }
2817 }
2818 None => {
2819 debug!("Unsupported reject type: {:?}", reject_type);
2820 return Ok(());
2821 }
2822 };
2823 }
2824 filter::Verdict::Proceed(filter::Accept) => {}
2825 }
2826
2827 let Some(src_ip) = packet.src_ipv6() else {
2831 debug!(
2832 "dispatch_receive_ipv6_packet: received packet from invalid source {} after the \
2833 LOCAL_INGRESS hook; dropping",
2834 packet.src_ip()
2835 );
2836
2837 core_ctx.increment_both(device, |c| &c.invalid_source);
2838 return Ok(());
2839 };
2840 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2841 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2842 debug!(
2843 "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2844 after the LOCAL_INGRESS hook; dropping"
2845 );
2846 return Ok(());
2847 };
2848
2849 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2850
2851 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2853
2854 let proto = packet.proto();
2855 let (fixed, extension, body) = packet.parts_with_body_mut();
2856 let buffer = Buf::new(body, ..);
2857 let header_info = Ipv6HeaderInfo { fixed, extension };
2858 let mut receive_info = LocalDeliveryPacketInfo { meta, header_info, marks };
2859
2860 core_ctx
2861 .dispatch_receive_ip_packet(
2862 bindings_ctx,
2863 device,
2864 src_ip,
2865 dst_ip,
2866 proto,
2867 buffer,
2868 &mut receive_info,
2869 early_demux_socket,
2870 )
2871 .or_else(|icmp_error| {
2872 let marks = receive_info.marks;
2873 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2874 Some(icmp_sender) => Err(icmp_sender),
2875 None => Ok(()),
2876 }
2877 })
2878}
2879
2880pub(crate) struct IpPacketForwarder<
2887 'a,
2888 I: IpLayerIpExt,
2889 D,
2890 A,
2891 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2892> {
2893 inbound_device: &'a D,
2894 outbound_device: &'a D,
2895 packet_meta: IpLayerPacketMetadata<I, A, BT>,
2896 src_ip: I::RecvSrcAddr,
2897 dst_ip: SpecifiedAddr<I::Addr>,
2898 destination: IpPacketDestination<I, &'a D>,
2899 proto: I::Proto,
2900 parse_meta: ParseMetadata,
2901 frame_dst: Option<LocalFrameDestination>,
2902}
2903
2904impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
2905where
2906 I: IpLayerIpExt,
2907 BC: IpLayerBindingsContext<I, D>,
2908{
2909 fn forward_with_buffer<CC, B>(
2911 self,
2912 core_ctx: &mut CC,
2913 bindings_ctx: &mut BC,
2914 buffer: B,
2915 max_fragment_len: Option<usize>,
2916 ) where
2917 B: BufferMut,
2918 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2919 {
2920 let Self {
2921 inbound_device,
2922 outbound_device,
2923 packet_meta,
2924 src_ip,
2925 dst_ip,
2926 destination,
2927 proto,
2928 parse_meta,
2929 frame_dst,
2930 } = self;
2931
2932 let outbound_mtu = core_ctx.get_mtu(outbound_device);
2933 let marks = packet_meta.marks;
2934
2935 let send_icmp_packet_too_big = |core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B| {
2936 debug!("failed to forward {} packet: MTU exceeded", I::NAME);
2937 core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
2938 let Some(err) = I::IcmpError::mtu_exceeded(outbound_mtu) else {
2940 return;
2941 };
2942 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2945 return;
2946 };
2947
2948 let Some(dst_ip) = SocketIpAddr::new(dst_ip.get()) else {
2949 return;
2950 };
2951
2952 core_ctx.send_icmp_error_message(
2962 bindings_ctx,
2963 Some(inbound_device),
2964 frame_dst,
2965 src_ip,
2966 dst_ip,
2967 buffer,
2968 err,
2969 parse_meta.header_len(),
2970 proto,
2971 &marks,
2972 );
2973 };
2974
2975 let max_fragment_len = max_fragment_len
2981 .map(|l| Mtu::new(u32::try_from(l).expect("fragment size must fit in u32")));
2982 if I::VERSION == IpVersion::V6
2983 && max_fragment_len.is_some_and(|max_fragment_len| max_fragment_len > outbound_mtu)
2984 {
2985 packet_meta.acknowledge_drop();
2986 send_icmp_packet_too_big(core_ctx, bindings_ctx, buffer);
2987 return;
2988 }
2989 let (was_reassembled, limit_mtu) = match max_fragment_len {
2990 None => (false, Mtu::no_limit()),
2991 Some(max_fragment_len) => (true, max_fragment_len),
2992 };
2993
2994 let packet = ForwardedPacket::new(
2995 src_ip.get(),
2996 dst_ip.get(),
2997 proto,
2998 parse_meta,
2999 buffer,
3000 was_reassembled,
3001 );
3002
3003 trace!("forward_with_buffer: forwarding {} packet", I::NAME);
3004
3005 match send_ip_frame(
3006 core_ctx,
3007 bindings_ctx,
3008 outbound_device,
3009 destination,
3010 packet,
3011 packet_meta,
3012 limit_mtu,
3013 ) {
3014 Ok(()) => (),
3015 Err(IpSendFrameError { serializer, error }) => {
3016 match error {
3017 IpSendFrameErrorReason::Device(
3018 SendFrameErrorReason::SizeConstraintsViolation,
3019 ) => {
3020 send_icmp_packet_too_big(core_ctx, bindings_ctx, serializer.into_buffer());
3021 }
3022 IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
3023 | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
3024 | IpSendFrameErrorReason::Device(
3025 SendFrameErrorReason::AddressResolutionFailed,
3026 )
3027 | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
3028 }
3029 debug!("failed to forward {} packet: {error:?}", I::NAME);
3030 }
3031 }
3032 }
3033}
3034
3035pub(crate) enum ForwardingAction<
3037 'a,
3038 I: IpLayerIpExt,
3039 D,
3040 A,
3041 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
3042> {
3043 SilentlyDrop,
3045 Forward(IpPacketForwarder<'a, I, D, A, BT>),
3047 DropWithIcmpError(IcmpErrorSender<'a, I, D>),
3050}
3051
3052impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
3053where
3054 I: IpLayerIpExt,
3055 BC: IpLayerBindingsContext<I, D>,
3056{
3057 pub(crate) fn perform_action_with_buffer<CC, B>(
3059 self,
3060 core_ctx: &mut CC,
3061 bindings_ctx: &mut BC,
3062 buffer: B,
3063 max_fragment_len: Option<usize>,
3064 ) where
3065 B: BufferMut,
3066 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
3067 {
3068 match self {
3069 ForwardingAction::SilentlyDrop => {}
3070 ForwardingAction::Forward(forwarder) => {
3071 forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer, max_fragment_len)
3072 }
3073 ForwardingAction::DropWithIcmpError(icmp_sender) => {
3074 icmp_sender.send(core_ctx, bindings_ctx, buffer)
3075 }
3076 }
3077 }
3078}
3079
3080pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
3082 core_ctx: &'a mut CC,
3083 mut packet: I::Packet<&'a mut [u8]>,
3084 mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3085 minimum_ttl: Option<NonZeroU8>,
3086 inbound_device: &'b CC::DeviceId,
3087 outbound_device: &'b CC::DeviceId,
3088 destination: IpPacketDestination<I, &'b CC::DeviceId>,
3089 frame_dst: Option<LocalFrameDestination>,
3090 src_ip: I::RecvSrcAddr,
3091 dst_ip: SpecifiedAddr<I::Addr>,
3092) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
3093where
3094 I: IpLayerIpExt,
3095 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3096 CC: IpLayerForwardingContext<I, BC>,
3097{
3098 const DEFAULT_MIN_TTL: u8 = 1;
3103 let minimum_ttl = minimum_ttl.map(NonZeroU8::get).unwrap_or(DEFAULT_MIN_TTL);
3104 let ttl = packet.ttl();
3105 if ttl <= minimum_ttl {
3106 debug!(
3107 "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
3108 I::NAME
3109 );
3110 if ttl > 1 {
3122 packet_meta.acknowledge_drop();
3123 return ForwardingAction::SilentlyDrop;
3124 }
3125
3126 core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
3127
3128 let marks = packet_meta.marks;
3129 packet_meta.acknowledge_drop();
3130
3131 match IcmpErrorSender::new(
3133 core_ctx,
3134 I::IcmpError::ttl_expired(),
3135 &packet,
3136 frame_dst,
3137 inbound_device,
3138 marks,
3139 ) {
3140 Some(icmp_sender) => return ForwardingAction::DropWithIcmpError(icmp_sender),
3141 None => return ForwardingAction::SilentlyDrop,
3142 }
3143 }
3144
3145 trace!("determine_ip_packet_forwarding_action: adequate TTL");
3146
3147 let maybe_ipv6_packet_action = I::map_ip_in(
3153 &packet,
3154 |_packet| None,
3155 |packet| {
3156 Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
3157 },
3158 );
3159 match maybe_ipv6_packet_action {
3160 None => {} Some(Ipv6PacketAction::_Discard) => {
3162 core_ctx.increment_both(inbound_device, |c| {
3163 #[derive(GenericOverIp)]
3164 #[generic_over_ip(I, Ip)]
3165 struct InCounters<'a, I: IpLayerIpExt>(
3166 &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<Counter>,
3167 );
3168 I::map_ip_in::<_, _>(
3169 InCounters(&c.version_rx),
3170 |_counters| {
3171 unreachable!(
3172 "`I` must be `Ipv6` because we're handling IPv6 extension headers"
3173 )
3174 },
3175 |InCounters(counters)| &counters.extension_header_discard,
3176 )
3177 });
3178 trace!(
3179 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3180 discarding packet"
3181 );
3182 packet_meta.acknowledge_drop();
3183 return ForwardingAction::SilentlyDrop;
3184 }
3185 Some(Ipv6PacketAction::Continue) => {
3186 trace!(
3187 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3188 forwarding packet"
3189 );
3190 }
3191 Some(Ipv6PacketAction::ProcessFragment) => {
3192 unreachable!(
3193 "When forwarding packets, we should only ever look at the hop by hop \
3194 options extension header (if present)"
3195 )
3196 }
3197 };
3198
3199 match core_ctx.filter_handler().forwarding_hook(
3200 I::as_filter_packet(&mut packet),
3201 inbound_device,
3202 outbound_device,
3203 &mut packet_meta,
3204 ) {
3205 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3206 packet_meta.acknowledge_drop();
3207 trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
3208 return ForwardingAction::SilentlyDrop;
3209 }
3210 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
3211 packet_meta.acknowledge_drop();
3213 trace!(
3214 "determine_ip_packet_forwarding_action: filter verdict: Reject({:?})",
3215 reject_type
3216 );
3217 return ForwardingAction::SilentlyDrop;
3218 }
3219 filter::Verdict::Proceed(filter::Accept) => {}
3220 }
3221
3222 packet.set_ttl(ttl - 1);
3223 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
3224 ForwardingAction::Forward(IpPacketForwarder {
3225 inbound_device,
3226 outbound_device,
3227 packet_meta,
3228 src_ip,
3229 dst_ip,
3230 destination,
3231 proto,
3232 parse_meta,
3233 frame_dst,
3234 })
3235}
3236
3237pub(crate) fn send_ip_frame<I, CC, BC, S>(
3238 core_ctx: &mut CC,
3239 bindings_ctx: &mut BC,
3240 device: &CC::DeviceId,
3241 destination: IpPacketDestination<I, &CC::DeviceId>,
3242 mut body: S,
3243 mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3244 limit_mtu: Mtu,
3245) -> Result<(), IpSendFrameError<S>>
3246where
3247 I: IpLayerIpExt,
3248 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3249 CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
3250 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>,
3251{
3252 let (verdict, proof) = core_ctx.filter_handler().egress_hook(
3253 bindings_ctx,
3254 &mut body,
3255 device,
3256 &mut packet_metadata,
3257 );
3258 match verdict {
3259 filter::Verdict::Stop(filter::DropPacket) => {
3260 packet_metadata.acknowledge_drop();
3261 return Ok(());
3262 }
3263 filter::Verdict::Proceed(filter::Accept) => {}
3264 }
3265
3266 let (conntrack_connection_and_direction, tx_metadata, marks, _socket_cookie, _gso_info) =
3273 packet_metadata.into_parts();
3274 let conntrack_entry = if device.is_loopback() {
3275 conntrack_connection_and_direction
3276 .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
3277 } else {
3278 None
3279 };
3280
3281 let mut device_layer_marks = Marks::default();
3282 for mark in BC::marks_to_keep_on_egress() {
3283 *device_layer_marks.get_mut(*mark) = *marks.get(*mark);
3284 }
3285
3286 let device_ip_layer_metadata =
3287 DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks: device_layer_marks };
3288
3289 if !device.is_loopback()
3293 && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
3294 || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
3295 {
3296 core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
3297 return Err(IpSendFrameError {
3298 serializer: body,
3299 error: IpSendFrameErrorReason::IllegalLoopbackAddress,
3300 });
3301 }
3302
3303 let mtu = limit_mtu.min(core_ctx.get_mtu(device));
3305
3306 let body = body.with_size_limit(mtu.into());
3307
3308 let fits_mtu = match body.serialize_new_buf(
3309 &mut NetworkSerializationContext::default(),
3310 PacketConstraints::UNCONSTRAINED,
3311 AlwaysFailBufferAlloc,
3312 ) {
3313 Err(SerializeError::Alloc(())) => true,
3316 Err(SerializeError::SizeLimitExceeded) => false,
3318 };
3319
3320 if fits_mtu {
3321 return core_ctx
3322 .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
3323 .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
3324 serializer: serializer.into_inner(),
3325 error: error.into(),
3326 });
3327 }
3328
3329 core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
3332
3333 let mut device_ip_layer_metadata = Some(device_ip_layer_metadata);
3335 let body = body.into_inner();
3336 let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
3337 Ok(mut fragmenter) => loop {
3338 let (fragment, has_more) = match fragmenter.next() {
3339 None => break Ok(()),
3340 Some(f) => f,
3341 };
3342
3343 let device_ip_layer_metadata = if has_more {
3348 let device_ip_layer_metadata = device_ip_layer_metadata.as_ref().unwrap();
3350 DeviceIpLayerMetadata {
3351 conntrack_entry: device_ip_layer_metadata.conntrack_entry.clone(),
3352 tx_metadata: Default::default(),
3353 marks: device_ip_layer_metadata.marks,
3354 }
3355 } else {
3356 device_ip_layer_metadata.take().unwrap()
3358 };
3359
3360 match core_ctx.send_ip_frame(
3361 bindings_ctx,
3362 device,
3363 destination.clone(),
3364 device_ip_layer_metadata,
3365 fragment,
3366 proof.clone_for_fragmentation(),
3367 ) {
3368 Ok(()) => {
3369 core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
3370 }
3371 Err(ErrorAndSerializer { serializer: _, error }) => {
3372 core_ctx
3373 .increment_both(device, |c| &c.fragmentation.error_fragmented_serializer);
3374 break Err(error);
3375 }
3376 }
3377 },
3378 Err(e) => {
3379 core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
3380 Err(SendFrameErrorReason::SizeConstraintsViolation)
3381 }
3382 };
3383 result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
3384}
3385
3386struct AlwaysFailBufferAlloc;
3391
3392impl LayoutBufferAlloc<!> for AlwaysFailBufferAlloc {
3393 type Error = ();
3394 fn layout_alloc(self, _prefix: usize, _body: usize, _suffix: usize) -> Result<!, Self::Error> {
3395 Err(())
3396 }
3397}
3398
3399macro_rules! drop_packet_and_undo_parse {
3408 ($packet:expr, $buffer:expr) => {{
3409 let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
3410 $buffer.undo_parse(meta);
3411 (src_ip, dst_ip, proto, meta)
3412 }};
3413}
3414
3415enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
3418 Done,
3421
3422 NotNeeded(I::Packet<&'a mut [u8]>),
3425
3426 Reassembled { buffer: Vec<u8>, max_fragment_len: usize },
3429}
3430
3431fn process_fragment<'a, I, CC, BC>(
3437 core_ctx: &mut CC,
3438 bindings_ctx: &mut BC,
3439 device: &CC::DeviceId,
3440 packet: I::Packet<&'a mut [u8]>,
3441) -> ProcessFragmentResult<'a, I>
3442where
3443 I: IpLayerIpExt,
3444 for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3445 CC: IpLayerIngressContext<I, BC>,
3446 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3447{
3448 match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3449 FragmentProcessingState::NotNeeded(packet) => {
3451 trace!("receive_ip_packet: not fragmented");
3452 ProcessFragmentResult::NotNeeded(packet)
3453 }
3454 FragmentProcessingState::Ready { key, packet_len } => {
3456 trace!("receive_ip_packet: fragmented, ready for reassembly");
3457 let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3459
3460 let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3462 core_ctx,
3463 bindings_ctx,
3464 &key,
3465 buffer.buffer_view_mut(),
3466 ) {
3467 Ok(max_fragment_len) => ProcessFragmentResult::Reassembled {
3469 buffer: buffer.into_inner(),
3470 max_fragment_len,
3471 },
3472 Err(e) => {
3473 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3474 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3475 ProcessFragmentResult::Done
3476 }
3477 };
3478 reassemble_result
3479 }
3480 FragmentProcessingState::NeedMoreFragments => {
3483 core_ctx.increment_both(device, |c| &c.need_more_fragments);
3484 trace!("receive_ip_packet: fragmented, need more before reassembly");
3485 ProcessFragmentResult::Done
3486 }
3487 FragmentProcessingState::InvalidFragment => {
3489 core_ctx.increment_both(device, |c| &c.invalid_fragment);
3490 trace!("receive_ip_packet: fragmented, invalid");
3491 ProcessFragmentResult::Done
3492 }
3493 FragmentProcessingState::OutOfMemory => {
3494 core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3495 trace!("receive_ip_packet: fragmented, dropped because OOM");
3496 ProcessFragmentResult::Done
3497 }
3498 }
3499}
3500
3501macro_rules! try_parse_ip_packet {
3511 ($buffer:expr) => {{
3512 let p_len = $buffer.prefix_len();
3513 let s_len = $buffer.suffix_len();
3514
3515 let result = $buffer.parse_mut();
3516
3517 if let Err(err) = result {
3518 let n_p_len = $buffer.prefix_len();
3520 let n_s_len = $buffer.suffix_len();
3521
3522 if n_p_len > p_len {
3523 $buffer.grow_front(n_p_len - p_len);
3524 }
3525
3526 if n_s_len > s_len {
3527 $buffer.grow_back(n_s_len - s_len);
3528 }
3529
3530 Err(err)
3531 } else {
3532 result
3533 }
3534 }};
3535}
3536
3537macro_rules! clone_packet_for_mcast_forwarding {
3555 {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3556 let mut $new_data = $packet.to_vec();
3557 let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3558 let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3559 };
3560}
3561
3562pub fn receive_ipv4_packet<
3567 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3568 B: BufferMut,
3569 CC: IpLayerIngressContext<Ipv4, BC>,
3570>(
3571 core_ctx: &mut CC,
3572 bindings_ctx: &mut BC,
3573 device: &CC::DeviceId,
3574 frame_dst: Option<LocalFrameDestination>,
3575 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3576 parsing_context: NetworkParsingContext,
3577 gso_info: Option<GsoInfo>,
3578 buffer: B,
3579) {
3580 if !core_ctx.is_ip_device_enabled(&device) {
3581 return;
3582 }
3583
3584 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3587
3588 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3589 trace!("receive_ip_packet({device:?})");
3590
3591 let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3592 Ok(packet) => packet,
3593 Err(ParseError::Format)
3594 | Err(ParseError::Checksum)
3595 | Err(ParseError::NotSupported)
3596 | Err(ParseError::NotExpected) => {
3597 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3598 return;
3599 }
3600 };
3601
3602 if packet.src_ipv4().is_none() {
3606 debug!(
3607 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3608 packet.src_ip()
3609 );
3610 core_ctx.increment_both(device, |c| &c.invalid_source);
3611 return;
3612 };
3613 if !packet.dst_ip().is_specified() {
3614 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3615 debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3616 return;
3617 };
3618
3619 if !device.is_loopback()
3623 && (Ipv4::LOOPBACK_SUBNET.contains(&packet.src_ip())
3624 || Ipv4::LOOPBACK_SUBNET.contains(&packet.dst_ip()))
3625 {
3626 debug!(
3627 "receive_ipv4_packet: received loopback packet (src={}, dst={}) \
3628 on non-loopback interface; dropping",
3629 packet.src_ip(),
3630 packet.dst_ip(),
3631 );
3632 return;
3633 }
3634
3635 if let Some(src_ip) = SpecifiedAddr::new(packet.src_ip()) {
3638 let is_broadcast = core_ctx
3641 .address_status_for_device(src_ip, device)
3642 .into_present()
3643 .and_then(|status| status.to_broadcast_marker())
3644 .is_some();
3645
3646 if is_broadcast {
3647 debug!(
3648 "receive_ipv4_packet: received packet from broadcast source {}; dropping",
3649 packet.src_ip()
3650 );
3651 core_ctx.increment_both(device, |c| &c.invalid_source);
3652 return;
3653 }
3654 }
3655
3656 let (mut packet, max_fragment_len) =
3669 match process_fragment(core_ctx, bindings_ctx, device, packet) {
3670 ProcessFragmentResult::Done => return,
3671 ProcessFragmentResult::NotNeeded(packet) => (packet, None),
3672 ProcessFragmentResult::Reassembled { buffer: buf, max_fragment_len } => {
3673 let buf = Buf::new(buf, ..);
3674 buffer = packet::Either::B(buf);
3675
3676 match buffer.parse_mut() {
3677 Ok(packet) => (packet, Some(max_fragment_len)),
3678 Err(err) => {
3679 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3680 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3681 return;
3682 }
3683 }
3684 }
3685 };
3686
3687 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3690 core_ctx,
3691 device,
3692 device_ip_layer_metadata,
3693 gso_info,
3694 );
3695 let mut filter = core_ctx.filter_handler();
3696 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3697 filter::Verdict::Proceed(filter::Accept) => {}
3698 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
3699 packet_metadata.acknowledge_drop();
3700 return;
3701 }
3702 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
3703 addr,
3704 port,
3705 }) => {
3706 drop(filter);
3709
3710 let Some(addr) = SpecifiedAddr::new(addr) else {
3711 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3712 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3713 packet_metadata.acknowledge_drop();
3714 return;
3715 };
3716
3717 let receive_meta = ReceiveIpPacketMeta {
3718 broadcast: None,
3722 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3723 parsing_context,
3724 };
3725
3726 dispatch_receive_ipv4_packet(
3730 core_ctx,
3731 bindings_ctx,
3732 device,
3733 frame_dst,
3734 packet,
3735 packet_metadata,
3736 receive_meta,
3737 )
3738 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3739 return;
3740 }
3741 }
3742 drop(filter);
3745
3746 let Some(src_ip) = packet.src_ipv4() else {
3747 core_ctx.increment_both(device, |c| &c.invalid_source);
3748 debug!(
3749 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3750 packet.src_ip()
3751 );
3752 packet_metadata.acknowledge_drop();
3753 return;
3754 };
3755
3756 let action = receive_ipv4_packet_action(
3757 core_ctx,
3758 bindings_ctx,
3759 device,
3760 &packet,
3761 frame_dst,
3762 &packet_metadata.marks,
3763 max_fragment_len,
3764 );
3765 match action {
3766 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3767 let mut packet_metadata = Some(packet_metadata);
3774 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3775 clone_packet_for_mcast_forwarding! {
3776 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3777 };
3778 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3779 core_ctx,
3780 copy_of_packet,
3781 packet_metadata.take().unwrap_or_default(),
3782 Some(*min_ttl),
3783 device,
3784 &output_interface,
3785 IpPacketDestination::from_addr(dst_ip),
3786 frame_dst,
3787 src_ip,
3788 dst_ip,
3789 )
3790 .perform_action_with_buffer(
3791 core_ctx,
3792 bindings_ctx,
3793 copy_of_buffer,
3794 max_fragment_len,
3795 );
3796 }
3797
3798 if let Some(address_status) = address_status {
3800 let receive_meta = ReceiveIpPacketMeta {
3801 broadcast: address_status.to_broadcast_marker(),
3802 transparent_override: None,
3803 parsing_context,
3804 };
3805 dispatch_receive_ipv4_packet(
3806 core_ctx,
3807 bindings_ctx,
3808 device,
3809 frame_dst,
3810 packet,
3811 packet_metadata.take().unwrap_or_default(),
3812 receive_meta,
3813 )
3814 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3815 }
3816 }
3817 ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
3818 match internal_forwarding {
3821 InternalForwarding::Used(outbound_device) => {
3822 core_ctx.increment_both(device, |c| &c.forward);
3823 match core_ctx.filter_handler().forwarding_hook(
3824 &mut packet,
3825 device,
3826 &outbound_device,
3827 &mut packet_metadata,
3828 ) {
3829 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3830 packet_metadata.acknowledge_drop();
3831 return;
3832 }
3833 filter::Verdict::Stop(filter::DropOrReject::Reject(_reject_type)) => {
3834 packet_metadata.acknowledge_drop();
3836 return;
3837 }
3838 filter::Verdict::Proceed(filter::Accept) => {}
3839 }
3840 }
3841 InternalForwarding::NotUsed => {}
3842 }
3843
3844 let receive_meta = ReceiveIpPacketMeta {
3845 broadcast: address_status.to_broadcast_marker(),
3846 transparent_override: None,
3847 parsing_context,
3848 };
3849 dispatch_receive_ipv4_packet(
3850 core_ctx,
3851 bindings_ctx,
3852 device,
3853 frame_dst,
3854 packet,
3855 packet_metadata,
3856 receive_meta,
3857 )
3858 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3859 }
3860 ReceivePacketAction::Forward {
3861 original_dst,
3862 dst: Destination { device: dst_device, next_hop },
3863 } => {
3864 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3865 core_ctx,
3866 packet,
3867 packet_metadata,
3868 None,
3869 device,
3870 &dst_device,
3871 IpPacketDestination::from_next_hop(next_hop, original_dst),
3872 frame_dst,
3873 src_ip,
3874 original_dst,
3875 )
3876 .perform_action_with_buffer(
3877 core_ctx,
3878 bindings_ctx,
3879 buffer,
3880 max_fragment_len,
3881 );
3882 }
3883 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3884 debug!("received IPv4 packet with no known route to destination {}", dst_ip);
3885
3886 let marks = packet_metadata.marks;
3887 packet_metadata.acknowledge_drop();
3888
3889 if let Some(sender) = IcmpErrorSender::new(
3890 core_ctx,
3891 Icmpv4Error::NetUnreachable,
3892 &packet,
3893 frame_dst,
3894 device,
3895 marks,
3896 ) {
3897 sender.send(core_ctx, bindings_ctx, buffer);
3898 }
3899 }
3900 ReceivePacketAction::Drop { reason } => {
3901 let src_ip = packet.src_ip();
3902 let dst_ip = packet.dst_ip();
3903 packet_metadata.acknowledge_drop();
3904 core_ctx.increment_both(device, |c| &c.dropped);
3905 debug!(
3906 "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
3907 {device:?}: {reason:?}",
3908 );
3909 }
3910 }
3911}
3912
3913fn handle_ipv6_parse_error<BC, B, CC>(
3914 core_ctx: &mut CC,
3915 bindings_ctx: &mut BC,
3916 device: &CC::DeviceId,
3917 frame_dst: Option<LocalFrameDestination>,
3918 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3919 mut buffer: B,
3920 error: Ipv6ParseError,
3921) where
3922 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3923 B: BufferMut,
3924 CC: IpLayerIngressContext<Ipv6, BC>,
3925{
3926 let Ipv6ParseError::ParameterProblem { src_ip, dst_ip, code, pointer, must_send_icmp, action } =
3932 error
3933 else {
3934 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3935 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
3936 return;
3937 };
3938 if !must_send_icmp || !action.should_send_icmp(&dst_ip) {
3939 return;
3940 }
3941 core_ctx.increment_both(device, |c| &c.parameter_problem);
3942 let dst_ip = match SocketIpAddr::new(dst_ip) {
3943 Some(ip) => ip,
3944 None => {
3945 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3946 debug!("receive_ipv6_packet: Dropping packet with unspecified destination IP");
3947 return;
3948 }
3949 };
3950
3951 let src_ip = match Ipv6SourceAddr::new(src_ip) {
3952 None => {
3953 core_ctx.increment_both(device, |c| &c.invalid_source);
3954 return;
3955 }
3956 Some(Ipv6SourceAddr::Unspecified) => {
3957 core_ctx.increment_both(device, |c| &c.unspecified_source);
3958 return;
3959 }
3960 Some(Ipv6SourceAddr::Unicast(src_ip)) => {
3961 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
3962 }
3963 };
3964
3965 let raw_packet: Ipv6PacketRaw<_> = match try_parse_ip_packet!(buffer) {
3968 Ok(packet) => packet,
3969 Err(error) => {
3970 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3971 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
3972 return;
3973 }
3974 };
3975 let proto = match raw_packet.proto() {
3976 Ok(proto) => proto,
3977 Err(error) => {
3978 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3979 debug!("receive_ipv6_packet: Failed to get protocol from IPv6 packet: {:?}", error);
3980 return;
3981 }
3982 };
3983 let parse_metadata = raw_packet.parse_metadata();
3984 let header_len = parse_metadata.header_len();
3985 buffer.undo_parse(parse_metadata);
3986
3987 let err = Icmpv6Error::ParameterProblem {
3988 code,
3989 pointer,
3990 allow_dst_multicast: action.should_send_icmp_to_multicast(),
3991 };
3992
3993 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3994 core_ctx,
3995 bindings_ctx,
3996 Some(device),
3997 frame_dst,
3998 src_ip,
3999 dst_ip,
4000 buffer,
4001 err,
4002 header_len,
4003 proto,
4004 &device_ip_layer_metadata.marks,
4005 );
4006}
4007
4008pub fn receive_ipv6_packet<
4013 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4014 B: BufferMut,
4015 CC: IpLayerIngressContext<Ipv6, BC>,
4016>(
4017 core_ctx: &mut CC,
4018 bindings_ctx: &mut BC,
4019 device: &CC::DeviceId,
4020 frame_dst: Option<LocalFrameDestination>,
4021 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
4022 parsing_context: NetworkParsingContext,
4023 gso_info: Option<GsoInfo>,
4024 buffer: B,
4025) {
4026 if !core_ctx.is_ip_device_enabled(&device) {
4027 return;
4028 }
4029
4030 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
4033
4034 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
4035 trace!("receive_ipv6_packet({:?})", device);
4036
4037 let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
4038 Ok(packet) => packet,
4039 Err(error) => {
4040 handle_ipv6_parse_error(
4041 core_ctx,
4042 bindings_ctx,
4043 device,
4044 frame_dst,
4045 device_ip_layer_metadata,
4046 buffer,
4047 error,
4048 );
4049 return;
4050 }
4051 };
4052
4053 trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
4054
4055 if packet.src_ipv6().is_none() {
4061 debug!(
4062 "receive_ipv6_packet: received packet from invalid source {}; dropping",
4063 packet.src_ip()
4064 );
4065 core_ctx.increment_both(device, |c| &c.invalid_source);
4066 return;
4067 };
4068 if !packet.dst_ip().is_specified() {
4069 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4070 debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
4071 return;
4072 };
4073
4074 if !device.is_loopback()
4082 && (Ipv6::LOOPBACK_SUBNET.contains(&packet.src_ip())
4083 || Ipv6::LOOPBACK_SUBNET.contains(&packet.dst_ip()))
4084 {
4085 debug!(
4086 "receive_ipv6_packet: received loopback packet (src={}, dst={}) \
4087 on non-loopback interface; dropping",
4088 packet.src_ip(),
4089 packet.dst_ip(),
4090 );
4091 return;
4092 }
4093
4094 let (mut packet, delivery_extension_header_action, max_fragment_len) =
4105 match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
4106 Ipv6PacketAction::_Discard => {
4107 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4108 trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
4109 return;
4110 }
4111 Ipv6PacketAction::Continue => {
4112 trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
4113 (packet, Some(Ipv6PacketAction::Continue), None)
4114 }
4115 Ipv6PacketAction::ProcessFragment => {
4116 trace!(
4117 "receive_ipv6_packet: handled IPv6 extension headers: handling \
4118 fragmented packet"
4119 );
4120
4121 match process_fragment(core_ctx, bindings_ctx, device, packet) {
4133 ProcessFragmentResult::Done => return,
4134 ProcessFragmentResult::NotNeeded(packet) => {
4135 (packet, Some(Ipv6PacketAction::Continue), None)
4150 }
4151 ProcessFragmentResult::Reassembled { buffer: buf, max_fragment_len } => {
4152 let buf = Buf::new(buf, ..);
4153 buffer = packet::Either::B(buf);
4154
4155 match buffer.parse_mut() {
4156 Ok(packet) => (packet, None, Some(max_fragment_len)),
4157 Err(err) => {
4158 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4159 debug!(
4160 "receive_ip_packet: fragmented, failed to reassemble: {:?}",
4161 err
4162 );
4163 return;
4164 }
4165 }
4166 }
4167 }
4168 }
4169 };
4170
4171 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
4172 core_ctx,
4173 device,
4174 device_ip_layer_metadata,
4175 gso_info,
4176 );
4177 let mut filter = core_ctx.filter_handler();
4178
4179 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
4180 filter::Verdict::Proceed(filter::Accept) => {}
4181 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
4182 packet_metadata.acknowledge_drop();
4183 return;
4184 }
4185 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
4186 addr,
4187 port,
4188 }) => {
4189 drop(filter);
4192
4193 let Some(addr) = SpecifiedAddr::new(addr) else {
4194 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4195 debug!("cannot perform transparent delivery to unspecified destination; dropping");
4196 packet_metadata.acknowledge_drop();
4197 return;
4198 };
4199
4200 let receive_meta = ReceiveIpPacketMeta {
4201 broadcast: None,
4202 transparent_override: Some(TransparentLocalDelivery { addr, port }),
4203 parsing_context,
4204 };
4205
4206 dispatch_receive_ipv6_packet(
4210 core_ctx,
4211 bindings_ctx,
4212 device,
4213 frame_dst,
4214 packet,
4215 packet_metadata,
4216 receive_meta,
4217 )
4218 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4219 return;
4220 }
4221 }
4222 drop(filter);
4225
4226 let Some(src_ip) = packet.src_ipv6() else {
4227 debug!(
4228 "receive_ipv6_packet: received packet from invalid source {}; dropping",
4229 packet.src_ip()
4230 );
4231 core_ctx.increment_both(device, |c| &c.invalid_source);
4232 packet_metadata.acknowledge_drop();
4233 return;
4234 };
4235
4236 match receive_ipv6_packet_action(
4237 core_ctx,
4238 bindings_ctx,
4239 device,
4240 &packet,
4241 frame_dst,
4242 &packet_metadata.marks,
4243 max_fragment_len,
4244 ) {
4245 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
4246 let mut packet_metadata = Some(packet_metadata);
4253 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
4254 clone_packet_for_mcast_forwarding! {
4255 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
4256 };
4257 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4258 core_ctx,
4259 copy_of_packet,
4260 packet_metadata.take().unwrap_or_default(),
4261 Some(*min_ttl),
4262 device,
4263 &output_interface,
4264 IpPacketDestination::from_addr(dst_ip),
4265 frame_dst,
4266 src_ip,
4267 dst_ip,
4268 )
4269 .perform_action_with_buffer(
4270 core_ctx,
4271 bindings_ctx,
4272 copy_of_buffer,
4273 max_fragment_len,
4274 );
4275 }
4276
4277 if let Some(_) = address_status {
4279 let receive_meta = ReceiveIpPacketMeta {
4280 broadcast: None,
4281 transparent_override: None,
4282 parsing_context,
4283 };
4284
4285 dispatch_receive_ipv6_packet(
4286 core_ctx,
4287 bindings_ctx,
4288 device,
4289 frame_dst,
4290 packet,
4291 packet_metadata.take().unwrap_or_default(),
4292 receive_meta,
4293 )
4294 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4295 }
4296 }
4297 ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
4298 trace!("receive_ipv6_packet: delivering locally");
4299
4300 let action = if let Some(action) = delivery_extension_header_action {
4301 action
4302 } else {
4303 ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
4304 };
4305 match action {
4306 Ipv6PacketAction::_Discard => {
4307 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4308 trace!(
4309 "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
4310 );
4311 packet_metadata.acknowledge_drop();
4312 }
4313 Ipv6PacketAction::Continue => {
4314 trace!(
4315 "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
4316 );
4317
4318 match internal_forwarding {
4321 InternalForwarding::Used(outbound_device) => {
4322 core_ctx.increment_both(device, |c| &c.forward);
4323 match core_ctx.filter_handler().forwarding_hook(
4324 &mut packet,
4325 device,
4326 &outbound_device,
4327 &mut packet_metadata,
4328 ) {
4329 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
4330 packet_metadata.acknowledge_drop();
4331 return;
4332 }
4333 filter::Verdict::Stop(filter::DropOrReject::Reject(
4334 _reject_type,
4335 )) => {
4336 packet_metadata.acknowledge_drop();
4338 return;
4339 }
4340 filter::Verdict::Proceed(filter::Accept) => {}
4341 }
4342 }
4343 InternalForwarding::NotUsed => {}
4344 }
4345
4346 let meta = ReceiveIpPacketMeta {
4347 broadcast: None,
4348 transparent_override: None,
4349 parsing_context,
4350 };
4351 dispatch_receive_ipv6_packet(
4352 core_ctx,
4353 bindings_ctx,
4354 device,
4355 frame_dst,
4356 packet,
4357 packet_metadata,
4358 meta,
4359 )
4360 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4361 }
4362 Ipv6PacketAction::ProcessFragment => {
4363 debug!("receive_ipv6_packet: found fragment header after reassembly; dropping");
4364 packet_metadata.acknowledge_drop();
4365 }
4366 }
4367 }
4368 ReceivePacketAction::Forward {
4369 original_dst,
4370 dst: Destination { device: dst_device, next_hop },
4371 } => {
4372 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4373 core_ctx,
4374 packet,
4375 packet_metadata,
4376 None,
4377 device,
4378 &dst_device,
4379 IpPacketDestination::from_next_hop(next_hop, original_dst),
4380 frame_dst,
4381 src_ip,
4382 original_dst,
4383 )
4384 .perform_action_with_buffer(
4385 core_ctx,
4386 bindings_ctx,
4387 buffer,
4388 max_fragment_len,
4389 );
4390 }
4391 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
4392 let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
4393 drop_packet_and_undo_parse!(packet, buffer);
4394 debug!("received IPv6 packet with no known route to destination {}", dst_ip);
4395 let marks = packet_metadata.marks;
4396 packet_metadata.acknowledge_drop();
4397
4398 let src_ip = match src_ip {
4399 Ipv6SourceAddr::Unspecified => {
4400 core_ctx.increment_both(device, |c| &c.unspecified_source);
4401 return;
4402 }
4403 Ipv6SourceAddr::Unicast(src_ip) => {
4404 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
4405 }
4406 };
4407
4408 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
4409 core_ctx,
4410 bindings_ctx,
4411 Some(device),
4412 frame_dst,
4413 src_ip,
4414 SocketIpAddr::new_from_witness(dst_ip),
4415 buffer,
4416 Icmpv6Error::NetUnreachable,
4417 meta.header_len(),
4418 proto,
4419 &marks,
4420 );
4421 }
4422 ReceivePacketAction::Drop { reason } => {
4423 core_ctx.increment_both(device, |c| &c.dropped);
4424 let src_ip = packet.src_ip();
4425 let dst_ip = packet.dst_ip();
4426 packet_metadata.acknowledge_drop();
4427 debug!(
4428 "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
4429 {device:?}: {reason:?}",
4430 );
4431 }
4432 }
4433}
4434
4435#[derive(Debug, PartialEq)]
4437pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
4438 Deliver {
4440 address_status: I::AddressStatus,
4442 internal_forwarding: InternalForwarding<DeviceId>,
4445 },
4446
4447 Forward {
4449 original_dst: SpecifiedAddr<I::Addr>,
4451 dst: Destination<I::Addr, DeviceId>,
4453 },
4454
4455 MulticastForward {
4463 targets: MulticastRouteTargets<DeviceId>,
4465 address_status: Option<I::AddressStatus>,
4468 dst_ip: SpecifiedAddr<I::Addr>,
4470 },
4471
4472 SendNoRouteToDest {
4478 dst: NonMappedAddr<SpecifiedAddr<I::Addr>>,
4480 },
4481
4482 #[allow(missing_docs)]
4486 Drop { reason: DropReason },
4487}
4488
4489fn choose_highest_priority_address_status<I: IpLayerIpExt>(
4492 address_statuses: impl Iterator<Item = I::AddressStatus>,
4493) -> Option<I::AddressStatus> {
4494 address_statuses.max_by_key(|status| {
4495 #[derive(GenericOverIp)]
4496 #[generic_over_ip(I, Ip)]
4497 struct Wrap<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
4498 I::map_ip_in(
4499 Wrap(status),
4500 |Wrap(v4_status)| match v4_status {
4501 Ipv4PresentAddressStatus::UnicastTentative => 0,
4502 _ => 1,
4503 },
4504 |Wrap(v6_status)| match v6_status {
4505 Ipv6PresentAddressStatus::UnicastTentative => 0,
4506 _ => 1,
4507 },
4508 )
4509 })
4510}
4511
4512#[derive(Debug, PartialEq)]
4514pub enum DropReason {
4515 Tentative,
4517 UnspecifiedDestination,
4519 InvalidDestination,
4521 ForwardUnspecifiedSource,
4523 ForwardLinkLocal,
4525 ForwardingDisabledInboundIface,
4528 MulticastNoInterest,
4534}
4535
4536pub fn receive_ipv4_packet_action<BC, CC, B>(
4538 core_ctx: &mut CC,
4539 bindings_ctx: &mut BC,
4540 device: &CC::DeviceId,
4541 packet: &Ipv4Packet<B>,
4542 frame_dst: Option<LocalFrameDestination>,
4543 marks: &Marks,
4544 max_fragment_len: Option<usize>,
4545) -> ReceivePacketAction<Ipv4, CC::DeviceId>
4546where
4547 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
4548 CC: IpLayerContext<Ipv4, BC>,
4549 B: SplitByteSlice,
4550{
4551 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4552 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4553 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4554 };
4555
4556 let highest_priority = if device.is_loopback() {
4569 core_ctx.with_address_statuses(dst_ip, |it| {
4570 let it = it.map(|(_device, status)| status);
4571 choose_highest_priority_address_status::<Ipv4>(it)
4572 })
4573 } else {
4574 core_ctx.address_status_for_device(dst_ip, device).into_present()
4575 };
4576 match highest_priority {
4577 Some(
4578 address_status @ (Ipv4PresentAddressStatus::UnicastAssigned
4579 | Ipv4PresentAddressStatus::LoopbackSubnet),
4580 ) => {
4581 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4582 ReceivePacketAction::Deliver {
4583 address_status,
4584 internal_forwarding: InternalForwarding::NotUsed,
4585 }
4586 }
4587 Some(Ipv4PresentAddressStatus::UnicastTentative) => {
4588 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4594 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4595 }
4596
4597 Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4598 receive_ip_multicast_packet_action(
4599 core_ctx,
4600 bindings_ctx,
4601 device,
4602 packet,
4603 Some(address_status),
4604 dst_ip,
4605 frame_dst,
4606 max_fragment_len,
4607 )
4608 }
4609 Some(
4610 address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4611 | Ipv4PresentAddressStatus::SubnetBroadcast),
4612 ) => {
4613 core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
4614 ReceivePacketAction::Deliver {
4615 address_status,
4616 internal_forwarding: InternalForwarding::NotUsed,
4617 }
4618 }
4619 None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4620 core_ctx,
4621 bindings_ctx,
4622 dst_ip,
4623 device,
4624 packet,
4625 frame_dst,
4626 marks,
4627 max_fragment_len,
4628 ),
4629 }
4630}
4631
4632pub fn receive_ipv6_packet_action<BC, CC, B>(
4634 core_ctx: &mut CC,
4635 bindings_ctx: &mut BC,
4636 device: &CC::DeviceId,
4637 packet: &Ipv6Packet<B>,
4638 frame_dst: Option<LocalFrameDestination>,
4639 marks: &Marks,
4640 max_fragment_len: Option<usize>,
4641) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4642where
4643 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4644 CC: IpLayerContext<Ipv6, BC>,
4645 B: SplitByteSlice,
4646{
4647 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4648 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4649 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4650 };
4651
4652 let highest_priority = if device.is_loopback() {
4665 core_ctx.with_address_statuses(dst_ip, |it| {
4666 let it = it.map(|(_device, status)| status);
4667 choose_highest_priority_address_status::<Ipv6>(it)
4668 })
4669 } else {
4670 core_ctx.address_status_for_device(dst_ip, device).into_present()
4671 };
4672 match highest_priority {
4673 Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
4674 receive_ip_multicast_packet_action(
4675 core_ctx,
4676 bindings_ctx,
4677 device,
4678 packet,
4679 Some(address_status),
4680 dst_ip,
4681 frame_dst,
4682 max_fragment_len,
4683 )
4684 }
4685 Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
4686 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4687 ReceivePacketAction::Deliver {
4688 address_status,
4689 internal_forwarding: InternalForwarding::NotUsed,
4690 }
4691 }
4692 Some(Ipv6PresentAddressStatus::UnicastTentative) => {
4693 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4724 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4725 }
4726 None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
4727 core_ctx,
4728 bindings_ctx,
4729 dst_ip,
4730 device,
4731 packet,
4732 frame_dst,
4733 marks,
4734 max_fragment_len,
4735 ),
4736 }
4737}
4738
4739fn receive_ip_multicast_packet_action<
4742 I: IpLayerIpExt,
4743 B: SplitByteSlice,
4744 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4745 CC: IpLayerContext<I, BC>,
4746>(
4747 core_ctx: &mut CC,
4748 bindings_ctx: &mut BC,
4749 device: &CC::DeviceId,
4750 packet: &I::Packet<B>,
4751 address_status: Option<I::AddressStatus>,
4752 dst_ip: SpecifiedAddr<I::Addr>,
4753 frame_dst: Option<LocalFrameDestination>,
4754 max_fragment_len: Option<usize>,
4755) -> ReceivePacketAction<I, CC::DeviceId> {
4756 let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
4757 core_ctx,
4758 bindings_ctx,
4759 packet,
4760 device,
4761 frame_dst,
4762 max_fragment_len,
4763 );
4764 match (targets, address_status) {
4765 (Some(targets), address_status) => {
4766 if address_status.is_some() {
4767 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4768 }
4769 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
4770 }
4771 (None, Some(address_status)) => {
4772 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4775 ReceivePacketAction::Deliver {
4776 address_status,
4777 internal_forwarding: InternalForwarding::NotUsed,
4778 }
4779 }
4780 (None, None) => {
4781 core_ctx.increment_both(device, |c| &c.multicast_no_interest);
4790 ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
4791 }
4792 }
4793}
4794
4795fn receive_ip_packet_action_common<
4798 I: IpLayerIpExt,
4799 B: SplitByteSlice,
4800 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4801 CC: IpLayerContext<I, BC>,
4802>(
4803 core_ctx: &mut CC,
4804 bindings_ctx: &mut BC,
4805 dst_ip: SpecifiedAddr<I::Addr>,
4806 device_id: &CC::DeviceId,
4807 packet: &I::Packet<B>,
4808 frame_dst: Option<LocalFrameDestination>,
4809 marks: &Marks,
4810 max_fragment_len: Option<usize>,
4811) -> ReceivePacketAction<I, CC::DeviceId> {
4812 if dst_ip.is_multicast() {
4813 return receive_ip_multicast_packet_action(
4814 core_ctx,
4815 bindings_ctx,
4816 device_id,
4817 packet,
4818 None,
4819 dst_ip,
4820 frame_dst,
4821 max_fragment_len,
4822 );
4823 }
4824
4825 let Some(dst_ip) = NonMappedAddr::new(dst_ip) else {
4827 return ReceivePacketAction::Drop { reason: DropReason::InvalidDestination };
4828 };
4829
4830 if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
4832 core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
4845 return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
4846 }
4847 let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
4854 return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
4855 };
4856
4857 if let Some(dst_ip) = NonMulticastAddr::new(dst_ip) {
4864 if let Some((outbound_device, address_status)) =
4865 get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
4866 {
4867 return ReceivePacketAction::Deliver {
4868 address_status,
4869 internal_forwarding: InternalForwarding::Used(outbound_device),
4870 };
4871 }
4872 }
4873
4874 if I::map_ip_in(
4889 &packet,
4890 |_| false,
4891 |packet| packet.src_ip().is_link_local() || packet.dst_ip().is_link_local(),
4892 ) {
4893 return ReceivePacketAction::Drop { reason: DropReason::ForwardLinkLocal };
4894 }
4895
4896 match lookup_route_table(
4897 core_ctx,
4898 dst_ip.get(),
4899 RuleInput {
4900 packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
4901 marks,
4902 },
4903 ) {
4904 Some(dst) => {
4905 core_ctx.increment_both(device_id, |c| &c.forward);
4906 ReceivePacketAction::Forward { original_dst: *dst_ip, dst }
4907 }
4908 None => {
4909 core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
4910 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
4911 }
4912 }
4913}
4914
4915fn lookup_route_table<
4917 I: IpLayerIpExt,
4918 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4919 CC: IpStateContext<I, BC>,
4920>(
4921 core_ctx: &mut CC,
4922 dst_ip: I::Addr,
4923 rule_input: RuleInput<'_, I, CC::DeviceId>,
4924) -> Option<Destination<I::Addr, CC::DeviceId>> {
4925 let bound_device = match rule_input.packet_origin {
4926 PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
4927 PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
4928 };
4929 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
4930 match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
4931 match table.lookup(core_ctx, bound_device, dst_ip) {
4932 Some(dst) => ControlFlow::Break(Some(dst)),
4933 None => ControlFlow::Continue(()),
4934 }
4935 }) {
4936 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
4937 inner: dst,
4938 observed_source_address_matcher: _,
4939 })) => dst,
4940 ControlFlow::Break(RuleAction::Unreachable) => None,
4941 ControlFlow::Continue(RuleWalkInfo {
4942 inner: (),
4943 observed_source_address_matcher: _,
4944 }) => None,
4945 }
4946 })
4947}
4948
4949#[derive(Debug, Derivative, Clone)]
4951#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
4952pub enum IpPacketDestination<I: BroadcastIpExt, D> {
4953 Broadcast(I::BroadcastMarker),
4955
4956 Multicast(MulticastAddr<I::Addr>),
4958
4959 Neighbor(SpecifiedAddr<I::Addr>),
4962
4963 Loopback(D),
4966}
4967
4968impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
4969 pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
4971 match MulticastAddr::new(addr.into_addr()) {
4972 Some(mc_addr) => Self::Multicast(mc_addr),
4973 None => Self::Neighbor(addr),
4974 }
4975 }
4976
4977 pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
4979 match next_hop {
4980 NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
4981 NextHop::Gateway(gateway) => Self::Neighbor(gateway),
4982 NextHop::Broadcast(marker) => Self::Broadcast(marker),
4983 }
4984 }
4985}
4986
4987#[derive(Debug, Clone)]
4989pub struct SendIpPacketMeta<I: IpExt, D, Src> {
4990 pub device: D,
4992
4993 pub src_ip: Src,
4995
4996 pub dst_ip: SpecifiedAddr<I::Addr>,
4998
4999 pub destination: IpPacketDestination<I, D>,
5001
5002 pub proto: I::Proto,
5004
5005 pub ttl: Option<NonZeroU8>,
5009
5010 pub mtu: Mtu,
5015
5016 pub dscp_and_ecn: DscpAndEcn,
5018}
5019
5020impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5021 for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
5022{
5023 fn from(
5024 SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
5025 I,
5026 D,
5027 SpecifiedAddr<I::Addr>,
5028 >,
5029 ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
5030 SendIpPacketMeta {
5031 device,
5032 src_ip: Some(src_ip),
5033 dst_ip,
5034 destination,
5035 proto,
5036 ttl,
5037 mtu,
5038 dscp_and_ecn,
5039 }
5040 }
5041}
5042
5043pub trait IpLayerHandler<I: IpExt + FragmentationIpExt + FilterIpExt, BC>:
5049 DeviceIdContext<AnyDevice>
5050{
5051 fn send_ip_packet_from_device<S>(
5054 &mut self,
5055 bindings_ctx: &mut BC,
5056 meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
5057 body: S,
5058 ) -> Result<(), IpSendFrameError<S>>
5059 where
5060 S: TransportPacketSerializer<I>,
5061 S::Buffer: BufferMut;
5062
5063 fn send_ip_frame<S>(
5070 &mut self,
5071 bindings_ctx: &mut BC,
5072 device: &Self::DeviceId,
5073 destination: IpPacketDestination<I, &Self::DeviceId>,
5074 body: S,
5075 ) -> Result<(), IpSendFrameError<S>>
5076 where
5077 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>;
5078}
5079
5080impl<
5081 I: IpLayerIpExt,
5082 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
5083 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
5084> IpLayerHandler<I, BC> for CC
5085{
5086 fn send_ip_packet_from_device<S>(
5087 &mut self,
5088 bindings_ctx: &mut BC,
5089 meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
5090 body: S,
5091 ) -> Result<(), IpSendFrameError<S>>
5092 where
5093 S: TransportPacketSerializer<I>,
5094 S::Buffer: BufferMut,
5095 {
5096 send_ip_packet_from_device(self, bindings_ctx, meta, body, IpLayerPacketMetadata::default())
5097 }
5098
5099 fn send_ip_frame<S>(
5100 &mut self,
5101 bindings_ctx: &mut BC,
5102 device: &Self::DeviceId,
5103 destination: IpPacketDestination<I, &Self::DeviceId>,
5104 body: S,
5105 ) -> Result<(), IpSendFrameError<S>>
5106 where
5107 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>,
5108 {
5109 send_ip_frame(
5110 self,
5111 bindings_ctx,
5112 device,
5113 destination,
5114 body,
5115 IpLayerPacketMetadata::default(),
5116 Mtu::no_limit(),
5117 )
5118 }
5119}
5120
5121pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
5128 core_ctx: &mut CC,
5129 bindings_ctx: &mut BC,
5130 meta: SendIpPacketMeta<
5131 I,
5132 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
5133 Option<SpecifiedAddr<I::Addr>>,
5134 >,
5135 body: S,
5136 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
5137) -> Result<(), IpSendFrameError<S>>
5138where
5139 I: IpLayerIpExt,
5140 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
5141 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
5142 S: TransportPacketSerializer<I>,
5143 S::Buffer: BufferMut,
5144{
5145 let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
5146 meta;
5147 core_ctx.increment_both(device, |c| &c.send_ip_packet);
5148 let next_packet_id = gen_ip_packet_id(core_ctx);
5149 let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
5150 let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
5151 let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
5152
5153 #[derive(GenericOverIp)]
5154 #[generic_over_ip(I, Ip)]
5155 struct Wrap<'a, I: IpLayerIpExt> {
5156 builder: &'a mut I::PacketBuilder<NetworkSerializationContext>,
5157 next_packet_id: I::PacketId,
5158 }
5159
5160 I::map_ip::<_, ()>(
5161 Wrap { builder: &mut builder, next_packet_id },
5162 |Wrap { builder, next_packet_id }| {
5163 builder.id(next_packet_id);
5164 },
5165 |Wrap { builder: _, next_packet_id: () }| {
5166 },
5168 );
5169
5170 builder.set_dscp_and_ecn(dscp_and_ecn);
5171
5172 let ip_frame = builder.wrap_body(body);
5173 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
5174 .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
5175}
5176
5177pub trait FilterHandlerProvider<I: FilterIpExt, BT: FilterBindingsTypes>:
5179 IpDeviceAddressIdContext<I, DeviceId: netstack3_base::InterfaceProperties<BT::DeviceClass>>
5180{
5181 type Handler<'a>: filter::FilterHandler<I, BT, DeviceId = Self::DeviceId, WeakAddressId = Self::WeakAddressId>
5183 where
5184 Self: 'a;
5185
5186 fn filter_handler(&mut self) -> Self::Handler<'_>;
5188}
5189
5190#[cfg(any(test, feature = "testutils"))]
5191pub(crate) mod testutil {
5192 use super::*;
5193
5194 use netstack3_base::testutil::{FakeBindingsCtx, FakeCoreCtx, FakeStrongDeviceId};
5195 use netstack3_base::{
5196 AssignedAddrIpExt, NetworkSerializer, SendFrameContext, SendFrameError, SendableFrameMeta,
5197 };
5198
5199 #[derive(Debug, GenericOverIp)]
5201 #[generic_over_ip()]
5202 #[allow(missing_docs)]
5203 pub enum DualStackSendIpPacketMeta<D> {
5204 V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
5205 V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
5206 }
5207
5208 impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5209 for DualStackSendIpPacketMeta<D>
5210 {
5211 fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
5212 #[derive(GenericOverIp)]
5213 #[generic_over_ip(I, Ip)]
5214 struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
5215 use DualStackSendIpPacketMeta::*;
5216 I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
5217 }
5218 }
5219
5220 impl<I: IpExt, S, DeviceId, BC>
5221 SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
5222 for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
5223 {
5224 fn send_meta<SS>(
5225 self,
5226 core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
5227 bindings_ctx: &mut BC,
5228 frame: SS,
5229 ) -> Result<(), SendFrameError<SS>>
5230 where
5231 SS: NetworkSerializer,
5232 SS::Buffer: BufferMut,
5233 {
5234 SendFrameContext::send_frame(
5235 &mut core_ctx.frames,
5236 bindings_ctx,
5237 DualStackSendIpPacketMeta::from(self),
5238 frame,
5239 )
5240 }
5241 }
5242
5243 #[derive(Debug)]
5245 pub struct WrongIpVersion;
5246
5247 impl<D> DualStackSendIpPacketMeta<D> {
5248 pub fn try_as<I: IpExt>(
5251 &self,
5252 ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
5253 #[derive(GenericOverIp)]
5254 #[generic_over_ip(I, Ip)]
5255 struct Wrap<'a, I: IpExt, D>(
5256 Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
5257 );
5258 use DualStackSendIpPacketMeta::*;
5259 let Wrap(dual_stack) = I::map_ip(
5260 self,
5261 |value| {
5262 Wrap(match value {
5263 V4(meta) => Some(meta),
5264 V6(_) => None,
5265 })
5266 },
5267 |value| {
5268 Wrap(match value {
5269 V4(_) => None,
5270 V6(meta) => Some(meta),
5271 })
5272 },
5273 );
5274 dual_stack.ok_or(WrongIpVersion)
5275 }
5276 }
5277
5278 impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
5279 where
5280 I: AssignedAddrIpExt + FilterIpExt,
5281 BC: FilterBindingsContext<DeviceId>,
5282 DeviceId: FakeStrongDeviceId + netstack3_base::InterfaceProperties<BC::DeviceClass>,
5283 {
5284 type Handler<'a>
5285 = filter::testutil::NoopImpl<DeviceId>
5286 where
5287 Self: 'a;
5288
5289 fn filter_handler(&mut self) -> Self::Handler<'_> {
5290 filter::testutil::NoopImpl::default()
5291 }
5292 }
5293
5294 impl<TimerId, Event: Debug, State, FrameMeta> MarksBindingsContext
5295 for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
5296 {
5297 fn marks_to_keep_on_egress() -> &'static [MarkDomain] {
5298 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark1];
5299 &MARKS
5300 }
5301
5302 fn marks_to_set_on_ingress() -> &'static [MarkDomain] {
5303 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark2];
5304 &MARKS
5305 }
5306 }
5307}
5308
5309#[cfg(test)]
5310mod test {
5311 use super::*;
5312
5313 #[test]
5314 fn highest_priority_address_status_v4() {
5315 assert_eq!(
5317 choose_highest_priority_address_status::<Ipv4>(
5318 [
5319 Ipv4PresentAddressStatus::UnicastAssigned,
5320 Ipv4PresentAddressStatus::UnicastTentative
5321 ]
5322 .into_iter()
5323 ),
5324 Some(Ipv4PresentAddressStatus::UnicastAssigned)
5325 )
5326 }
5327
5328 #[test]
5329 fn highest_priority_address_status_v6() {
5330 assert_eq!(
5332 choose_highest_priority_address_status::<Ipv6>(
5333 [
5334 Ipv6PresentAddressStatus::UnicastAssigned,
5335 Ipv6PresentAddressStatus::UnicastTentative
5336 ]
5337 .into_iter()
5338 ),
5339 Some(Ipv6PresentAddressStatus::UnicastAssigned)
5340 )
5341 }
5342}