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