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>> = {
1426 let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1427 match (device, dst_ip) {
1428 (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1429 .then_some(LocalDelivery::StrongForDevice(device.clone())),
1430 (None, Some(dst_ip)) => {
1431 get_device_with_assigned_address(core_ctx, dst_ip).map(
1432 |(dst_device, _addr_status)| {
1433 if src_ip_and_policy
1438 .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1439 || dst_ip.as_ref().must_have_zone()
1440 {
1441 LocalDelivery::StrongForDevice(dst_device)
1442 } else {
1443 LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1444 }
1445 },
1446 )
1447 }
1448 (_, None) => None,
1449 }
1450 };
1451
1452 if let Some(local_delivery) = local_delivery_instructions {
1453 let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1454
1455 let (src_addr, dest_device) = match local_delivery {
1456 LocalDelivery::WeakLoopback { dst_ip, device } => {
1457 let src_ip = match src_ip_and_policy {
1458 Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1459 let _device = get_device_with_assigned_address(core_ctx, src_ip)
1460 .ok_or(ResolveRouteError::NoSrcAddr)?;
1461 src_ip
1462 }
1463 Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1464 None => dst_ip,
1465 };
1466 (src_ip, device)
1467 }
1468 LocalDelivery::StrongForDevice(device) => {
1469 (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1470 }
1471 };
1472 return Ok(ResolvedRoute {
1473 src_addr,
1474 local_delivery_device: Some(dest_device),
1475 device: loopback,
1476 next_hop: NextHop::RemoteAsNeighbor,
1477 internal_forwarding: InternalForwarding::NotUsed,
1478 });
1479 }
1480 let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1481 let rule_input = RuleInput {
1482 packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1483 marks,
1484 };
1485 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
1486 let mut walk_rules = |rule_input, src_ip_and_policy| {
1487 walk_rules(
1488 core_ctx,
1489 rules,
1490 None, rule_input,
1492 |first_error, core_ctx, table| {
1493 let mut matching_with_addr = table.lookup_filter_map(
1494 core_ctx,
1495 device,
1496 dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1497 |core_ctx, d| {
1498 Some(get_local_addr_with_internal_forwarding(
1499 core_ctx,
1500 src_ip_and_policy,
1501 d,
1502 dst_ip,
1503 ))
1504 },
1505 );
1506
1507 let first_error_in_this_table = match matching_with_addr.next() {
1508 Some((
1509 Destination { device, next_hop },
1510 Ok((local_addr, internal_forwarding)),
1511 )) => {
1512 return ControlFlow::Break(Ok((
1513 Destination { device: device.clone(), next_hop },
1514 local_addr,
1515 internal_forwarding,
1516 )));
1517 }
1518 Some((_, Err(e))) => e,
1519 None => return ControlFlow::Continue(first_error),
1523 };
1524
1525 matching_with_addr
1526 .filter_map(|(destination, local_addr)| {
1527 local_addr.ok_checked::<ResolveRouteError>().map(
1530 |(local_addr, internal_forwarding)| {
1531 (destination, local_addr, internal_forwarding)
1532 },
1533 )
1534 })
1535 .next()
1536 .map_or(
1537 ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1538 |(
1539 Destination { device, next_hop },
1540 local_addr,
1541 internal_forwarding,
1542 )| {
1543 ControlFlow::Break(Ok((
1544 Destination { device: device.clone(), next_hop },
1545 local_addr,
1546 internal_forwarding,
1547 )))
1548 },
1549 )
1550 },
1551 )
1552 };
1553
1554 let result = match walk_rules(&rule_input, src_ip_and_policy) {
1555 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1562 inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1563 observed_source_address_matcher: true,
1564 })) if src_ip_and_policy.is_none() => walk_rules(
1565 &RuleInput {
1566 packet_origin: PacketOrigin::Local {
1567 bound_address: Some(selected_src_addr.into()),
1568 bound_device: device,
1569 },
1570 marks,
1571 },
1572 Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1573 ),
1574 result => result,
1575 };
1576
1577 match result {
1578 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1579 inner: result,
1580 observed_source_address_matcher: _,
1581 })) => {
1582 result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1583 ResolvedRoute {
1584 src_addr,
1585 device,
1586 local_delivery_device: None,
1587 next_hop,
1588 internal_forwarding,
1589 }
1590 })
1591 }
1592 ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1593 ControlFlow::Continue(RuleWalkInfo {
1594 inner: first_error,
1595 observed_source_address_matcher: _,
1596 }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1597 }
1598 })
1599}
1600
1601pub trait UseIpSocketContextBlanket {}
1606
1607impl<I, BC, CC> IpSocketContext<I, BC> for CC
1608where
1609 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1610 BC: IpDeviceBindingsContext<I, CC::DeviceId>
1611 + IpLayerBindingsContext<I, CC::DeviceId>
1612 + IpSocketBindingsContext<CC::DeviceId>,
1613 CC: IpLayerEgressContext<I, BC>
1614 + IpStateContext<I, BC>
1615 + IpDeviceContext<I>
1616 + IpDeviceConfirmReachableContext<I, BC>
1617 + IpDeviceMtuContext<I>
1618 + device::IpDeviceConfigurationContext<I, BC>
1619 + IcmpErrorHandler<I, BC>
1620 + UseIpSocketContextBlanket,
1621{
1622 fn lookup_route(
1623 &mut self,
1624 _bindings_ctx: &mut BC,
1625 device: Option<&CC::DeviceId>,
1626 local_ip: Option<IpDeviceAddr<I::Addr>>,
1627 addr: RoutableIpAddr<I::Addr>,
1628 transparent: bool,
1629 marks: &Marks,
1630 ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1631 let src_ip_and_policy = local_ip.map(|local_ip| {
1632 (
1633 local_ip,
1634 if transparent {
1635 NonLocalSrcAddrPolicy::Allow
1636 } else {
1637 NonLocalSrcAddrPolicy::Deny
1638 },
1639 )
1640 });
1641 let res =
1642 resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1643 trace!(
1644 "lookup_route(\
1645 device={device:?}, \
1646 local_ip={local_ip:?}, \
1647 addr={addr:?}, \
1648 transparent={transparent:?}, \
1649 marks={marks:?}) => {res:?}"
1650 );
1651 res
1652 }
1653
1654 fn send_ip_packet<S>(
1655 &mut self,
1656 bindings_ctx: &mut BC,
1657 meta: SendIpPacketMeta<
1658 I,
1659 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1660 SpecifiedAddr<I::Addr>,
1661 >,
1662 body: S,
1663 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1664 ) -> Result<(), IpSendFrameError<S>>
1665 where
1666 S: TransportPacketSerializer<I>,
1667 S::Buffer: BufferMut,
1668 {
1669 send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1670 }
1671
1672 fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1673 device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1674 }
1675
1676 fn confirm_reachable(
1677 &mut self,
1678 bindings_ctx: &mut BC,
1679 dst: SpecifiedAddr<I::Addr>,
1680 input: RuleInput<'_, I, Self::DeviceId>,
1681 ) {
1682 match lookup_route_table(self, dst.get(), input) {
1683 Some(Destination { next_hop, device }) => {
1684 let neighbor = match next_hop {
1685 NextHop::RemoteAsNeighbor => dst,
1686 NextHop::Gateway(gateway) => gateway,
1687 NextHop::Broadcast(marker) => {
1688 I::map_ip::<_, ()>(
1689 WrapBroadcastMarker(marker),
1690 |WrapBroadcastMarker(())| {
1691 debug!(
1692 "can't confirm {dst:?}@{device:?} as reachable: \
1693 dst is a broadcast address"
1694 );
1695 },
1696 |WrapBroadcastMarker(never)| match never {},
1697 );
1698 return;
1699 }
1700 };
1701 IpDeviceConfirmReachableContext::confirm_reachable(
1702 self,
1703 bindings_ctx,
1704 &device,
1705 neighbor,
1706 );
1707 }
1708 None => {
1709 debug!("can't confirm {dst:?} as reachable: no route");
1710 }
1711 }
1712 }
1713}
1714
1715pub trait SocketMetadata<CC>
1718where
1719 CC: ?Sized,
1720{
1721 fn socket_cookie(&self, core_ctx: &mut CC) -> SocketCookie;
1723 fn marks(&self, core_ctx: &mut CC) -> Marks;
1725}
1726
1727impl<T, O, CC> SocketMetadata<CC> for EitherStack<T, O>
1728where
1729 CC: ?Sized,
1730 T: SocketMetadata<CC>,
1731 O: SocketMetadata<CC>,
1732{
1733 fn socket_cookie(&self, core_ctx: &mut CC) -> SocketCookie {
1734 match self {
1735 Self::ThisStack(t) => t.socket_cookie(core_ctx),
1736 Self::OtherStack(o) => o.socket_cookie(core_ctx),
1737 }
1738 }
1739
1740 fn marks(&self, core_ctx: &mut CC) -> Marks {
1741 match self {
1742 Self::ThisStack(t) => t.marks(core_ctx),
1743 Self::OtherStack(o) => o.marks(core_ctx),
1744 }
1745 }
1746}
1747
1748pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1753 type EarlyDemuxSocket: SocketMetadata<Self>;
1755
1756 fn early_demux<B: ParseBuffer>(
1758 &mut self,
1759 device: &Self::DeviceId,
1760 frame_dst: Option<FrameDestination>,
1761 src_ip: I::Addr,
1762 dst_ip: I::Addr,
1763 proto: I::Proto,
1764 body: B,
1765 ) -> Option<Self::EarlyDemuxSocket>;
1766
1767 fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1771 &mut self,
1772 bindings_ctx: &mut BC,
1773 device: &Self::DeviceId,
1774 src_ip: I::RecvSrcAddr,
1775 dst_ip: SpecifiedAddr<I::Addr>,
1776 proto: I::Proto,
1777 body: B,
1778 info: &LocalDeliveryPacketInfo<I, H>,
1779 early_demux_socket: Option<Self::EarlyDemuxSocket>,
1780 ) -> Result<(), I::IcmpError>;
1781}
1782
1783pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1785 IpTransportDispatchContext<
1786 I,
1787 BC,
1788 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1789 > + IpDeviceIngressStateContext<I>
1790 + IpDeviceMtuContext<I>
1791 + IpDeviceSendContext<I, BC>
1792 + IcmpErrorHandler<I, BC>
1793 + IpLayerContext<I, BC>
1794 + FragmentHandler<I, BC>
1795 + FilterHandlerProvider<I, BC>
1796 + RawIpSocketHandler<I, BC>
1797{
1798}
1799
1800impl<
1801 I: IpLayerIpExt,
1802 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1803 CC: IpTransportDispatchContext<
1804 I,
1805 BC,
1806 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1807 > + IpDeviceIngressStateContext<I>
1808 + IpDeviceMtuContext<I>
1809 + IpDeviceSendContext<I, BC>
1810 + IcmpErrorHandler<I, BC>
1811 + IpLayerContext<I, BC>
1812 + FragmentHandler<I, BC>
1813 + FilterHandlerProvider<I, BC>
1814 + RawIpSocketHandler<I, BC>,
1815> IpLayerIngressContext<I, BC> for CC
1816{
1817}
1818
1819pub trait IpLayerEgressContext<I, BC>:
1821 IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1822 + FilterHandlerProvider<I, BC>
1823 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1824where
1825 I: IpLayerIpExt,
1826 BC: FilterBindingsContext<Self::DeviceId> + TxMetadataBindingsTypes,
1827{
1828}
1829
1830impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1831where
1832 I: IpLayerIpExt,
1833 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes,
1834 CC: IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1835 + FilterHandlerProvider<I, BC>
1836 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
1837{
1838}
1839
1840pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1842 IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
1843{
1844}
1845
1846impl<
1847 I: IpLayerIpExt,
1848 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1849 CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
1850> IpLayerForwardingContext<I, BC> for CC
1851{
1852}
1853
1854#[derive(Copy, Clone, Default)]
1856pub struct Ipv4StateBuilder {
1857 icmp: Icmpv4StateBuilder,
1858}
1859
1860impl Ipv4StateBuilder {
1861 #[cfg(any(test, feature = "testutils"))]
1863 pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
1864 &mut self.icmp
1865 }
1866
1867 pub fn build<
1869 CC: CoreTimerContext<IpLayerTimerId, BC>,
1870 StrongDeviceId: StrongDeviceIdentifier,
1871 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1872 >(
1873 self,
1874 bindings_ctx: &mut BC,
1875 ) -> Ipv4State<StrongDeviceId, BC> {
1876 let Ipv4StateBuilder { icmp } = self;
1877
1878 Ipv4State {
1879 inner: IpStateInner::new::<CC>(bindings_ctx),
1880 icmp: icmp.build(),
1881 next_packet_id: Default::default(),
1882 }
1883 }
1884}
1885
1886#[derive(Copy, Clone)]
1890pub struct Ipv6StateBuilder {
1891 icmp: Icmpv6StateBuilder,
1892 slaac_stable_secret_key: Option<IidSecret>,
1893}
1894
1895impl Ipv6StateBuilder {
1896 pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
1901 self.slaac_stable_secret_key = Some(secret_key);
1902 self
1903 }
1904
1905 pub fn build<
1911 CC: CoreTimerContext<IpLayerTimerId, BC>,
1912 StrongDeviceId: StrongDeviceIdentifier,
1913 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1914 >(
1915 self,
1916 bindings_ctx: &mut BC,
1917 ) -> Ipv6State<StrongDeviceId, BC> {
1918 let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
1919
1920 let slaac_stable_secret_key = slaac_stable_secret_key
1921 .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
1922
1923 Ipv6State {
1924 inner: IpStateInner::new::<CC>(bindings_ctx),
1925 icmp: icmp.build(),
1926 slaac_counters: Default::default(),
1927 slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
1928 slaac_stable_secret_key,
1929 }
1930 }
1931}
1932
1933impl Default for Ipv6StateBuilder {
1934 fn default() -> Self {
1935 #[cfg(any(test, feature = "testutils"))]
1936 let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
1937
1938 #[cfg(not(any(test, feature = "testutils")))]
1939 let slaac_stable_secret_key = None;
1940
1941 Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
1942 }
1943}
1944
1945pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1947 pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
1949 pub icmp: Icmpv4State<BT>,
1951 pub next_packet_id: AtomicU16,
1953}
1954
1955impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1956 AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
1957{
1958 fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
1959 &self.inner
1960 }
1961}
1962
1963pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
1967 core_ctx: &mut CC,
1968) -> I::PacketId {
1969 core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
1970}
1971
1972pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1974 pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
1976 pub icmp: Icmpv6State<BT>,
1978 pub slaac_counters: SlaacCounters,
1980 pub slaac_temp_secret_key: IidSecret,
1982 pub slaac_stable_secret_key: IidSecret,
1987}
1988
1989impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1990 AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
1991{
1992 fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
1993 &self.inner
1994 }
1995}
1996
1997impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1998 OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
1999{
2000 type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
2001 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2002 OrderedLockRef::new(&self.fragment_cache)
2003 }
2004}
2005
2006impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2007 OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
2008{
2009 type Lock = Mutex<PmtuCache<I, BT>>;
2010 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2011 OrderedLockRef::new(&self.pmtu_cache)
2012 }
2013}
2014
2015impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2016 OrderedLockAccess<RulesTable<I, D, BT>> for IpStateInner<I, D, BT>
2017{
2018 type Lock = RwLock<RulesTable<I, D, BT>>;
2019 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2020 OrderedLockRef::new(&self.rules_table)
2021 }
2022}
2023
2024impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2025 OrderedLockAccess<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>
2026 for IpStateInner<I, D, BT>
2027{
2028 type Lock =
2029 Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>;
2030 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2031 OrderedLockRef::new(&self.tables)
2032 }
2033}
2034
2035impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpRoutingBindingsTypes>
2036 OrderedLockAccess<RoutingTable<I, D>> for RoutingTableId<I, D, BT>
2037{
2038 type Lock = RwLock<RoutingTable<I, D>>;
2039 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2040 let Self(inner) = self;
2041 OrderedLockRef::new(&inner.routing_table)
2042 }
2043}
2044
2045impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2046 OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
2047{
2048 type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
2049 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2050 OrderedLockRef::new(&self.multicast_forwarding)
2051 }
2052}
2053
2054impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2055 OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
2056{
2057 type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
2058 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2059 OrderedLockRef::new(&self.raw_sockets)
2060 }
2061}
2062
2063impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2064 OrderedLockAccess<filter::State<I, WeakAddressId<I, BT>, BT>> for IpStateInner<I, D, BT>
2065{
2066 type Lock = RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>;
2067 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2068 OrderedLockRef::new(&self.filter)
2069 }
2070}
2071
2072pub trait IpStateBindingsTypes:
2074 PmtuBindingsTypes
2075 + FragmentBindingsTypes
2076 + RawIpSocketsBindingsTypes
2077 + FilterBindingsTypes
2078 + MulticastForwardingBindingsTypes
2079 + IpDeviceStateBindingsTypes
2080 + IpRoutingBindingsTypes
2081{
2082}
2083impl<BT> IpStateBindingsTypes for BT where
2084 BT: PmtuBindingsTypes
2085 + FragmentBindingsTypes
2086 + RawIpSocketsBindingsTypes
2087 + FilterBindingsTypes
2088 + MulticastForwardingBindingsTypes
2089 + IpDeviceStateBindingsTypes
2090 + IpRoutingBindingsTypes
2091{
2092}
2093
2094#[derive(Derivative)]
2096#[derivative(Debug(bound = ""))]
2097#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2098pub enum RoutingTableCookie<BT: IpRoutingBindingsTypes> {
2099 Main,
2101 BindingsId(BT::RoutingTableId),
2103}
2104
2105#[derive(Derivative)]
2107#[derivative(Debug(bound = "D: Debug"))]
2108pub struct BaseRoutingTableState<I: Ip, D, BT: IpRoutingBindingsTypes> {
2109 routing_table: RwLock<RoutingTable<I, D>>,
2110 bindings_id: RoutingTableCookie<BT>,
2111}
2112
2113impl<I: Ip, D, BT: IpRoutingBindingsTypes> BaseRoutingTableState<I, D, BT> {
2114 pub(crate) fn with_bindings_id(bindings_id: RoutingTableCookie<BT>) -> Self {
2115 Self { bindings_id, routing_table: Default::default() }
2116 }
2117}
2118
2119#[derive(Derivative)]
2121#[derivative(PartialEq(bound = ""))]
2122#[derivative(Eq(bound = ""))]
2123#[derivative(Hash(bound = ""))]
2124#[derivative(Clone(bound = ""))]
2125pub struct RoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes>(
2126 StrongRc<BaseRoutingTableState<I, D, BT>>,
2127);
2128
2129impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for RoutingTableId<I, D, BT> {
2130 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2131 let Self(rc) = self;
2132 f.debug_tuple("RoutingTableId").field(&I::NAME).field(&rc.bindings_id).finish()
2133 }
2134}
2135
2136impl<I: Ip, D, BT: IpRoutingBindingsTypes> RoutingTableId<I, D, BT> {
2137 pub(crate) fn new(rc: StrongRc<BaseRoutingTableState<I, D, BT>>) -> Self {
2139 Self(rc)
2140 }
2141
2142 #[cfg(any(test, feature = "testutils"))]
2144 pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
2145 let Self(inner) = self;
2146 &inner.routing_table
2147 }
2148
2149 pub fn downgrade(&self) -> WeakRoutingTableId<I, D, BT>
2151 where
2152 BT::RoutingTableId: Clone,
2153 {
2154 let Self(rc) = self;
2155 WeakRoutingTableId { rc: StrongRc::downgrade(rc), bindings_id: rc.bindings_id.clone() }
2156 }
2157
2158 #[cfg(test)]
2159 fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2160 let Self(rc) = self;
2161 rc.routing_table.write()
2162 }
2163
2164 pub fn bindings_id(&self) -> &RoutingTableCookie<BT> {
2166 let Self(rc) = self;
2167 &rc.bindings_id
2168 }
2169}
2170
2171#[derive(Derivative)]
2173#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2174#[derivative(PartialEq, Eq, Hash)]
2175pub struct WeakRoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes> {
2176 rc: WeakRc<BaseRoutingTableState<I, D, BT>>,
2177 #[derivative(PartialEq = "ignore")]
2178 #[derivative(Hash = "ignore")]
2179 bindings_id: RoutingTableCookie<BT>,
2180}
2181
2182impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for WeakRoutingTableId<I, D, BT> {
2183 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2184 let Self { bindings_id, .. } = self;
2185 f.debug_tuple("WeakRoutingTableId").field(&I::NAME).field(bindings_id).finish()
2186 }
2187}
2188
2189#[derive(GenericOverIp)]
2191#[generic_over_ip(I, Ip)]
2192pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2193 rules_table: RwLock<RulesTable<I, D, BT>>,
2194 main_table_id: RoutingTableId<I, D, BT>,
2196 multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2197 multicast_forwarding_counters: MulticastForwardingCounters<I>,
2198 fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2199 pmtu_cache: Mutex<PmtuCache<I, BT>>,
2200 counters: IpCounters<I>,
2201 raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2202 raw_socket_counters: RawIpSocketCounters<I>,
2203 filter: RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>,
2204 tables: Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>,
2210 igmp_counters: IgmpCounters,
2211 mld_counters: MldCounters,
2212}
2213
2214impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2215 pub fn counters(&self) -> &IpCounters<I> {
2217 &self.counters
2218 }
2219
2220 pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2222 &self.multicast_forwarding_counters
2223 }
2224
2225 pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2227 &self.raw_socket_counters
2228 }
2229
2230 pub fn main_table_id(&self) -> &RoutingTableId<I, D, BT> {
2232 &self.main_table_id
2233 }
2234
2235 #[cfg(any(test, feature = "testutils"))]
2237 pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2238 &self.pmtu_cache
2239 }
2240
2241 #[cfg(any(test, feature = "testutils"))]
2243 pub fn filter(&self) -> &RwLock<filter::State<I, WeakAddressId<I, BT>, BT>> {
2244 &self.filter
2245 }
2246
2247 pub fn igmp_counters(&self) -> &IgmpCounters {
2249 &self.igmp_counters
2250 }
2251
2252 pub fn mld_counters(&self) -> &MldCounters {
2254 &self.mld_counters
2255 }
2256}
2257
2258impl<
2259 I: IpLayerIpExt,
2260 D: StrongDeviceIdentifier,
2261 BC: TimerContext + RngContext + IpStateBindingsTypes + IpRoutingBindingsTypes,
2262> IpStateInner<I, D, BC>
2263{
2264 fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2266 let main_table: PrimaryRc<BaseRoutingTableState<I, D, BC>> =
2267 PrimaryRc::new(BaseRoutingTableState::with_bindings_id(RoutingTableCookie::Main));
2268 let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2269 Self {
2270 rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2271 tables: Mutex::new(HashMap::from_iter(core::iter::once((
2272 main_table_id.clone(),
2273 main_table,
2274 )))),
2275 main_table_id,
2276 multicast_forwarding: Default::default(),
2277 multicast_forwarding_counters: Default::default(),
2278 fragment_cache: Mutex::new(
2279 IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2280 ),
2281 pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2282 counters: Default::default(),
2283 raw_sockets: Default::default(),
2284 raw_socket_counters: Default::default(),
2285 filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2286 igmp_counters: Default::default(),
2287 mld_counters: Default::default(),
2288 }
2289 }
2290}
2291
2292#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2294#[generic_over_ip()]
2295pub enum IpLayerTimerId {
2296 ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2298 ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2300 PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2302 PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2304 FilterTimerv4(FilterTimerId<Ipv4>),
2306 FilterTimerv6(FilterTimerId<Ipv6>),
2308 MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2310 MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2312}
2313
2314impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2315 fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2316 I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2317 }
2318}
2319
2320impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2321 fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2322 I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2323 }
2324}
2325
2326impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2327 fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2328 I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2329 }
2330}
2331
2332impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2333 fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2334 I::map_ip(
2335 timer,
2336 IpLayerTimerId::MulticastForwardingTimerv4,
2337 IpLayerTimerId::MulticastForwardingTimerv6,
2338 )
2339 }
2340}
2341
2342impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2343where
2344 CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2345 + TimerHandler<BC, FragmentTimerId<Ipv6>>
2346 + TimerHandler<BC, PmtuTimerId<Ipv4>>
2347 + TimerHandler<BC, PmtuTimerId<Ipv6>>
2348 + TimerHandler<BC, FilterTimerId<Ipv4>>
2349 + TimerHandler<BC, FilterTimerId<Ipv6>>
2350 + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2351 + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2352 BC: TimerBindingsTypes,
2353{
2354 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2355 match self {
2356 IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2357 core_ctx.handle_timer(bindings_ctx, id, timer)
2358 }
2359 IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2360 core_ctx.handle_timer(bindings_ctx, id, timer)
2361 }
2362 IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2363 IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2364 IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2365 IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2366 IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2367 core_ctx.handle_timer(bindings_ctx, id, timer)
2368 }
2369 IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2370 core_ctx.handle_timer(bindings_ctx, id, timer)
2371 }
2372 }
2373 }
2374}
2375
2376pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2383 err: I::IcmpError,
2385 src_ip: SocketIpAddr<I::Addr>,
2388 dst_ip: SocketIpAddr<I::Addr>,
2391 frame_dst: Option<FrameDestination>,
2393 device: &'a D,
2395 meta: ParseMetadata,
2398 marks: Marks,
2400 proto: I::Proto,
2402}
2403
2404impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2405 pub fn new<CC, B>(
2406 core_ctx: &mut CC,
2407 err: I::IcmpError,
2408 packet: &I::Packet<B>,
2409 frame_dst: Option<FrameDestination>,
2410 device: &'a D,
2411 marks: Marks,
2412 ) -> Option<Self>
2413 where
2414 I: IpCountersIpExt,
2415 CC: ResourceCounterContext<D, IpCounters<I>>,
2416 B: SplitByteSlice,
2417 {
2418 let Some(src_ip) = SocketIpAddr::new(packet.src_ip()) else {
2419 core_ctx.increment_both(device, |c| &c.unspecified_source);
2420 return None;
2421 };
2422 let Some(dst_ip) = SocketIpAddr::new(packet.dst_ip()) else {
2423 return None;
2424 };
2425
2426 let is_ipv4_fragment = I::map_ip_in(
2428 packet,
2429 |p| {
2430 packet_formats::ipv4::Ipv4Header::fragment_type(p)
2431 == Ipv4FragmentType::NonInitialFragment
2432 },
2433 |_| false,
2434 );
2435 if is_ipv4_fragment {
2436 return None;
2437 }
2438
2439 let meta = packet.parse_metadata();
2440 let proto = packet.proto();
2441 Some(Self { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto })
2442 }
2443
2444 pub fn send<B, BC, CC>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, mut body: B)
2451 where
2452 B: BufferMut,
2453 CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2454 {
2455 let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto } = self;
2456 let header_len = meta.header_len();
2457
2458 body.undo_parse(meta);
2462
2463 core_ctx.send_icmp_error_message(
2464 bindings_ctx,
2465 Some(device),
2466 frame_dst,
2467 src_ip,
2468 dst_ip,
2469 body,
2470 err,
2471 header_len,
2472 proto,
2473 &marks,
2474 );
2475 }
2476}
2477
2478#[derive(PartialEq, Eq)]
2484struct EarlyDemuxResult<I: Ip, S> {
2485 socket: S,
2486 src_addr: I::Addr,
2487 src_port: Option<u16>,
2488}
2489
2490impl<I: FilterIpExt, S> EarlyDemuxResult<I, S> {
2491 fn new<P: IpPacket<I>>(socket: S, packet: &P) -> Self {
2492 let src_port =
2493 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port());
2494 Self { socket, src_addr: packet.src_addr(), src_port }
2495 }
2496
2497 fn take_socket<P: IpPacket<I>>(self, packet: &P) -> Option<S> {
2499 let src_port =
2500 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port());
2501 (self.src_addr == packet.src_addr() && self.src_port == src_port).then_some(self.socket)
2502 }
2503
2504 fn update_packet_metadata<CC, BC>(
2505 &self,
2506 core_ctx: &mut CC,
2507 packet_metadata: &mut IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2508 ) where
2509 I: IpLayerIpExt,
2510 S: SocketMetadata<CC>,
2511 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2512 CC: IpLayerIngressContext<I, BC>,
2513 {
2514 packet_metadata.socket_cookie = Some(self.socket.socket_cookie(core_ctx));
2515 for mark in BC::marks_to_set_on_ingress() {
2516 *packet_metadata.marks.get_mut(*mark) = self.socket.marks(core_ctx).get(*mark).clone();
2517 }
2518 }
2519}
2520
2521pub(crate) fn reject_type_to_icmpv4_error(reject_type: RejectType) -> Option<Icmpv4Error> {
2522 let error = match reject_type {
2523 RejectType::NetUnreachable => Icmpv4Error::NetUnreachable,
2524 RejectType::ProtoUnreachable => Icmpv4Error::ProtocolUnreachable,
2525 RejectType::PortUnreachable => Icmpv4Error::PortUnreachable,
2526 RejectType::HostUnreachable => Icmpv4Error::HostUnreachable,
2527 RejectType::RoutePolicyFail => Icmpv4Error::NetworkProhibited,
2528 RejectType::RejectRoute => Icmpv4Error::HostProhibited,
2529 RejectType::AdminProhibited => Icmpv4Error::AdminProhibited,
2530 RejectType::TcpReset => return None,
2532 };
2533 Some(error)
2534}
2535
2536pub(crate) fn reject_type_to_icmpv6_error(reject_type: RejectType) -> Option<Icmpv6Error> {
2537 let error = match reject_type {
2538 RejectType::NetUnreachable => Icmpv6Error::NetUnreachable,
2539 RejectType::PortUnreachable => Icmpv6Error::PortUnreachable,
2540 RejectType::HostUnreachable => Icmpv6Error::AddressUnreachable,
2541 RejectType::AdminProhibited => Icmpv6Error::AdminProhibited,
2542 RejectType::RoutePolicyFail => Icmpv6Error::SourceAddressPolicyFailed,
2543 RejectType::RejectRoute => Icmpv6Error::RejectRoute,
2544 RejectType::TcpReset | RejectType::ProtoUnreachable => return None,
2546 };
2547 Some(error)
2548}
2549fn dispatch_receive_ipv4_packet<
2570 'a,
2571 'b,
2572 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2573 CC: IpLayerIngressContext<Ipv4, BC>,
2574>(
2575 core_ctx: &'a mut CC,
2576 bindings_ctx: &'a mut BC,
2577 device: &'b CC::DeviceId,
2578 frame_dst: Option<FrameDestination>,
2579 mut packet: Ipv4Packet<&'a mut [u8]>,
2580 mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2581 receive_meta: ReceiveIpPacketMeta<Ipv4>,
2582) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2583 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2584
2585 match frame_dst {
2586 Some(FrameDestination::Individual { local: false }) => {
2587 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2588 }
2589 Some(FrameDestination::Individual { local: true })
2590 | Some(FrameDestination::Multicast)
2591 | Some(FrameDestination::Broadcast)
2592 | None => (),
2593 };
2594
2595 let early_demux_result = receive_meta
2598 .transparent_override
2599 .is_none()
2600 .then(|| {
2601 core_ctx.early_demux(
2602 device,
2603 frame_dst,
2604 packet.src_ip(),
2605 packet.dst_ip(),
2606 packet.proto(),
2607 packet.body(),
2608 )
2609 })
2610 .flatten()
2611 .map(|socket| {
2612 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2613 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2614 early_demux_result
2615 });
2616
2617 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2618 bindings_ctx,
2619 &mut packet,
2620 device,
2621 &mut packet_metadata,
2622 );
2623
2624 let marks = packet_metadata.marks;
2625 packet_metadata.acknowledge_drop();
2626
2627 match filter_verdict {
2628 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2629 return Ok(());
2630 }
2631 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2632 return match reject_type_to_icmpv4_error(reject_type) {
2633 Some(icmp_error) => {
2634 match IcmpErrorSender::new(
2635 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2636 ) {
2637 Some(icmp_sender) => Err(icmp_sender),
2638 None => Ok(()),
2639 }
2640 }
2641 None => {
2642 debug!("Unsupported reject type: {:?}", reject_type);
2643 return Ok(());
2644 }
2645 };
2646 }
2647 filter::Verdict::Proceed(filter::Accept) => (),
2648 };
2649
2650 let Some(src_ip) = packet.src_ipv4() else {
2654 debug!(
2655 "dispatch_receive_ipv4_packet: received packet from invalid source {} after the \
2656 LOCAL_INGRESS hook; dropping",
2657 packet.src_ip()
2658 );
2659 core_ctx.increment_both(device, |c| &c.invalid_source);
2660 return Ok(());
2661 };
2662 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2663 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2664 debug!(
2665 "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2666 after the LOCAL_INGRESS hook; dropping"
2667 );
2668 return Ok(());
2669 };
2670
2671 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2672
2673 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2675
2676 let proto = packet.proto();
2677 let (prefix, options, body) = packet.parts_with_body_mut();
2678 let buffer = Buf::new(body, ..);
2679 let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2680 let receive_info = LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks };
2681
2682 core_ctx
2683 .dispatch_receive_ip_packet(
2684 bindings_ctx,
2685 device,
2686 src_ip,
2687 dst_ip,
2688 proto,
2689 buffer,
2690 &receive_info,
2691 early_demux_socket,
2692 )
2693 .or_else(|icmp_error| {
2694 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2695 Some(icmp_sender) => Err(icmp_sender),
2696 None => Ok(()),
2697 }
2698 })
2699}
2700
2701fn dispatch_receive_ipv6_packet<
2706 'a,
2707 'b,
2708 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2709 CC: IpLayerIngressContext<Ipv6, BC>,
2710>(
2711 core_ctx: &'a mut CC,
2712 bindings_ctx: &'a mut BC,
2713 device: &'b CC::DeviceId,
2714 frame_dst: Option<FrameDestination>,
2715 mut packet: Ipv6Packet<&'a mut [u8]>,
2716 mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2717 meta: ReceiveIpPacketMeta<Ipv6>,
2718) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2719 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2726
2727 match frame_dst {
2728 Some(FrameDestination::Individual { local: false }) => {
2729 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2730 }
2731 Some(FrameDestination::Individual { local: true })
2732 | Some(FrameDestination::Multicast)
2733 | Some(FrameDestination::Broadcast)
2734 | None => (),
2735 }
2736
2737 let early_demux_result = meta
2740 .transparent_override
2741 .is_none()
2742 .then(|| {
2743 core_ctx.early_demux(
2744 device,
2745 frame_dst,
2746 packet.src_ip(),
2747 packet.dst_ip(),
2748 packet.proto(),
2749 packet.body(),
2750 )
2751 })
2752 .flatten()
2753 .map(|socket| {
2754 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2755 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2756 early_demux_result
2757 });
2758
2759 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2760 bindings_ctx,
2761 &mut packet,
2762 device,
2763 &mut packet_metadata,
2764 );
2765
2766 let marks = packet_metadata.marks;
2767 packet_metadata.acknowledge_drop();
2768
2769 match filter_verdict {
2770 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2771 return Ok(());
2772 }
2773 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2774 return match reject_type_to_icmpv6_error(reject_type) {
2775 Some(icmp_error) => {
2776 match IcmpErrorSender::new(
2777 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2778 ) {
2779 Some(icmp_sender) => Err(icmp_sender),
2780 None => Ok(()),
2781 }
2782 }
2783 None => {
2784 debug!("Unsupported reject type: {:?}", reject_type);
2785 return Ok(());
2786 }
2787 };
2788 }
2789 filter::Verdict::Proceed(filter::Accept) => {}
2790 }
2791
2792 let Some(src_ip) = packet.src_ipv6() else {
2796 debug!(
2797 "dispatch_receive_ipv6_packet: received packet from invalid source {} after the \
2798 LOCAL_INGRESS hook; dropping",
2799 packet.src_ip()
2800 );
2801
2802 core_ctx.increment_both(device, |c| &c.invalid_source);
2803 return Ok(());
2804 };
2805 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2806 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2807 debug!(
2808 "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2809 after the LOCAL_INGRESS hook; dropping"
2810 );
2811 return Ok(());
2812 };
2813
2814 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2815
2816 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2818
2819 let proto = packet.proto();
2820 let (fixed, extension, body) = packet.parts_with_body_mut();
2821 let buffer = Buf::new(body, ..);
2822 let header_info = Ipv6HeaderInfo { fixed, extension };
2823 let receive_info = LocalDeliveryPacketInfo { meta, header_info, marks };
2824
2825 core_ctx
2826 .dispatch_receive_ip_packet(
2827 bindings_ctx,
2828 device,
2829 src_ip,
2830 dst_ip,
2831 proto,
2832 buffer,
2833 &receive_info,
2834 early_demux_socket,
2835 )
2836 .or_else(|icmp_error| {
2837 let marks = receive_info.marks;
2838 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2839 Some(icmp_sender) => Err(icmp_sender),
2840 None => Ok(()),
2841 }
2842 })
2843}
2844
2845pub(crate) struct IpPacketForwarder<
2852 'a,
2853 I: IpLayerIpExt,
2854 D,
2855 A,
2856 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2857> {
2858 inbound_device: &'a D,
2859 outbound_device: &'a D,
2860 packet_meta: IpLayerPacketMetadata<I, A, BT>,
2861 src_ip: I::RecvSrcAddr,
2862 dst_ip: SpecifiedAddr<I::Addr>,
2863 destination: IpPacketDestination<I, &'a D>,
2864 proto: I::Proto,
2865 parse_meta: ParseMetadata,
2866 frame_dst: Option<FrameDestination>,
2867}
2868
2869impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
2870where
2871 I: IpLayerIpExt,
2872 BC: IpLayerBindingsContext<I, D>,
2873{
2874 fn forward_with_buffer<CC, B>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B)
2876 where
2877 B: BufferMut,
2878 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2879 {
2880 let Self {
2881 inbound_device,
2882 outbound_device,
2883 packet_meta,
2884 src_ip,
2885 dst_ip,
2886 destination,
2887 proto,
2888 parse_meta,
2889 frame_dst,
2890 } = self;
2891
2892 let packet = ForwardedPacket::new(src_ip.get(), dst_ip.get(), proto, parse_meta, buffer);
2893
2894 trace!("forward_with_buffer: forwarding {} packet", I::NAME);
2895
2896 let marks = packet_meta.marks;
2897 match send_ip_frame(
2898 core_ctx,
2899 bindings_ctx,
2900 outbound_device,
2901 destination,
2902 packet,
2903 packet_meta,
2904 Mtu::no_limit(),
2905 ) {
2906 Ok(()) => (),
2907 Err(IpSendFrameError { serializer, error }) => {
2908 match error {
2909 IpSendFrameErrorReason::Device(
2910 SendFrameErrorReason::SizeConstraintsViolation,
2911 ) => {
2912 debug!("failed to forward {} packet: MTU exceeded", I::NAME);
2913 core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
2914 let mtu = core_ctx.get_mtu(inbound_device);
2915 let Some(err) = I::IcmpError::mtu_exceeded(mtu) else {
2917 return;
2918 };
2919 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2922 return;
2923 };
2924
2925 let Some(dst_ip) = SocketIpAddr::new(dst_ip.get()) else {
2926 return;
2927 };
2928
2929 core_ctx.send_icmp_error_message(
2939 bindings_ctx,
2940 Some(inbound_device),
2941 frame_dst,
2942 src_ip,
2943 dst_ip,
2944 serializer.into_buffer(),
2945 err,
2946 parse_meta.header_len(),
2947 proto,
2948 &marks,
2949 );
2950 }
2951 IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
2952 | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
2953 | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
2954 }
2955 debug!("failed to forward {} packet: {error:?}", I::NAME);
2956 }
2957 }
2958 }
2959}
2960
2961pub(crate) enum ForwardingAction<
2963 'a,
2964 I: IpLayerIpExt,
2965 D,
2966 A,
2967 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2968> {
2969 SilentlyDrop,
2971 Forward(IpPacketForwarder<'a, I, D, A, BT>),
2973 DropWithIcmpError(IcmpErrorSender<'a, I, D>),
2976}
2977
2978impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
2979where
2980 I: IpLayerIpExt,
2981 BC: IpLayerBindingsContext<I, D>,
2982{
2983 pub(crate) fn perform_action_with_buffer<CC, B>(
2985 self,
2986 core_ctx: &mut CC,
2987 bindings_ctx: &mut BC,
2988 buffer: B,
2989 ) where
2990 B: BufferMut,
2991 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2992 {
2993 match self {
2994 ForwardingAction::SilentlyDrop => {}
2995 ForwardingAction::Forward(forwarder) => {
2996 forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer)
2997 }
2998 ForwardingAction::DropWithIcmpError(icmp_sender) => {
2999 icmp_sender.send(core_ctx, bindings_ctx, buffer)
3000 }
3001 }
3002 }
3003}
3004
3005pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
3007 core_ctx: &'a mut CC,
3008 mut packet: I::Packet<&'a mut [u8]>,
3009 mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3010 minimum_ttl: Option<u8>,
3011 inbound_device: &'b CC::DeviceId,
3012 outbound_device: &'b CC::DeviceId,
3013 destination: IpPacketDestination<I, &'b CC::DeviceId>,
3014 frame_dst: Option<FrameDestination>,
3015 src_ip: I::RecvSrcAddr,
3016 dst_ip: SpecifiedAddr<I::Addr>,
3017) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
3018where
3019 I: IpLayerIpExt,
3020 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3021 CC: IpLayerForwardingContext<I, BC>,
3022{
3023 const DEFAULT_MINIMUM_FORWARDING_TTL: u8 = 2;
3028 let minimum_ttl = minimum_ttl.unwrap_or(DEFAULT_MINIMUM_FORWARDING_TTL);
3029
3030 let ttl = packet.ttl();
3031 if ttl < minimum_ttl {
3032 debug!(
3033 "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
3034 I::NAME
3035 );
3036 if ttl > 1 {
3048 packet_meta.acknowledge_drop();
3049 return ForwardingAction::SilentlyDrop;
3050 }
3051
3052 core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
3053
3054 let marks = packet_meta.marks;
3055 packet_meta.acknowledge_drop();
3056
3057 match IcmpErrorSender::new(
3059 core_ctx,
3060 I::IcmpError::ttl_expired(),
3061 &packet,
3062 frame_dst,
3063 inbound_device,
3064 marks,
3065 ) {
3066 Some(icmp_sender) => return ForwardingAction::DropWithIcmpError(icmp_sender),
3067 None => return ForwardingAction::SilentlyDrop,
3068 }
3069 }
3070
3071 trace!("determine_ip_packet_forwarding_action: adequate TTL");
3072
3073 let maybe_ipv6_packet_action = I::map_ip_in(
3079 &packet,
3080 |_packet| None,
3081 |packet| {
3082 Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
3083 },
3084 );
3085 match maybe_ipv6_packet_action {
3086 None => {} Some(Ipv6PacketAction::_Discard) => {
3088 core_ctx.increment_both(inbound_device, |c| {
3089 #[derive(GenericOverIp)]
3090 #[generic_over_ip(I, Ip)]
3091 struct InCounters<'a, I: IpLayerIpExt>(
3092 &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<Counter>,
3093 );
3094 I::map_ip_in::<_, _>(
3095 InCounters(&c.version_rx),
3096 |_counters| {
3097 unreachable!(
3098 "`I` must be `Ipv6` because we're handling IPv6 extension headers"
3099 )
3100 },
3101 |InCounters(counters)| &counters.extension_header_discard,
3102 )
3103 });
3104 trace!(
3105 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3106 discarding packet"
3107 );
3108 packet_meta.acknowledge_drop();
3109 return ForwardingAction::SilentlyDrop;
3110 }
3111 Some(Ipv6PacketAction::Continue) => {
3112 trace!(
3113 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3114 forwarding packet"
3115 );
3116 }
3117 Some(Ipv6PacketAction::ProcessFragment) => {
3118 unreachable!(
3119 "When forwarding packets, we should only ever look at the hop by hop \
3120 options extension header (if present)"
3121 )
3122 }
3123 };
3124
3125 match core_ctx.filter_handler().forwarding_hook(
3126 I::as_filter_packet(&mut packet),
3127 inbound_device,
3128 outbound_device,
3129 &mut packet_meta,
3130 ) {
3131 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3132 packet_meta.acknowledge_drop();
3133 trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
3134 return ForwardingAction::SilentlyDrop;
3135 }
3136 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
3137 packet_meta.acknowledge_drop();
3139 trace!(
3140 "determine_ip_packet_forwarding_action: filter verdict: Reject({:?})",
3141 reject_type
3142 );
3143 return ForwardingAction::SilentlyDrop;
3144 }
3145 filter::Verdict::Proceed(filter::Accept) => {}
3146 }
3147
3148 packet.set_ttl(ttl - 1);
3149 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
3150 ForwardingAction::Forward(IpPacketForwarder {
3151 inbound_device,
3152 outbound_device,
3153 packet_meta,
3154 src_ip,
3155 dst_ip,
3156 destination,
3157 proto,
3158 parse_meta,
3159 frame_dst,
3160 })
3161}
3162
3163pub(crate) fn send_ip_frame<I, CC, BC, S>(
3164 core_ctx: &mut CC,
3165 bindings_ctx: &mut BC,
3166 device: &CC::DeviceId,
3167 destination: IpPacketDestination<I, &CC::DeviceId>,
3168 mut body: S,
3169 mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3170 limit_mtu: Mtu,
3171) -> Result<(), IpSendFrameError<S>>
3172where
3173 I: IpLayerIpExt,
3174 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3175 CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
3176 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>,
3177{
3178 let (verdict, proof) = core_ctx.filter_handler().egress_hook(
3179 bindings_ctx,
3180 &mut body,
3181 device,
3182 &mut packet_metadata,
3183 );
3184 match verdict {
3185 filter::Verdict::Stop(filter::DropPacket) => {
3186 packet_metadata.acknowledge_drop();
3187 return Ok(());
3188 }
3189 filter::Verdict::Proceed(filter::Accept) => {}
3190 }
3191
3192 let (conntrack_connection_and_direction, tx_metadata, marks, _socket_cookie) =
3196 packet_metadata.into_parts();
3197 let conntrack_entry = if device.is_loopback() {
3198 conntrack_connection_and_direction
3199 .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
3200 } else {
3201 None
3202 };
3203
3204 let mut device_layer_marks = Marks::default();
3205 for mark in BC::marks_to_keep_on_egress() {
3206 *device_layer_marks.get_mut(*mark) = *marks.get(*mark);
3207 }
3208
3209 let device_ip_layer_metadata =
3210 DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks: device_layer_marks };
3211
3212 if !device.is_loopback()
3216 && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
3217 || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
3218 {
3219 core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
3220 return Err(IpSendFrameError {
3221 serializer: body,
3222 error: IpSendFrameErrorReason::IllegalLoopbackAddress,
3223 });
3224 }
3225
3226 let mtu = limit_mtu.min(core_ctx.get_mtu(device));
3228
3229 let body = body.with_size_limit(mtu.into());
3230
3231 let fits_mtu =
3232 match body.serialize_new_buf(PacketConstraints::UNCONSTRAINED, AlwaysFailBufferAlloc) {
3233 Err(SerializeError::Alloc(())) => true,
3236 Err(SerializeError::SizeLimitExceeded) => false,
3238 };
3239
3240 if fits_mtu {
3241 return core_ctx
3242 .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
3243 .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
3244 serializer: serializer.into_inner(),
3245 error: error.into(),
3246 });
3247 }
3248
3249 core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
3252
3253 let mut device_ip_layer_metadata = Some(device_ip_layer_metadata);
3255 let body = body.into_inner();
3256 let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
3257 Ok(mut fragmenter) => loop {
3258 let (fragment, has_more) = match fragmenter.next() {
3259 None => break Ok(()),
3260 Some(f) => f,
3261 };
3262
3263 let device_ip_layer_metadata = if has_more {
3268 let device_ip_layer_metadata = device_ip_layer_metadata.as_ref().unwrap();
3270 DeviceIpLayerMetadata {
3271 conntrack_entry: device_ip_layer_metadata.conntrack_entry.clone(),
3272 tx_metadata: Default::default(),
3273 marks: device_ip_layer_metadata.marks,
3274 }
3275 } else {
3276 device_ip_layer_metadata.take().unwrap()
3278 };
3279
3280 match core_ctx.send_ip_frame(
3281 bindings_ctx,
3282 device,
3283 destination.clone(),
3284 device_ip_layer_metadata,
3285 fragment,
3286 proof.clone_for_fragmentation(),
3287 ) {
3288 Ok(()) => {
3289 core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
3290 }
3291 Err(ErrorAndSerializer { serializer: _, error }) => {
3292 core_ctx
3293 .increment_both(device, |c| &c.fragmentation.error_fragmented_serializer);
3294 break Err(error);
3295 }
3296 }
3297 },
3298 Err(e) => {
3299 core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
3300 Err(SendFrameErrorReason::SizeConstraintsViolation)
3301 }
3302 };
3303 result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
3304}
3305
3306struct AlwaysFailBufferAlloc;
3311
3312impl LayoutBufferAlloc<Never> for AlwaysFailBufferAlloc {
3313 type Error = ();
3314 fn layout_alloc(
3315 self,
3316 _prefix: usize,
3317 _body: usize,
3318 _suffix: usize,
3319 ) -> Result<Never, Self::Error> {
3320 Err(())
3321 }
3322}
3323
3324macro_rules! drop_packet_and_undo_parse {
3333 ($packet:expr, $buffer:expr) => {{
3334 let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
3335 $buffer.undo_parse(meta);
3336 (src_ip, dst_ip, proto, meta)
3337 }};
3338}
3339
3340enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
3343 Done,
3346
3347 NotNeeded(I::Packet<&'a mut [u8]>),
3350
3351 Reassembled(Vec<u8>),
3354}
3355
3356fn process_fragment<'a, I, CC, BC>(
3362 core_ctx: &mut CC,
3363 bindings_ctx: &mut BC,
3364 device: &CC::DeviceId,
3365 packet: I::Packet<&'a mut [u8]>,
3366) -> ProcessFragmentResult<'a, I>
3367where
3368 I: IpLayerIpExt,
3369 for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3370 CC: IpLayerIngressContext<I, BC>,
3371 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3372{
3373 match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3374 FragmentProcessingState::NotNeeded(packet) => {
3376 trace!("receive_ip_packet: not fragmented");
3377 ProcessFragmentResult::NotNeeded(packet)
3378 }
3379 FragmentProcessingState::Ready { key, packet_len } => {
3381 trace!("receive_ip_packet: fragmented, ready for reassembly");
3382 let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3384
3385 let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3387 core_ctx,
3388 bindings_ctx,
3389 &key,
3390 buffer.buffer_view_mut(),
3391 ) {
3392 Ok(()) => ProcessFragmentResult::Reassembled(buffer.into_inner()),
3394 Err(e) => {
3395 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3396 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3397 ProcessFragmentResult::Done
3398 }
3399 };
3400 reassemble_result
3401 }
3402 FragmentProcessingState::NeedMoreFragments => {
3405 core_ctx.increment_both(device, |c| &c.need_more_fragments);
3406 trace!("receive_ip_packet: fragmented, need more before reassembly");
3407 ProcessFragmentResult::Done
3408 }
3409 FragmentProcessingState::InvalidFragment => {
3411 core_ctx.increment_both(device, |c| &c.invalid_fragment);
3412 trace!("receive_ip_packet: fragmented, invalid");
3413 ProcessFragmentResult::Done
3414 }
3415 FragmentProcessingState::OutOfMemory => {
3416 core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3417 trace!("receive_ip_packet: fragmented, dropped because OOM");
3418 ProcessFragmentResult::Done
3419 }
3420 }
3421}
3422
3423macro_rules! try_parse_ip_packet {
3433 ($buffer:expr) => {{
3434 let p_len = $buffer.prefix_len();
3435 let s_len = $buffer.suffix_len();
3436
3437 let result = $buffer.parse_mut();
3438
3439 if let Err(err) = result {
3440 let n_p_len = $buffer.prefix_len();
3442 let n_s_len = $buffer.suffix_len();
3443
3444 if n_p_len > p_len {
3445 $buffer.grow_front(n_p_len - p_len);
3446 }
3447
3448 if n_s_len > s_len {
3449 $buffer.grow_back(n_s_len - s_len);
3450 }
3451
3452 Err(err)
3453 } else {
3454 result
3455 }
3456 }};
3457}
3458
3459macro_rules! clone_packet_for_mcast_forwarding {
3477 {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3478 let mut $new_data = $packet.to_vec();
3479 let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3480 let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3481 };
3482}
3483
3484pub fn receive_ipv4_packet<
3489 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3490 B: BufferMut,
3491 CC: IpLayerIngressContext<Ipv4, BC>,
3492>(
3493 core_ctx: &mut CC,
3494 bindings_ctx: &mut BC,
3495 device: &CC::DeviceId,
3496 frame_dst: Option<FrameDestination>,
3497 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3498 buffer: B,
3499) {
3500 if !core_ctx.is_ip_device_enabled(&device) {
3501 return;
3502 }
3503
3504 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3507
3508 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3509 trace!("receive_ip_packet({device:?})");
3510
3511 let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3512 Ok(packet) => packet,
3513 Err(ParseError::Format)
3514 | Err(ParseError::Checksum)
3515 | Err(ParseError::NotSupported)
3516 | Err(ParseError::NotExpected) => {
3517 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3518 return;
3519 }
3520 };
3521
3522 if packet.src_ipv4().is_none() {
3526 debug!(
3527 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3528 packet.src_ip()
3529 );
3530 core_ctx.increment_both(device, |c| &c.invalid_source);
3531 return;
3532 };
3533 if !packet.dst_ip().is_specified() {
3534 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3535 debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3536 return;
3537 };
3538
3539 let mut packet = match process_fragment(core_ctx, bindings_ctx, device, packet) {
3552 ProcessFragmentResult::Done => return,
3553 ProcessFragmentResult::NotNeeded(packet) => packet,
3554 ProcessFragmentResult::Reassembled(buf) => {
3555 let buf = Buf::new(buf, ..);
3556 buffer = packet::Either::B(buf);
3557
3558 match buffer.parse_mut() {
3559 Ok(packet) => packet,
3560 Err(err) => {
3561 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3562 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3563 return;
3564 }
3565 }
3566 }
3567 };
3568
3569 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3572 core_ctx,
3573 device,
3574 device_ip_layer_metadata,
3575 );
3576 let mut filter = core_ctx.filter_handler();
3577 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3578 filter::Verdict::Proceed(filter::Accept) => {}
3579 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
3580 packet_metadata.acknowledge_drop();
3581 return;
3582 }
3583 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
3584 addr,
3585 port,
3586 }) => {
3587 drop(filter);
3590
3591 let Some(addr) = SpecifiedAddr::new(addr) else {
3592 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3593 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3594 return;
3595 };
3596
3597 let receive_meta = ReceiveIpPacketMeta {
3598 broadcast: None,
3602 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3603 };
3604
3605 dispatch_receive_ipv4_packet(
3609 core_ctx,
3610 bindings_ctx,
3611 device,
3612 frame_dst,
3613 packet,
3614 packet_metadata,
3615 receive_meta,
3616 )
3617 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3618 return;
3619 }
3620 }
3621 drop(filter);
3624
3625 let Some(src_ip) = packet.src_ipv4() else {
3626 core_ctx.increment_both(device, |c| &c.invalid_source);
3627 debug!(
3628 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3629 packet.src_ip()
3630 );
3631 return;
3632 };
3633
3634 let action = receive_ipv4_packet_action(
3635 core_ctx,
3636 bindings_ctx,
3637 device,
3638 &packet,
3639 frame_dst,
3640 &packet_metadata.marks,
3641 );
3642 match action {
3643 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3644 let mut packet_metadata = Some(packet_metadata);
3651 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3652 clone_packet_for_mcast_forwarding! {
3653 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3654 };
3655 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3656 core_ctx,
3657 copy_of_packet,
3658 packet_metadata.take().unwrap_or_default(),
3659 Some(*min_ttl),
3660 device,
3661 &output_interface,
3662 IpPacketDestination::from_addr(dst_ip),
3663 frame_dst,
3664 src_ip,
3665 dst_ip,
3666 )
3667 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3668 }
3669
3670 if let Some(address_status) = address_status {
3672 let receive_meta = ReceiveIpPacketMeta {
3673 broadcast: address_status.to_broadcast_marker(),
3674 transparent_override: None,
3675 };
3676 dispatch_receive_ipv4_packet(
3677 core_ctx,
3678 bindings_ctx,
3679 device,
3680 frame_dst,
3681 packet,
3682 packet_metadata.take().unwrap_or_default(),
3683 receive_meta,
3684 )
3685 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3686 }
3687 }
3688 ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
3689 match internal_forwarding {
3692 InternalForwarding::Used(outbound_device) => {
3693 core_ctx.increment_both(device, |c| &c.forward);
3694 match core_ctx.filter_handler().forwarding_hook(
3695 &mut packet,
3696 device,
3697 &outbound_device,
3698 &mut packet_metadata,
3699 ) {
3700 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3701 packet_metadata.acknowledge_drop();
3702 return;
3703 }
3704 filter::Verdict::Stop(filter::DropOrReject::Reject(_reject_type)) => {
3705 packet_metadata.acknowledge_drop();
3707 return;
3708 }
3709 filter::Verdict::Proceed(filter::Accept) => {}
3710 }
3711 }
3712 InternalForwarding::NotUsed => {}
3713 }
3714
3715 let receive_meta = ReceiveIpPacketMeta {
3716 broadcast: address_status.to_broadcast_marker(),
3717 transparent_override: None,
3718 };
3719 dispatch_receive_ipv4_packet(
3720 core_ctx,
3721 bindings_ctx,
3722 device,
3723 frame_dst,
3724 packet,
3725 packet_metadata,
3726 receive_meta,
3727 )
3728 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3729 }
3730 ReceivePacketAction::Forward {
3731 original_dst,
3732 dst: Destination { device: dst_device, next_hop },
3733 } => {
3734 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3735 core_ctx,
3736 packet,
3737 packet_metadata,
3738 None,
3739 device,
3740 &dst_device,
3741 IpPacketDestination::from_next_hop(next_hop, original_dst),
3742 frame_dst,
3743 src_ip,
3744 original_dst,
3745 )
3746 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3747 }
3748 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3749 core_ctx.increment_both(device, |c| &c.no_route_to_host);
3750 debug!("received IPv4 packet with no known route to destination {}", dst_ip);
3751
3752 let marks = packet_metadata.marks;
3753 packet_metadata.acknowledge_drop();
3754
3755 if let Some(sender) = IcmpErrorSender::new(
3756 core_ctx,
3757 Icmpv4Error::NetUnreachable,
3758 &packet,
3759 frame_dst,
3760 device,
3761 marks,
3762 ) {
3763 sender.send(core_ctx, bindings_ctx, buffer);
3764 }
3765 }
3766 ReceivePacketAction::Drop { reason } => {
3767 let src_ip = packet.src_ip();
3768 let dst_ip = packet.dst_ip();
3769 packet_metadata.acknowledge_drop();
3770 core_ctx.increment_both(device, |c| &c.dropped);
3771 debug!(
3772 "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
3773 {device:?}: {reason:?}",
3774 );
3775 }
3776 }
3777}
3778
3779fn handle_ipv6_parse_error<BC, B, CC>(
3780 core_ctx: &mut CC,
3781 bindings_ctx: &mut BC,
3782 device: &CC::DeviceId,
3783 frame_dst: Option<FrameDestination>,
3784 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3785 mut buffer: B,
3786 error: Ipv6ParseError,
3787) where
3788 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3789 B: BufferMut,
3790 CC: IpLayerIngressContext<Ipv6, BC>,
3791{
3792 let Ipv6ParseError::ParameterProblem { src_ip, dst_ip, code, pointer, must_send_icmp, action } =
3798 error
3799 else {
3800 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3801 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
3802 return;
3803 };
3804 if !must_send_icmp || !action.should_send_icmp(&dst_ip) {
3805 return;
3806 }
3807 core_ctx.increment_both(device, |c| &c.parameter_problem);
3808 let dst_ip = match SocketIpAddr::new(dst_ip) {
3809 Some(ip) => ip,
3810 None => {
3811 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3812 debug!("receive_ipv6_packet: Dropping packet with unspecified destination IP");
3813 return;
3814 }
3815 };
3816
3817 let src_ip = match Ipv6SourceAddr::new(src_ip) {
3818 None => {
3819 core_ctx.increment_both(device, |c| &c.invalid_source);
3820 return;
3821 }
3822 Some(Ipv6SourceAddr::Unspecified) => {
3823 core_ctx.increment_both(device, |c| &c.unspecified_source);
3824 return;
3825 }
3826 Some(Ipv6SourceAddr::Unicast(src_ip)) => {
3827 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
3828 }
3829 };
3830
3831 let raw_packet: Ipv6PacketRaw<_> = match try_parse_ip_packet!(buffer) {
3834 Ok(packet) => packet,
3835 Err(error) => {
3836 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3837 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
3838 return;
3839 }
3840 };
3841 let proto = match raw_packet.proto() {
3842 Ok(proto) => proto,
3843 Err(error) => {
3844 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3845 debug!("receive_ipv6_packet: Failed to get protocol from IPv6 packet: {:?}", error);
3846 return;
3847 }
3848 };
3849 let parse_metadata = raw_packet.parse_metadata();
3850 let header_len = parse_metadata.header_len();
3851 buffer.undo_parse(parse_metadata);
3852
3853 let err = Icmpv6Error::ParameterProblem {
3854 code,
3855 pointer,
3856 allow_dst_multicast: action.should_send_icmp_to_multicast(),
3857 };
3858
3859 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3860 core_ctx,
3861 bindings_ctx,
3862 Some(device),
3863 frame_dst,
3864 src_ip,
3865 dst_ip,
3866 buffer,
3867 err,
3868 header_len,
3869 proto,
3870 &device_ip_layer_metadata.marks,
3871 );
3872}
3873
3874pub fn receive_ipv6_packet<
3879 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3880 B: BufferMut,
3881 CC: IpLayerIngressContext<Ipv6, BC>,
3882>(
3883 core_ctx: &mut CC,
3884 bindings_ctx: &mut BC,
3885 device: &CC::DeviceId,
3886 frame_dst: Option<FrameDestination>,
3887 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3888 buffer: B,
3889) {
3890 if !core_ctx.is_ip_device_enabled(&device) {
3891 return;
3892 }
3893
3894 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3897
3898 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3899 trace!("receive_ipv6_packet({:?})", device);
3900
3901 let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
3902 Ok(packet) => packet,
3903 Err(error) => {
3904 handle_ipv6_parse_error(
3905 core_ctx,
3906 bindings_ctx,
3907 device,
3908 frame_dst,
3909 device_ip_layer_metadata,
3910 buffer,
3911 error,
3912 );
3913 return;
3914 }
3915 };
3916
3917 trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
3918
3919 if packet.src_ipv6().is_none() {
3925 debug!(
3926 "receive_ipv6_packet: received packet from invalid source {}; dropping",
3927 packet.src_ip()
3928 );
3929 core_ctx.increment_both(device, |c| &c.invalid_source);
3930 return;
3931 };
3932 if !packet.dst_ip().is_specified() {
3933 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3934 debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
3935 return;
3936 };
3937
3938 let (mut packet, delivery_extension_header_action) =
3949 match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
3950 Ipv6PacketAction::_Discard => {
3951 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3952 trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
3953 return;
3954 }
3955 Ipv6PacketAction::Continue => {
3956 trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
3957 (packet, Some(Ipv6PacketAction::Continue))
3958 }
3959 Ipv6PacketAction::ProcessFragment => {
3960 trace!(
3961 "receive_ipv6_packet: handled IPv6 extension headers: handling \
3962 fragmented packet"
3963 );
3964
3965 match process_fragment(core_ctx, bindings_ctx, device, packet) {
3977 ProcessFragmentResult::Done => return,
3978 ProcessFragmentResult::NotNeeded(packet) => {
3979 (packet, Some(Ipv6PacketAction::Continue))
3994 }
3995 ProcessFragmentResult::Reassembled(buf) => {
3996 let buf = Buf::new(buf, ..);
3997 buffer = packet::Either::B(buf);
3998
3999 match buffer.parse_mut() {
4000 Ok(packet) => (packet, None),
4001 Err(err) => {
4002 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4003 debug!(
4004 "receive_ip_packet: fragmented, failed to reassemble: {:?}",
4005 err
4006 );
4007 return;
4008 }
4009 }
4010 }
4011 }
4012 }
4013 };
4014
4015 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
4016 core_ctx,
4017 device,
4018 device_ip_layer_metadata,
4019 );
4020 let mut filter = core_ctx.filter_handler();
4021
4022 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
4023 filter::Verdict::Proceed(filter::Accept) => {}
4024 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
4025 packet_metadata.acknowledge_drop();
4026 return;
4027 }
4028 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
4029 addr,
4030 port,
4031 }) => {
4032 drop(filter);
4035
4036 let Some(addr) = SpecifiedAddr::new(addr) else {
4037 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4038 debug!("cannot perform transparent delivery to unspecified destination; dropping");
4039 return;
4040 };
4041
4042 let receive_meta = ReceiveIpPacketMeta {
4043 broadcast: None,
4044 transparent_override: Some(TransparentLocalDelivery { addr, port }),
4045 };
4046
4047 dispatch_receive_ipv6_packet(
4051 core_ctx,
4052 bindings_ctx,
4053 device,
4054 frame_dst,
4055 packet,
4056 packet_metadata,
4057 receive_meta,
4058 )
4059 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4060 return;
4061 }
4062 }
4063 drop(filter);
4066
4067 let Some(src_ip) = packet.src_ipv6() else {
4068 debug!(
4069 "receive_ipv6_packet: received packet from invalid source {}; dropping",
4070 packet.src_ip()
4071 );
4072 core_ctx.increment_both(device, |c| &c.invalid_source);
4073 return;
4074 };
4075
4076 match receive_ipv6_packet_action(
4077 core_ctx,
4078 bindings_ctx,
4079 device,
4080 &packet,
4081 frame_dst,
4082 &packet_metadata.marks,
4083 ) {
4084 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
4085 let mut packet_metadata = Some(packet_metadata);
4092 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
4093 clone_packet_for_mcast_forwarding! {
4094 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
4095 };
4096 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4097 core_ctx,
4098 copy_of_packet,
4099 packet_metadata.take().unwrap_or_default(),
4100 Some(*min_ttl),
4101 device,
4102 &output_interface,
4103 IpPacketDestination::from_addr(dst_ip),
4104 frame_dst,
4105 src_ip,
4106 dst_ip,
4107 )
4108 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
4109 }
4110
4111 if let Some(_) = address_status {
4113 let receive_meta =
4114 ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
4115
4116 dispatch_receive_ipv6_packet(
4117 core_ctx,
4118 bindings_ctx,
4119 device,
4120 frame_dst,
4121 packet,
4122 packet_metadata.take().unwrap_or_default(),
4123 receive_meta,
4124 )
4125 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4126 }
4127 }
4128 ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
4129 trace!("receive_ipv6_packet: delivering locally");
4130
4131 let action = if let Some(action) = delivery_extension_header_action {
4132 action
4133 } else {
4134 ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
4135 };
4136 match action {
4137 Ipv6PacketAction::_Discard => {
4138 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4139 trace!(
4140 "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
4141 );
4142 packet_metadata.acknowledge_drop();
4143 }
4144 Ipv6PacketAction::Continue => {
4145 trace!(
4146 "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
4147 );
4148
4149 match internal_forwarding {
4152 InternalForwarding::Used(outbound_device) => {
4153 core_ctx.increment_both(device, |c| &c.forward);
4154 match core_ctx.filter_handler().forwarding_hook(
4155 &mut packet,
4156 device,
4157 &outbound_device,
4158 &mut packet_metadata,
4159 ) {
4160 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
4161 packet_metadata.acknowledge_drop();
4162 return;
4163 }
4164 filter::Verdict::Stop(filter::DropOrReject::Reject(
4165 _reject_type,
4166 )) => {
4167 packet_metadata.acknowledge_drop();
4169 return;
4170 }
4171 filter::Verdict::Proceed(filter::Accept) => {}
4172 }
4173 }
4174 InternalForwarding::NotUsed => {}
4175 }
4176
4177 let meta = ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
4178 dispatch_receive_ipv6_packet(
4179 core_ctx,
4180 bindings_ctx,
4181 device,
4182 frame_dst,
4183 packet,
4184 packet_metadata,
4185 meta,
4186 )
4187 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4188 }
4189 Ipv6PacketAction::ProcessFragment => {
4190 debug!("receive_ipv6_packet: found fragment header after reassembly; dropping");
4191 packet_metadata.acknowledge_drop();
4192 }
4193 }
4194 }
4195 ReceivePacketAction::Forward {
4196 original_dst,
4197 dst: Destination { device: dst_device, next_hop },
4198 } => {
4199 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4200 core_ctx,
4201 packet,
4202 packet_metadata,
4203 None,
4204 device,
4205 &dst_device,
4206 IpPacketDestination::from_next_hop(next_hop, original_dst),
4207 frame_dst,
4208 src_ip,
4209 original_dst,
4210 )
4211 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
4212 }
4213 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
4214 core_ctx.increment_both(device, |c| &c.no_route_to_host);
4215 let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
4216 drop_packet_and_undo_parse!(packet, buffer);
4217 debug!("received IPv6 packet with no known route to destination {}", dst_ip);
4218 let marks = packet_metadata.marks;
4219 packet_metadata.acknowledge_drop();
4220
4221 let src_ip = match src_ip {
4222 Ipv6SourceAddr::Unspecified => {
4223 core_ctx.increment_both(device, |c| &c.unspecified_source);
4224 return;
4225 }
4226 Ipv6SourceAddr::Unicast(src_ip) => {
4227 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
4228 }
4229 };
4230
4231 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
4232 core_ctx,
4233 bindings_ctx,
4234 Some(device),
4235 frame_dst,
4236 src_ip,
4237 SocketIpAddr::new_from_witness(dst_ip),
4238 buffer,
4239 Icmpv6Error::NetUnreachable,
4240 meta.header_len(),
4241 proto,
4242 &marks,
4243 );
4244 }
4245 ReceivePacketAction::Drop { reason } => {
4246 core_ctx.increment_both(device, |c| &c.dropped);
4247 let src_ip = packet.src_ip();
4248 let dst_ip = packet.dst_ip();
4249 packet_metadata.acknowledge_drop();
4250 debug!(
4251 "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
4252 {device:?}: {reason:?}",
4253 );
4254 }
4255 }
4256}
4257
4258#[derive(Debug, PartialEq)]
4260pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
4261 Deliver {
4263 address_status: I::AddressStatus,
4265 internal_forwarding: InternalForwarding<DeviceId>,
4268 },
4269
4270 Forward {
4272 original_dst: SpecifiedAddr<I::Addr>,
4274 dst: Destination<I::Addr, DeviceId>,
4276 },
4277
4278 MulticastForward {
4286 targets: MulticastRouteTargets<DeviceId>,
4288 address_status: Option<I::AddressStatus>,
4291 dst_ip: SpecifiedAddr<I::Addr>,
4293 },
4294
4295 SendNoRouteToDest {
4301 dst: NonMappedAddr<SpecifiedAddr<I::Addr>>,
4303 },
4304
4305 #[allow(missing_docs)]
4309 Drop { reason: DropReason },
4310}
4311
4312fn choose_highest_priority_address_status<I: IpLayerIpExt>(
4315 address_statuses: impl Iterator<Item = I::AddressStatus>,
4316) -> Option<I::AddressStatus> {
4317 address_statuses.max_by_key(|status| {
4318 #[derive(GenericOverIp)]
4319 #[generic_over_ip(I, Ip)]
4320 struct Wrap<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
4321 I::map_ip_in(
4322 Wrap(status),
4323 |Wrap(v4_status)| match v4_status {
4324 Ipv4PresentAddressStatus::UnicastTentative => 0,
4325 _ => 1,
4326 },
4327 |Wrap(v6_status)| match v6_status {
4328 Ipv6PresentAddressStatus::UnicastTentative => 0,
4329 _ => 1,
4330 },
4331 )
4332 })
4333}
4334
4335#[derive(Debug, PartialEq)]
4337pub enum DropReason {
4338 Tentative,
4340 UnspecifiedDestination,
4342 InvalidDestination,
4344 ForwardUnspecifiedSource,
4346 ForwardLinkLocal,
4348 ForwardingDisabledInboundIface,
4351 MulticastNoInterest,
4357}
4358
4359pub fn receive_ipv4_packet_action<BC, CC, B>(
4361 core_ctx: &mut CC,
4362 bindings_ctx: &mut BC,
4363 device: &CC::DeviceId,
4364 packet: &Ipv4Packet<B>,
4365 frame_dst: Option<FrameDestination>,
4366 marks: &Marks,
4367) -> ReceivePacketAction<Ipv4, CC::DeviceId>
4368where
4369 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
4370 CC: IpLayerContext<Ipv4, BC>,
4371 B: SplitByteSlice,
4372{
4373 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4374 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4375 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4376 };
4377
4378 let highest_priority = if device.is_loopback() {
4391 core_ctx.with_address_statuses(dst_ip, |it| {
4392 let it = it.map(|(_device, status)| status);
4393 choose_highest_priority_address_status::<Ipv4>(it)
4394 })
4395 } else {
4396 core_ctx.address_status_for_device(dst_ip, device).into_present()
4397 };
4398 match highest_priority {
4399 Some(
4400 address_status @ (Ipv4PresentAddressStatus::UnicastAssigned
4401 | Ipv4PresentAddressStatus::LoopbackSubnet),
4402 ) => {
4403 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4404 ReceivePacketAction::Deliver {
4405 address_status,
4406 internal_forwarding: InternalForwarding::NotUsed,
4407 }
4408 }
4409 Some(Ipv4PresentAddressStatus::UnicastTentative) => {
4410 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4416 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4417 }
4418
4419 Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4420 receive_ip_multicast_packet_action(
4421 core_ctx,
4422 bindings_ctx,
4423 device,
4424 packet,
4425 Some(address_status),
4426 dst_ip,
4427 frame_dst,
4428 )
4429 }
4430 Some(
4431 address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4432 | Ipv4PresentAddressStatus::SubnetBroadcast),
4433 ) => {
4434 core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
4435 ReceivePacketAction::Deliver {
4436 address_status,
4437 internal_forwarding: InternalForwarding::NotUsed,
4438 }
4439 }
4440 None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4441 core_ctx,
4442 bindings_ctx,
4443 dst_ip,
4444 device,
4445 packet,
4446 frame_dst,
4447 marks,
4448 ),
4449 }
4450}
4451
4452pub fn receive_ipv6_packet_action<BC, CC, B>(
4454 core_ctx: &mut CC,
4455 bindings_ctx: &mut BC,
4456 device: &CC::DeviceId,
4457 packet: &Ipv6Packet<B>,
4458 frame_dst: Option<FrameDestination>,
4459 marks: &Marks,
4460) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4461where
4462 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4463 CC: IpLayerContext<Ipv6, BC>,
4464 B: SplitByteSlice,
4465{
4466 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4467 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4468 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4469 };
4470
4471 let highest_priority = if device.is_loopback() {
4484 core_ctx.with_address_statuses(dst_ip, |it| {
4485 let it = it.map(|(_device, status)| status);
4486 choose_highest_priority_address_status::<Ipv6>(it)
4487 })
4488 } else {
4489 core_ctx.address_status_for_device(dst_ip, device).into_present()
4490 };
4491 match highest_priority {
4492 Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
4493 receive_ip_multicast_packet_action(
4494 core_ctx,
4495 bindings_ctx,
4496 device,
4497 packet,
4498 Some(address_status),
4499 dst_ip,
4500 frame_dst,
4501 )
4502 }
4503 Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
4504 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4505 ReceivePacketAction::Deliver {
4506 address_status,
4507 internal_forwarding: InternalForwarding::NotUsed,
4508 }
4509 }
4510 Some(Ipv6PresentAddressStatus::UnicastTentative) => {
4511 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4542 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4543 }
4544 None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
4545 core_ctx,
4546 bindings_ctx,
4547 dst_ip,
4548 device,
4549 packet,
4550 frame_dst,
4551 marks,
4552 ),
4553 }
4554}
4555
4556fn receive_ip_multicast_packet_action<
4559 I: IpLayerIpExt,
4560 B: SplitByteSlice,
4561 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4562 CC: IpLayerContext<I, BC>,
4563>(
4564 core_ctx: &mut CC,
4565 bindings_ctx: &mut BC,
4566 device: &CC::DeviceId,
4567 packet: &I::Packet<B>,
4568 address_status: Option<I::AddressStatus>,
4569 dst_ip: SpecifiedAddr<I::Addr>,
4570 frame_dst: Option<FrameDestination>,
4571) -> ReceivePacketAction<I, CC::DeviceId> {
4572 let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
4573 core_ctx,
4574 bindings_ctx,
4575 packet,
4576 device,
4577 frame_dst,
4578 );
4579 match (targets, address_status) {
4580 (Some(targets), address_status) => {
4581 if address_status.is_some() {
4582 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4583 }
4584 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
4585 }
4586 (None, Some(address_status)) => {
4587 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4590 ReceivePacketAction::Deliver {
4591 address_status,
4592 internal_forwarding: InternalForwarding::NotUsed,
4593 }
4594 }
4595 (None, None) => {
4596 core_ctx.increment_both(device, |c| &c.multicast_no_interest);
4605 ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
4606 }
4607 }
4608}
4609
4610fn receive_ip_packet_action_common<
4613 I: IpLayerIpExt,
4614 B: SplitByteSlice,
4615 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4616 CC: IpLayerContext<I, BC>,
4617>(
4618 core_ctx: &mut CC,
4619 bindings_ctx: &mut BC,
4620 dst_ip: SpecifiedAddr<I::Addr>,
4621 device_id: &CC::DeviceId,
4622 packet: &I::Packet<B>,
4623 frame_dst: Option<FrameDestination>,
4624 marks: &Marks,
4625) -> ReceivePacketAction<I, CC::DeviceId> {
4626 if dst_ip.is_multicast() {
4627 return receive_ip_multicast_packet_action(
4628 core_ctx,
4629 bindings_ctx,
4630 device_id,
4631 packet,
4632 None,
4633 dst_ip,
4634 frame_dst,
4635 );
4636 }
4637
4638 let Some(dst_ip) = NonMappedAddr::new(dst_ip) else {
4640 return ReceivePacketAction::Drop { reason: DropReason::InvalidDestination };
4641 };
4642
4643 if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
4645 core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
4658 return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
4659 }
4660 let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
4667 return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
4668 };
4669
4670 if let Some(dst_ip) = NonMulticastAddr::new(dst_ip) {
4677 if let Some((outbound_device, address_status)) =
4678 get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
4679 {
4680 return ReceivePacketAction::Deliver {
4681 address_status,
4682 internal_forwarding: InternalForwarding::Used(outbound_device),
4683 };
4684 }
4685 }
4686
4687 if I::map_ip_in(
4702 &packet,
4703 |_| false,
4704 |packet| packet.src_ip().is_link_local() || packet.dst_ip().is_link_local(),
4705 ) {
4706 return ReceivePacketAction::Drop { reason: DropReason::ForwardLinkLocal };
4707 }
4708
4709 match lookup_route_table(
4710 core_ctx,
4711 dst_ip.get(),
4712 RuleInput {
4713 packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
4714 marks,
4715 },
4716 ) {
4717 Some(dst) => {
4718 core_ctx.increment_both(device_id, |c| &c.forward);
4719 ReceivePacketAction::Forward { original_dst: *dst_ip, dst }
4720 }
4721 None => {
4722 core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
4723 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
4724 }
4725 }
4726}
4727
4728fn lookup_route_table<
4730 I: IpLayerIpExt,
4731 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4732 CC: IpStateContext<I, BC>,
4733>(
4734 core_ctx: &mut CC,
4735 dst_ip: I::Addr,
4736 rule_input: RuleInput<'_, I, CC::DeviceId>,
4737) -> Option<Destination<I::Addr, CC::DeviceId>> {
4738 let bound_device = match rule_input.packet_origin {
4739 PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
4740 PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
4741 };
4742 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
4743 match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
4744 match table.lookup(core_ctx, bound_device, dst_ip) {
4745 Some(dst) => ControlFlow::Break(Some(dst)),
4746 None => ControlFlow::Continue(()),
4747 }
4748 }) {
4749 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
4750 inner: dst,
4751 observed_source_address_matcher: _,
4752 })) => dst,
4753 ControlFlow::Break(RuleAction::Unreachable) => None,
4754 ControlFlow::Continue(RuleWalkInfo {
4755 inner: (),
4756 observed_source_address_matcher: _,
4757 }) => None,
4758 }
4759 })
4760}
4761
4762#[derive(Debug, Derivative, Clone)]
4764#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
4765pub enum IpPacketDestination<I: BroadcastIpExt, D> {
4766 Broadcast(I::BroadcastMarker),
4768
4769 Multicast(MulticastAddr<I::Addr>),
4771
4772 Neighbor(SpecifiedAddr<I::Addr>),
4775
4776 Loopback(D),
4779}
4780
4781impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
4782 pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
4784 match MulticastAddr::new(addr.into_addr()) {
4785 Some(mc_addr) => Self::Multicast(mc_addr),
4786 None => Self::Neighbor(addr),
4787 }
4788 }
4789
4790 pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
4792 match next_hop {
4793 NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
4794 NextHop::Gateway(gateway) => Self::Neighbor(gateway),
4795 NextHop::Broadcast(marker) => Self::Broadcast(marker),
4796 }
4797 }
4798}
4799
4800#[derive(Debug, Clone)]
4802pub struct SendIpPacketMeta<I: IpExt, D, Src> {
4803 pub device: D,
4805
4806 pub src_ip: Src,
4808
4809 pub dst_ip: SpecifiedAddr<I::Addr>,
4811
4812 pub destination: IpPacketDestination<I, D>,
4814
4815 pub proto: I::Proto,
4817
4818 pub ttl: Option<NonZeroU8>,
4822
4823 pub mtu: Mtu,
4828
4829 pub dscp_and_ecn: DscpAndEcn,
4831}
4832
4833impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4834 for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
4835{
4836 fn from(
4837 SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
4838 I,
4839 D,
4840 SpecifiedAddr<I::Addr>,
4841 >,
4842 ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
4843 SendIpPacketMeta {
4844 device,
4845 src_ip: Some(src_ip),
4846 dst_ip,
4847 destination,
4848 proto,
4849 ttl,
4850 mtu,
4851 dscp_and_ecn,
4852 }
4853 }
4854}
4855
4856pub trait IpLayerHandler<I: IpExt + FragmentationIpExt + FilterIpExt, BC>:
4862 DeviceIdContext<AnyDevice>
4863{
4864 fn send_ip_packet_from_device<S>(
4867 &mut self,
4868 bindings_ctx: &mut BC,
4869 meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4870 body: S,
4871 ) -> Result<(), IpSendFrameError<S>>
4872 where
4873 S: TransportPacketSerializer<I>,
4874 S::Buffer: BufferMut;
4875
4876 fn send_ip_frame<S>(
4883 &mut self,
4884 bindings_ctx: &mut BC,
4885 device: &Self::DeviceId,
4886 destination: IpPacketDestination<I, &Self::DeviceId>,
4887 body: S,
4888 ) -> Result<(), IpSendFrameError<S>>
4889 where
4890 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>;
4891}
4892
4893impl<
4894 I: IpLayerIpExt,
4895 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
4896 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4897> IpLayerHandler<I, BC> for CC
4898{
4899 fn send_ip_packet_from_device<S>(
4900 &mut self,
4901 bindings_ctx: &mut BC,
4902 meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4903 body: S,
4904 ) -> Result<(), IpSendFrameError<S>>
4905 where
4906 S: TransportPacketSerializer<I>,
4907 S::Buffer: BufferMut,
4908 {
4909 send_ip_packet_from_device(self, bindings_ctx, meta, body, IpLayerPacketMetadata::default())
4910 }
4911
4912 fn send_ip_frame<S>(
4913 &mut self,
4914 bindings_ctx: &mut BC,
4915 device: &Self::DeviceId,
4916 destination: IpPacketDestination<I, &Self::DeviceId>,
4917 body: S,
4918 ) -> Result<(), IpSendFrameError<S>>
4919 where
4920 S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>,
4921 {
4922 send_ip_frame(
4923 self,
4924 bindings_ctx,
4925 device,
4926 destination,
4927 body,
4928 IpLayerPacketMetadata::default(),
4929 Mtu::no_limit(),
4930 )
4931 }
4932}
4933
4934pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
4941 core_ctx: &mut CC,
4942 bindings_ctx: &mut BC,
4943 meta: SendIpPacketMeta<
4944 I,
4945 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
4946 Option<SpecifiedAddr<I::Addr>>,
4947 >,
4948 body: S,
4949 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
4950) -> Result<(), IpSendFrameError<S>>
4951where
4952 I: IpLayerIpExt,
4953 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
4954 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4955 S: TransportPacketSerializer<I>,
4956 S::Buffer: BufferMut,
4957{
4958 let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
4959 meta;
4960 core_ctx.increment_both(device, |c| &c.send_ip_packet);
4961 let next_packet_id = gen_ip_packet_id(core_ctx);
4962 let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
4963 let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
4964 let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
4965
4966 #[derive(GenericOverIp)]
4967 #[generic_over_ip(I, Ip)]
4968 struct Wrap<'a, I: IpLayerIpExt> {
4969 builder: &'a mut I::PacketBuilder,
4970 next_packet_id: I::PacketId,
4971 }
4972
4973 I::map_ip::<_, ()>(
4974 Wrap { builder: &mut builder, next_packet_id },
4975 |Wrap { builder, next_packet_id }| {
4976 builder.id(next_packet_id);
4977 },
4978 |Wrap { builder: _, next_packet_id: () }| {
4979 },
4981 );
4982
4983 builder.set_dscp_and_ecn(dscp_and_ecn);
4984
4985 let ip_frame = builder.wrap_body(body);
4986 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
4987 .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
4988}
4989
4990pub trait FilterHandlerProvider<I: FilterIpExt, BT: FilterBindingsTypes>:
4992 IpDeviceAddressIdContext<I, DeviceId: netstack3_base::InterfaceProperties<BT::DeviceClass>>
4993{
4994 type Handler<'a>: filter::FilterHandler<I, BT, DeviceId = Self::DeviceId, WeakAddressId = Self::WeakAddressId>
4996 where
4997 Self: 'a;
4998
4999 fn filter_handler(&mut self) -> Self::Handler<'_>;
5001}
5002
5003#[cfg(any(test, feature = "testutils"))]
5004pub(crate) mod testutil {
5005 use super::*;
5006
5007 use netstack3_base::testutil::{FakeBindingsCtx, FakeCoreCtx, FakeStrongDeviceId};
5008 use netstack3_base::{AssignedAddrIpExt, SendFrameContext, SendFrameError, SendableFrameMeta};
5009 use packet::Serializer;
5010
5011 #[derive(Debug, GenericOverIp)]
5013 #[generic_over_ip()]
5014 #[allow(missing_docs)]
5015 pub enum DualStackSendIpPacketMeta<D> {
5016 V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
5017 V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
5018 }
5019
5020 impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5021 for DualStackSendIpPacketMeta<D>
5022 {
5023 fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
5024 #[derive(GenericOverIp)]
5025 #[generic_over_ip(I, Ip)]
5026 struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
5027 use DualStackSendIpPacketMeta::*;
5028 I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
5029 }
5030 }
5031
5032 impl<I: IpExt, S, DeviceId, BC>
5033 SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
5034 for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
5035 {
5036 fn send_meta<SS>(
5037 self,
5038 core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
5039 bindings_ctx: &mut BC,
5040 frame: SS,
5041 ) -> Result<(), SendFrameError<SS>>
5042 where
5043 SS: Serializer,
5044 SS::Buffer: BufferMut,
5045 {
5046 SendFrameContext::send_frame(
5047 &mut core_ctx.frames,
5048 bindings_ctx,
5049 DualStackSendIpPacketMeta::from(self),
5050 frame,
5051 )
5052 }
5053 }
5054
5055 #[derive(Debug)]
5057 pub struct WrongIpVersion;
5058
5059 impl<D> DualStackSendIpPacketMeta<D> {
5060 pub fn try_as<I: IpExt>(
5063 &self,
5064 ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
5065 #[derive(GenericOverIp)]
5066 #[generic_over_ip(I, Ip)]
5067 struct Wrap<'a, I: IpExt, D>(
5068 Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
5069 );
5070 use DualStackSendIpPacketMeta::*;
5071 let Wrap(dual_stack) = I::map_ip(
5072 self,
5073 |value| {
5074 Wrap(match value {
5075 V4(meta) => Some(meta),
5076 V6(_) => None,
5077 })
5078 },
5079 |value| {
5080 Wrap(match value {
5081 V4(_) => None,
5082 V6(meta) => Some(meta),
5083 })
5084 },
5085 );
5086 dual_stack.ok_or(WrongIpVersion)
5087 }
5088 }
5089
5090 impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
5091 where
5092 I: AssignedAddrIpExt + FilterIpExt,
5093 BC: FilterBindingsContext<DeviceId>,
5094 DeviceId: FakeStrongDeviceId + netstack3_base::InterfaceProperties<BC::DeviceClass>,
5095 {
5096 type Handler<'a>
5097 = filter::testutil::NoopImpl<DeviceId>
5098 where
5099 Self: 'a;
5100
5101 fn filter_handler(&mut self) -> Self::Handler<'_> {
5102 filter::testutil::NoopImpl::default()
5103 }
5104 }
5105
5106 impl<TimerId, Event: Debug, State, FrameMeta> MarksBindingsContext
5107 for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
5108 {
5109 fn marks_to_keep_on_egress() -> &'static [MarkDomain] {
5110 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark1];
5111 &MARKS
5112 }
5113
5114 fn marks_to_set_on_ingress() -> &'static [MarkDomain] {
5115 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark2];
5116 &MARKS
5117 }
5118 }
5119}
5120
5121#[cfg(test)]
5122mod test {
5123 use super::*;
5124
5125 #[test]
5126 fn highest_priority_address_status_v4() {
5127 assert_eq!(
5129 choose_highest_priority_address_status::<Ipv4>(
5130 [
5131 Ipv4PresentAddressStatus::UnicastAssigned,
5132 Ipv4PresentAddressStatus::UnicastTentative
5133 ]
5134 .into_iter()
5135 ),
5136 Some(Ipv4PresentAddressStatus::UnicastAssigned)
5137 )
5138 }
5139
5140 #[test]
5141 fn highest_priority_address_status_v6() {
5142 assert_eq!(
5144 choose_highest_priority_address_status::<Ipv6>(
5145 [
5146 Ipv6PresentAddressStatus::UnicastAssigned,
5147 Ipv6PresentAddressStatus::UnicastTentative
5148 ]
5149 .into_iter()
5150 ),
5151 Some(Ipv6PresentAddressStatus::UnicastAssigned)
5152 )
5153 }
5154}