1use alloc::boxed::Box;
6use alloc::vec::Vec;
7use core::fmt::Debug;
8use core::hash::Hash;
9use core::marker::PhantomData;
10use core::num::NonZeroU8;
11use core::ops::ControlFlow;
12#[cfg(test)]
13use core::ops::DerefMut;
14use core::sync::atomic::{self, AtomicU16};
15
16use derivative::Derivative;
17use explicit::ResultExt as _;
18use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
19use log::{debug, error, trace};
20use net_types::ip::{
21 GenericOverIp, Ip, IpVersion, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu, Subnet,
22};
23use net_types::{
24 LinkLocalAddress, MulticastAddr, MulticastAddress, NonMappedAddr, NonMulticastAddr,
25 SpecifiedAddr, SpecifiedAddress as _, Witness,
26};
27use netstack3_base::socket::{EitherStack, SocketIpAddr, SocketIpAddrExt as _};
28use netstack3_base::sync::{Mutex, PrimaryRc, RwLock, StrongRc, WeakRc};
29use netstack3_base::{
30 AnyDevice, BroadcastIpExt, CoreTimerContext, Counter, CounterCollectionSpec, CounterContext,
31 DeviceIdContext, DeviceIdentifier as _, ErrorAndSerializer, EventContext, GsoInfo,
32 HandleableTimer, InstantContext, InterfaceProperties, IpAddressId, IpDeviceAddr,
33 IpDeviceAddressIdContext, IpExt, LocalFrameDestination, MarkDomain, Marks, Matcher as _,
34 MatcherBindingsTypes, NestedIntoCoreTimerCtx, NetworkParsingContext,
35 NetworkSerializationContext, NotFoundError, PacketType, 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 _, ProofOfEgressCheck, RejectType, SocketInfo,
44 TransportPacketSerializer, Tuple, WeakConnectionError, WeakConntrackConnection,
45};
46use netstack3_hashmap::HashMap;
47use packet::{
48 Buf, BufferMut, GrowBuffer, LayoutBufferAlloc, NestablePacketBuilder as _, PacketConstraints,
49 ParsablePacket as _, ParseBuffer, ParseBufferMut, ParseMetadata, SerializeError,
50 Serializer as _,
51};
52use packet_formats::error::{Ipv6ParseError, ParseError};
53use packet_formats::ip::{DscpAndEcn, IpPacket as _, IpPacketBuilder as _};
54use packet_formats::ipv4::{Ipv4FragmentType, Ipv4Packet};
55use packet_formats::ipv6::ext_hdrs::Ipv6ExtensionHeader;
56use packet_formats::ipv6::{Ipv6Packet, Ipv6PacketRaw};
57use thiserror::Error;
58use zerocopy::SplitByteSlice;
59
60use crate::internal::counters::{IpCounters, IpCountersIpExt};
61use crate::internal::device::opaque_iid::IidSecret;
62use crate::internal::device::slaac::SlaacCounters;
63use crate::internal::device::state::{
64 IpAddressData, IpAddressFlags, IpDeviceStateBindingsTypes, IpDeviceStateIpExt, WeakAddressId,
65};
66use crate::internal::device::{
67 self, IpDeviceAddressContext, IpDeviceBindingsContext, IpDeviceIpExt, IpDeviceSendContext,
68};
69use crate::internal::fragmentation::{FragmentableIpSerializer, FragmentationIpExt, IpFragmenter};
70use crate::internal::gmp::GmpQueryHandler;
71use crate::internal::gmp::igmp::IgmpCounters;
72use crate::internal::gmp::mld::MldCounters;
73use crate::internal::gso::{
74 GsoError, GsoIpExt, MaybeSegmentableIpSerializer, MaybeSegmentableTransportSerializer,
75};
76use crate::internal::icmp::counters::IcmpCountersIpExt;
77use crate::internal::icmp::{
78 IcmpBindingsTypes, IcmpError, IcmpErrorHandler, IcmpHandlerIpExt, Icmpv4Error, Icmpv4State,
79 Icmpv4StateBuilder, Icmpv6Error, Icmpv6State, Icmpv6StateBuilder,
80};
81use crate::internal::ipv6::Ipv6PacketAction;
82use crate::internal::local_delivery::{
83 IpHeaderInfo, Ipv4HeaderInfo, Ipv6HeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta,
84 TransparentLocalDelivery,
85};
86use crate::internal::multicast_forwarding::counters::MulticastForwardingCounters;
87use crate::internal::multicast_forwarding::route::{
88 MulticastRouteIpExt, MulticastRouteTarget, MulticastRouteTargets,
89};
90use crate::internal::multicast_forwarding::state::{
91 MulticastForwardingState, MulticastForwardingStateContext,
92};
93use crate::internal::multicast_forwarding::{
94 MulticastForwardingBindingsTypes, MulticastForwardingDeviceContext, MulticastForwardingEvent,
95 MulticastForwardingTimerId,
96};
97use crate::internal::path_mtu::{PmtuBindingsTypes, PmtuCache, PmtuTimerId};
98use crate::internal::raw::counters::RawIpSocketCounters;
99use crate::internal::raw::{RawIpSocketHandler, RawIpSocketMap, RawIpSocketsBindingsTypes};
100use crate::internal::reassembly::{
101 FragmentBindingsTypes, FragmentHandler, FragmentProcessingState, FragmentTimerId,
102 FragmentablePacket, IpPacketFragmentCache, ReassemblyIpExt,
103};
104use crate::internal::routing::rules::{Rule, RuleAction, RuleInput, RulesTable};
105use crate::internal::routing::{
106 IpRoutingBindingsTypes, IpRoutingDeviceContext, NonLocalSrcAddrPolicy, PacketOrigin,
107 RoutingTable,
108};
109use crate::internal::socket::{IpSocketBindingsContext, IpSocketContext, IpSocketHandler};
110use crate::internal::types::{
111 self, Destination, InternalForwarding, NextHop, ResolvedRoute, RoutableIpAddr,
112};
113use crate::internal::{ipv6, multicast_forwarding};
114
115#[cfg(test)]
116mod tests;
117
118pub const DEFAULT_TTL: NonZeroU8 = NonZeroU8::new(64).unwrap();
120
121#[derive(Copy, Clone, Debug, Eq, PartialEq)]
123#[allow(missing_docs)]
124pub struct HopLimits {
125 pub unicast: NonZeroU8,
126 pub multicast: NonZeroU8,
127}
128
129pub const DEFAULT_HOP_LIMITS: HopLimits =
131 HopLimits { unicast: DEFAULT_TTL, multicast: NonZeroU8::new(1).unwrap() };
132
133pub const IPV6_DEFAULT_SUBNET: Subnet<Ipv6Addr> = Ipv6::ALL_ADDRS_SUBNET;
135
136pub struct IpLayerPacketMetadata<
142 I: packet_formats::ip::IpExt,
143 A,
144 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
145> {
146 conntrack_connection_and_direction:
147 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
148
149 tx_metadata: BT::TxMetadata,
154
155 marks: Marks,
157
158 socket_info: Option<SocketInfo>,
160
161 gso_info: Option<GsoInfo>,
168
169 packet_type: PacketType,
171
172 #[cfg(debug_assertions)]
173 drop_check: IpLayerPacketMetadataDropCheck,
174}
175
176#[cfg(debug_assertions)]
183#[derive(Default)]
184struct IpLayerPacketMetadataDropCheck {
185 okay_to_drop: bool,
186}
187
188#[derive(Derivative)]
191#[derivative(Debug(bound = ""))]
192pub struct DeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
193 conntrack_entry: Option<(WeakConntrackConnection, ConnectionDirection)>,
201 tx_metadata: BT::TxMetadata,
206 marks: Marks,
213 packet_type: PacketType,
217}
218
219pub(crate) struct SplitDeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
222 pub(crate) primary: DeviceIpLayerMetadata<BT>,
223 pub(crate) secondary: DeviceIpLayerMetadata<BT>,
224}
225
226impl<BT: TxMetadataBindingsTypes> DeviceIpLayerMetadata<BT> {
227 pub fn from_tx_metadata_and_marks(tx_metadata: BT::TxMetadata, marks: Marks) -> Self {
229 Self { conntrack_entry: None, tx_metadata, marks, packet_type: PacketType::Outgoing }
230 }
231
232 pub fn new_for_rx_packet(packet_type: PacketType) -> Self {
234 Self {
235 conntrack_entry: None,
236 tx_metadata: Default::default(),
237 marks: Default::default(),
238 packet_type,
239 }
240 }
241
242 #[cfg(any(test, feature = "testutils"))]
244 pub fn empty() -> Self {
245 Self {
246 conntrack_entry: None,
247 tx_metadata: Default::default(),
248 marks: Default::default(),
249 packet_type: PacketType::Host,
250 }
251 }
252
253 pub fn into_tx_metadata(self) -> BT::TxMetadata {
256 self.tx_metadata
257 }
258
259 #[cfg(any(test, feature = "testutils"))]
261 pub fn with_marks_and_packet_type(marks: Marks, packet_type: PacketType) -> Self {
262 Self { conntrack_entry: None, tx_metadata: Default::default(), marks, packet_type }
263 }
264
265 pub(crate) fn split_for_multiple_frames(self) -> SplitDeviceIpLayerMetadata<BT> {
274 let (primary_tx_metadata, secondary_tx_metadata) =
275 self.tx_metadata.split_for_multiple_frames();
276 let secondary = Self {
277 conntrack_entry: self.conntrack_entry.clone(),
278 tx_metadata: secondary_tx_metadata,
283 marks: self.marks,
284 packet_type: self.packet_type,
285 };
286 let primary = Self {
287 conntrack_entry: self.conntrack_entry,
288 tx_metadata: primary_tx_metadata,
289 marks: self.marks,
290 packet_type: self.packet_type,
291 };
292 SplitDeviceIpLayerMetadata { primary, secondary }
293 }
294
295 pub fn set_packet_type(&mut self, packet_type: PacketType) {
297 self.packet_type = packet_type;
298 }
299
300 pub fn packet_type(&self) -> PacketType {
302 self.packet_type
303 }
304}
305
306impl<
307 I: IpLayerIpExt,
308 A: WeakIpAddressId<I::Addr>,
309 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
310> IpLayerPacketMetadata<I, A, BT>
311{
312 pub(crate) fn from_device_ip_layer_metadata<CC, D>(
313 core_ctx: &mut CC,
314 device: &D,
315 metadata: DeviceIpLayerMetadata<BT>,
316 gso_info: Option<GsoInfo>,
317 ) -> Self
318 where
319 CC: ResourceCounterContext<D, IpCounters<I>>,
320 {
321 let DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks, packet_type } = metadata;
322 let conntrack_connection_and_direction = match conntrack_entry
323 .map(|(conn, dir)| conn.into_inner().map(|conn| (conn, dir)))
324 .transpose()
325 {
326 Ok(conn_and_dir) => conn_and_dir,
329 Err(WeakConnectionError::EntryRemoved) => None,
331 Err(WeakConnectionError::InvalidEntry) => {
335 core_ctx.increment_both(device, |c| &c.invalid_cached_conntrack_entry);
336 None
337 }
338 };
339
340 Self {
341 conntrack_connection_and_direction,
342 tx_metadata,
343 marks,
344 socket_info: None,
348 gso_info,
349 packet_type,
350 #[cfg(debug_assertions)]
351 drop_check: Default::default(),
352 }
353 }
354}
355
356pub(crate) struct SplitMulticastPacketMetadata<I, A, BT>
359where
360 I: packet_formats::ip::IpExt,
361 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
362{
363 pub(crate) primary: IpLayerPacketMetadata<I, A, BT>,
364 pub(crate) secondary: IpLayerPacketMetadata<I, A, BT>,
365}
366
367impl<I: IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
368 IpLayerPacketMetadata<I, A, BT>
369{
370 pub(crate) fn split_for_multicast(self) -> SplitMulticastPacketMetadata<I, A, BT> {
378 let secondary = Self {
379 conntrack_connection_and_direction: None,
380 tx_metadata: Default::default(),
381 marks: self.marks,
382 socket_info: self.socket_info.clone(),
383 gso_info: self.gso_info,
384 packet_type: self.packet_type,
385 #[cfg(debug_assertions)]
386 drop_check: Default::default(),
387 };
388 SplitMulticastPacketMetadata { primary: self, secondary }
389 }
390
391 pub(crate) fn new_local_tx(
392 tx_metadata: BT::TxMetadata,
393 marks: Marks,
394 gso_info: Option<GsoInfo>,
395 ) -> Self {
396 let socket_info = tx_metadata.socket_info();
397 Self {
398 conntrack_connection_and_direction: None,
399 tx_metadata,
400 marks,
401 socket_info,
402 gso_info,
403 packet_type: PacketType::Outgoing,
404 #[cfg(debug_assertions)]
405 drop_check: Default::default(),
406 }
407 }
408
409 #[cfg(any(test, feature = "testutils"))]
411 pub fn new_empty() -> Self {
412 Self::new_local_tx(Default::default(), Default::default(), None)
413 }
414
415 pub(crate) fn into_parts(
416 self,
417 ) -> (
418 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
419 BT::TxMetadata,
420 Marks,
421 Option<SocketInfo>,
422 Option<GsoInfo>,
423 PacketType,
424 ) {
425 let Self {
426 tx_metadata,
427 marks,
428 conntrack_connection_and_direction,
429 socket_info,
430 gso_info,
431 packet_type,
432 #[cfg(debug_assertions)]
433 mut drop_check,
434 } = self;
435 #[cfg(debug_assertions)]
436 {
437 drop_check.okay_to_drop = true;
438 }
439 (conntrack_connection_and_direction, tx_metadata, marks, socket_info, gso_info, packet_type)
440 }
441
442 pub(crate) fn acknowledge_drop(self) {
447 #[cfg(debug_assertions)]
448 {
449 let mut this = self;
450 this.drop_check.okay_to_drop = true;
451 }
452 }
453
454 pub(crate) fn tx_metadata(&self) -> &BT::TxMetadata {
456 &self.tx_metadata
457 }
458
459 pub(crate) fn marks(&self) -> &Marks {
461 &self.marks
462 }
463
464 pub(crate) fn gso_info(&self) -> Option<GsoInfo> {
466 self.gso_info
467 }
468
469 pub fn set_packet_type(&mut self, packet_type: PacketType) {
471 self.packet_type = packet_type;
472 }
473}
474
475#[cfg(debug_assertions)]
476impl Drop for IpLayerPacketMetadataDropCheck {
477 fn drop(&mut self) {
478 if !self.okay_to_drop {
479 panic!(
480 "IpLayerPacketMetadata dropped without acknowledgement. https://fxbug.dev/334127474"
481 );
482 }
483 }
484}
485
486impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
487 FilterIpMetadata<I, A, BT> for IpLayerPacketMetadata<I, A, BT>
488{
489 fn take_connection_and_direction(
490 &mut self,
491 ) -> Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)> {
492 self.conntrack_connection_and_direction.take()
493 }
494
495 fn replace_connection_and_direction(
496 &mut self,
497 conn: ConntrackConnection<I, A, BT>,
498 direction: ConnectionDirection,
499 ) -> Option<ConntrackConnection<I, A, BT>> {
500 self.conntrack_connection_and_direction.replace((conn, direction)).map(|(conn, _dir)| conn)
501 }
502}
503
504impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
505 FilterPacketMetadata for IpLayerPacketMetadata<I, A, BT>
506{
507 fn apply_mark_action(&mut self, domain: MarkDomain, action: MarkAction) {
508 action.apply(self.marks.get_mut(domain))
509 }
510
511 fn socket_info(&self) -> Option<SocketInfo> {
512 self.socket_info.clone()
513 }
514
515 fn marks(&self) -> &Marks {
516 &self.marks
517 }
518
519 fn packet_type(&self) -> PacketType {
520 self.packet_type
521 }
522
523 fn gso_info(&self) -> Option<GsoInfo> {
524 self.gso_info
525 }
526}
527
528pub type IpSendFrameError<S> = ErrorAndSerializer<IpSendFrameErrorReason, S>;
530
531#[derive(Debug, PartialEq)]
533pub enum IpSendFrameErrorReason {
534 Device(SendFrameErrorReason),
536 IllegalLoopbackAddress,
539}
540
541impl From<SendFrameErrorReason> for IpSendFrameErrorReason {
542 fn from(value: SendFrameErrorReason) -> Self {
543 Self::Device(value)
544 }
545}
546
547pub trait IpTransportContext<I, BC, CC>
553where
554 I: IpLayerIpExt,
555 CC: DeviceIdContext<AnyDevice> + ?Sized,
556{
557 type EarlyDemuxSocket;
559
560 fn early_demux<B: ParseBuffer>(
571 core_ctx: &mut CC,
572 device: &CC::DeviceId,
573 src_ip: I::Addr,
574 dst_ip: I::Addr,
575 buffer: B,
576 ) -> Option<Self::EarlyDemuxSocket>;
577
578 fn receive_icmp_error(
592 core_ctx: &mut CC,
593 bindings_ctx: &mut BC,
594 device: &CC::DeviceId,
595 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
596 original_dst_ip: SpecifiedAddr<I::Addr>,
597 original_body: &[u8],
598 err: I::ErrorCode,
599 );
600
601 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
607 core_ctx: &mut CC,
608 bindings_ctx: &mut BC,
609 device: &CC::DeviceId,
610 src_ip: I::RecvSrcAddr,
611 dst_ip: SpecifiedAddr<I::Addr>,
612 buffer: B,
613 info: &mut LocalDeliveryPacketInfo<I, H>,
614 early_demux_socket: Option<Self::EarlyDemuxSocket>,
615 ) -> Result<(), (B, I::IcmpError)>;
616}
617
618pub trait BaseTransportIpContext<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
621 type DevicesWithAddrIter<'s>: Iterator<Item = Self::DeviceId>;
624
625 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
631 &mut self,
632 addr: SpecifiedAddr<I::Addr>,
633 cb: F,
634 ) -> O;
635
636 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits;
641
642 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)>;
646}
647
648pub trait TransportIpContext<I: IpExt + FilterIpExt, BC: TxMetadataBindingsTypes>:
651 BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>
652{
653}
654
655impl<I, CC, BC> TransportIpContext<I, BC> for CC
656where
657 I: IpExt + FilterIpExt,
658 CC: BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>,
659 BC: TxMetadataBindingsTypes,
660{
661}
662
663pub trait MulticastMembershipHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
665 fn join_multicast_group(
672 &mut self,
673 bindings_ctx: &mut BC,
674 device: &Self::DeviceId,
675 addr: MulticastAddr<I::Addr>,
676 );
677
678 fn leave_multicast_group(
686 &mut self,
687 bindings_ctx: &mut BC,
688 device: &Self::DeviceId,
689 addr: MulticastAddr<I::Addr>,
690 );
691
692 fn select_device_for_multicast_group(
697 &mut self,
698 addr: MulticastAddr<I::Addr>,
699 marks: &Marks,
700 ) -> Result<Self::DeviceId, ResolveRouteError>;
701}
702
703pub trait UseTransportIpContextBlanket {}
715
716pub struct AssignedAddressDeviceIterator<Iter, I, D>(Iter, PhantomData<(I, D)>);
719
720impl<Iter, I, D> Iterator for AssignedAddressDeviceIterator<Iter, I, D>
721where
722 Iter: Iterator<Item = (D, I::AddressStatus)>,
723 I: IpLayerIpExt,
724{
725 type Item = D;
726 fn next(&mut self) -> Option<D> {
727 let Self(iter, PhantomData) = self;
728 iter.by_ref().find_map(|(device, state)| is_unicast_assigned::<I>(&state).then_some(device))
729 }
730}
731
732impl<
733 I: IpLayerIpExt,
734 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + IpRoutingBindingsTypes,
735 CC: IpDeviceContext<I>
736 + IpSocketHandler<I, BC>
737 + IpStateContext<I, BC>
738 + FilterIpContext<I, BC>
739 + UseTransportIpContextBlanket,
740> BaseTransportIpContext<I, BC> for CC
741{
742 type DevicesWithAddrIter<'s> =
743 AssignedAddressDeviceIterator<CC::DeviceAndAddressStatusIter<'s>, I, CC::DeviceId>;
744
745 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
746 &mut self,
747 addr: SpecifiedAddr<I::Addr>,
748 cb: F,
749 ) -> O {
750 self.with_address_statuses(addr, |it| cb(AssignedAddressDeviceIterator(it, PhantomData)))
751 }
752
753 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
754 match device {
755 Some(device) => HopLimits {
756 unicast: IpDeviceEgressStateContext::<I>::get_hop_limit(self, device),
757 ..DEFAULT_HOP_LIMITS
758 },
759 None => DEFAULT_HOP_LIMITS,
760 }
761 }
762
763 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)> {
764 self.with_filter_state(|state| {
765 let conn = state.conntrack.get_connection(&tuple)?;
766
767 if !conn.destination_nat() {
768 return None;
769 }
770
771 let original = conn.original_tuple();
775 Some((original.dst_addr, original.transport.dst_port_or_id()))
776 })
777 }
778}
779
780#[derive(Debug, PartialEq)]
782#[allow(missing_docs)]
783pub enum AddressStatus<S> {
784 Present(S),
785 Unassigned,
786}
787
788impl<S> AddressStatus<S> {
789 fn into_present(self) -> Option<S> {
790 match self {
791 Self::Present(s) => Some(s),
792 Self::Unassigned => None,
793 }
794 }
795}
796
797impl AddressStatus<Ipv4PresentAddressStatus> {
798 pub fn from_context_addr_v4<
800 BC: IpDeviceStateBindingsTypes,
801 CC: device::IpDeviceStateContext<Ipv4, BC> + GmpQueryHandler<Ipv4, BC>,
802 >(
803 core_ctx: &mut CC,
804 device: &CC::DeviceId,
805 addr: SpecifiedAddr<Ipv4Addr>,
806 ) -> AddressStatus<Ipv4PresentAddressStatus> {
807 if addr.is_limited_broadcast() {
808 return AddressStatus::Present(Ipv4PresentAddressStatus::LimitedBroadcast);
809 }
810
811 if MulticastAddr::new(addr.get())
812 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
813 {
814 return AddressStatus::Present(Ipv4PresentAddressStatus::Multicast);
815 }
816
817 core_ctx.with_address_ids(device, |mut addrs, core_ctx| {
818 addrs
819 .find_map(|addr_id| {
820 let dev_addr = addr_id.addr_sub();
821 let (dev_addr, subnet) = dev_addr.addr_subnet();
822
823 if **dev_addr == addr {
824 let assigned = core_ctx.with_ip_address_data(
825 device,
826 &addr_id,
827 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| {
828 *assigned
829 },
830 );
831
832 if assigned {
833 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastAssigned))
834 } else {
835 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastTentative))
836 }
837 } else if addr.get() == subnet.broadcast() {
838 Some(AddressStatus::Present(Ipv4PresentAddressStatus::SubnetBroadcast))
839 } else if device.is_loopback() && subnet.contains(addr.as_ref()) {
840 Some(AddressStatus::Present(Ipv4PresentAddressStatus::LoopbackSubnet))
841 } else {
842 None
843 }
844 })
845 .unwrap_or(AddressStatus::Unassigned)
846 })
847 }
848}
849
850impl AddressStatus<Ipv6PresentAddressStatus> {
851 pub fn from_context_addr_v6<
853 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
854 CC: device::Ipv6DeviceContext<BC> + GmpQueryHandler<Ipv6, BC>,
855 >(
856 core_ctx: &mut CC,
857 device: &CC::DeviceId,
858 addr: SpecifiedAddr<Ipv6Addr>,
859 ) -> AddressStatus<Ipv6PresentAddressStatus> {
860 if MulticastAddr::new(addr.get())
861 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
862 {
863 return AddressStatus::Present(Ipv6PresentAddressStatus::Multicast);
864 }
865
866 let addr_id = match core_ctx.get_address_id(device, addr) {
867 Ok(o) => o,
868 Err(NotFoundError) => return AddressStatus::Unassigned,
869 };
870
871 let assigned = core_ctx.with_ip_address_data(
872 device,
873 &addr_id,
874 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
875 );
876
877 if assigned {
878 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned)
879 } else {
880 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastTentative)
881 }
882 }
883}
884
885impl<S: GenericOverIp<I>, I: Ip> GenericOverIp<I> for AddressStatus<S> {
886 type Type = AddressStatus<S::Type>;
887}
888
889#[derive(Debug, PartialEq)]
891#[allow(missing_docs)]
892pub enum Ipv4PresentAddressStatus {
893 LimitedBroadcast,
894 SubnetBroadcast,
895 Multicast,
896 UnicastAssigned,
897 UnicastTentative,
898 LoopbackSubnet,
909}
910
911impl Ipv4PresentAddressStatus {
912 fn to_broadcast_marker(&self) -> Option<<Ipv4 as BroadcastIpExt>::BroadcastMarker> {
913 match self {
914 Self::LimitedBroadcast | Self::SubnetBroadcast => Some(()),
915 Self::Multicast
916 | Self::UnicastAssigned
917 | Self::UnicastTentative
918 | Self::LoopbackSubnet => None,
919 }
920 }
921}
922
923#[derive(Debug, PartialEq)]
925#[allow(missing_docs)]
926pub enum Ipv6PresentAddressStatus {
927 Multicast,
928 UnicastAssigned,
929 UnicastTentative,
930}
931
932pub trait IpLayerIpExt:
934 IpExt
935 + MulticastRouteIpExt
936 + IcmpHandlerIpExt
937 + FilterIpExt
938 + FragmentationIpExt
939 + GsoIpExt
940 + IpDeviceIpExt
941 + IpCountersIpExt
942 + IcmpCountersIpExt
943 + ReassemblyIpExt
944{
945 type AddressStatus: Debug;
947 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>: AsRef<
949 IpStateInner<Self, StrongDeviceId, BT>,
950 >;
951 type PacketIdState;
953 type PacketId;
955 fn next_packet_id_from_state(state: &Self::PacketIdState) -> Self::PacketId;
957}
958
959impl IpLayerIpExt for Ipv4 {
960 type AddressStatus = Ipv4PresentAddressStatus;
961 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
962 Ipv4State<StrongDeviceId, BT>;
963 type PacketIdState = AtomicU16;
964 type PacketId = u16;
965 fn next_packet_id_from_state(next_packet_id: &Self::PacketIdState) -> Self::PacketId {
966 next_packet_id.fetch_add(1, atomic::Ordering::Relaxed)
970 }
971}
972
973impl IpLayerIpExt for Ipv6 {
974 type AddressStatus = Ipv6PresentAddressStatus;
975 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
976 Ipv6State<StrongDeviceId, BT>;
977 type PacketIdState = ();
978 type PacketId = ();
979 fn next_packet_id_from_state((): &Self::PacketIdState) -> Self::PacketId {
980 ()
981 }
982}
983
984pub trait IpStateContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes + MatcherBindingsTypes>:
986 IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>
987{
988 type IpRouteTablesCtx<'a>: IpRouteTablesContext<I, BT, DeviceId = Self::DeviceId>;
990
991 fn with_rules_table<
993 O,
994 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId, BT>) -> O,
995 >(
996 &mut self,
997 cb: F,
998 ) -> O;
999
1000 fn with_rules_table_mut<
1002 O,
1003 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId, BT>) -> O,
1004 >(
1005 &mut self,
1006 cb: F,
1007 ) -> O;
1008}
1009
1010pub trait IpRouteTablesContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
1012 IpRouteTableContext<I, BT> + IpDeviceContext<I>
1013{
1014 type Ctx<'a>: IpRouteTableContext<I, BT, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>;
1016
1017 fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId, BT>;
1019
1020 fn with_ip_routing_tables<
1022 O,
1023 F: FnOnce(
1024 &mut Self::Ctx<'_>,
1025 &HashMap<
1026 RoutingTableId<I, Self::DeviceId, BT>,
1027 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
1028 >,
1029 ) -> O,
1030 >(
1031 &mut self,
1032 cb: F,
1033 ) -> O;
1034
1035 fn with_ip_routing_tables_mut<
1037 O,
1038 F: FnOnce(
1039 &mut HashMap<
1040 RoutingTableId<I, Self::DeviceId, BT>,
1041 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
1042 >,
1043 ) -> O,
1044 >(
1045 &mut self,
1046 cb: F,
1047 ) -> O;
1048
1049 fn with_main_ip_routing_table<
1053 O,
1054 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
1055 >(
1056 &mut self,
1057 cb: F,
1058 ) -> O {
1059 let main_table_id = self.main_table_id();
1060 self.with_ip_routing_table(&main_table_id, cb)
1061 }
1062
1063 fn with_main_ip_routing_table_mut<
1067 O,
1068 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
1069 >(
1070 &mut self,
1071 cb: F,
1072 ) -> O {
1073 let main_table_id = self.main_table_id();
1074 self.with_ip_routing_table_mut(&main_table_id, cb)
1075 }
1076}
1077
1078pub trait IpRouteTableContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
1080 IpDeviceContext<I>
1081{
1082 type IpDeviceIdCtx<'a>: DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
1084 + IpRoutingDeviceContext<I>
1085 + IpDeviceContext<I>;
1086
1087 fn with_ip_routing_table<
1089 O,
1090 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
1091 >(
1092 &mut self,
1093 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
1094 cb: F,
1095 ) -> O;
1096
1097 fn with_ip_routing_table_mut<
1099 O,
1100 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
1101 >(
1102 &mut self,
1103 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
1104 cb: F,
1105 ) -> O;
1106}
1107
1108pub trait IpDeviceEgressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
1110 fn with_next_packet_id<O, F: FnOnce(&I::PacketIdState) -> O>(&self, cb: F) -> O;
1112
1113 fn get_local_addr_for_remote(
1115 &mut self,
1116 device_id: &Self::DeviceId,
1117 remote: Option<SpecifiedAddr<I::Addr>>,
1118 ) -> Option<IpDeviceAddr<I::Addr>>;
1119
1120 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8;
1122}
1123
1124pub trait IpDeviceIngressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
1126 fn address_status_for_device(
1132 &mut self,
1133 addr: SpecifiedAddr<I::Addr>,
1134 device_id: &Self::DeviceId,
1135 ) -> AddressStatus<I::AddressStatus>;
1136}
1137
1138pub trait IpDeviceContext<I: IpLayerIpExt>:
1140 IpDeviceEgressStateContext<I> + IpDeviceIngressStateContext<I>
1141{
1142 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
1144
1145 type DeviceAndAddressStatusIter<'a>: Iterator<Item = (Self::DeviceId, I::AddressStatus)>;
1147
1148 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
1154 &mut self,
1155 addr: SpecifiedAddr<I::Addr>,
1156 cb: F,
1157 ) -> R;
1158
1159 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
1161}
1162
1163pub trait IpDeviceConfirmReachableContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1165 fn confirm_reachable(
1168 &mut self,
1169 bindings_ctx: &mut BC,
1170 device: &Self::DeviceId,
1171 neighbor: SpecifiedAddr<I::Addr>,
1172 );
1173}
1174
1175pub trait IpDeviceMtuContext<I: Ip>: DeviceIdContext<AnyDevice> {
1177 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu;
1181}
1182
1183#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
1185#[generic_over_ip(I, Ip)]
1186pub enum IpLayerEvent<DeviceId, I: IpLayerIpExt> {
1187 AddRoute(types::AddableEntry<I::Addr, DeviceId>),
1189 RemoveRoutes {
1191 subnet: Subnet<I::Addr>,
1193 device: DeviceId,
1195 gateway: Option<SpecifiedAddr<I::Addr>>,
1197 },
1198 MulticastForwarding(MulticastForwardingEvent<I, DeviceId>),
1200}
1201
1202impl<DeviceId, I: IpLayerIpExt> From<MulticastForwardingEvent<I, DeviceId>>
1203 for IpLayerEvent<DeviceId, I>
1204{
1205 fn from(event: MulticastForwardingEvent<I, DeviceId>) -> IpLayerEvent<DeviceId, I> {
1206 IpLayerEvent::MulticastForwarding(event)
1207 }
1208}
1209
1210impl<DeviceId, I: IpLayerIpExt> IpLayerEvent<DeviceId, I> {
1211 pub fn map_device<N, F: Fn(DeviceId) -> N>(self, map: F) -> IpLayerEvent<N, I> {
1213 match self {
1214 IpLayerEvent::AddRoute(types::AddableEntry {
1215 subnet,
1216 device,
1217 gateway,
1218 metric,
1219 route_preference,
1220 }) => IpLayerEvent::AddRoute(types::AddableEntry {
1221 subnet,
1222 device: map(device),
1223 gateway,
1224 metric,
1225 route_preference,
1226 }),
1227 IpLayerEvent::RemoveRoutes { subnet, device, gateway } => {
1228 IpLayerEvent::RemoveRoutes { subnet, device: map(device), gateway }
1229 }
1230 IpLayerEvent::MulticastForwarding(e) => {
1231 IpLayerEvent::MulticastForwarding(e.map_device(map))
1232 }
1233 }
1234 }
1235}
1236
1237#[derive(Derivative, PartialEq, Eq, Clone, Hash)]
1239#[derivative(Debug)]
1240pub struct RouterAdvertisementEvent<D> {
1241 #[derivative(Debug = "ignore")]
1244 pub options_bytes: Box<[u8]>,
1245 pub source: net_types::ip::Ipv6Addr,
1247 pub device: D,
1249}
1250
1251impl<D> RouterAdvertisementEvent<D> {
1252 pub fn map_device<N, F: Fn(D) -> N>(self, map: F) -> RouterAdvertisementEvent<N> {
1254 let Self { options_bytes, source, device } = self;
1255 RouterAdvertisementEvent { options_bytes, source, device: map(device) }
1256 }
1257}
1258
1259pub trait NdpBindingsContext<DeviceId>: EventContext<RouterAdvertisementEvent<DeviceId>> {}
1261impl<DeviceId, BC: EventContext<RouterAdvertisementEvent<DeviceId>>> NdpBindingsContext<DeviceId>
1262 for BC
1263{
1264}
1265
1266pub trait MarksBindingsContext {
1268 fn marks_to_keep_on_egress() -> &'static [MarkDomain];
1273
1274 fn marks_to_set_on_ingress() -> &'static [MarkDomain];
1279
1280 fn update_ingress_marks(mut packet_marks: Marks, socket_marks: &Marks) -> Marks {
1283 for mark in Self::marks_to_set_on_ingress() {
1284 *packet_marks.get_mut(*mark) = *socket_marks.get(*mark);
1285 }
1286 packet_marks
1287 }
1288}
1289
1290pub trait IpLayerBindingsContext<I: IpLayerIpExt, DeviceId>:
1292 InstantContext
1293 + EventContext<IpLayerEvent<DeviceId, I>>
1294 + FilterBindingsContext<DeviceId>
1295 + TxMetadataBindingsTypes
1296 + IpRoutingBindingsTypes
1297 + MarksBindingsContext
1298{
1299}
1300impl<
1301 I: IpLayerIpExt,
1302 DeviceId,
1303 BC: InstantContext
1304 + EventContext<IpLayerEvent<DeviceId, I>>
1305 + FilterBindingsContext<DeviceId>
1306 + TxMetadataBindingsTypes
1307 + IpRoutingBindingsTypes
1308 + MarksBindingsContext,
1309> IpLayerBindingsContext<I, DeviceId> for BC
1310{
1311}
1312
1313pub trait IpLayerBindingsTypes:
1315 IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes
1316{
1317}
1318impl<BT: IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes> IpLayerBindingsTypes
1319 for BT
1320{
1321}
1322
1323pub trait IpLayerContext<
1325 I: IpLayerIpExt,
1326 BC: IpLayerBindingsContext<I, <Self as DeviceIdContext<AnyDevice>>::DeviceId>,
1327>:
1328 IpStateContext<I, BC>
1329 + IpDeviceContext<I>
1330 + IpDeviceMtuContext<I>
1331 + IpDeviceSendContext<I, BC>
1332 + IcmpErrorHandler<I, BC>
1333 + MulticastForwardingStateContext<I, BC>
1334 + MulticastForwardingDeviceContext<I>
1335 + CounterContext<MulticastForwardingCounters<I>>
1336 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>
1337{
1338}
1339
1340impl<
1341 I: IpLayerIpExt,
1342 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
1343 CC: IpStateContext<I, BC>
1344 + IpDeviceContext<I>
1345 + IpDeviceMtuContext<I>
1346 + IpDeviceSendContext<I, BC>
1347 + IcmpErrorHandler<I, BC>
1348 + MulticastForwardingStateContext<I, BC>
1349 + MulticastForwardingDeviceContext<I>
1350 + CounterContext<MulticastForwardingCounters<I>>
1351 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>,
1352> IpLayerContext<I, BC> for CC
1353{
1354}
1355
1356fn is_unicast_assigned<I: IpLayerIpExt>(status: &I::AddressStatus) -> bool {
1357 #[derive(GenericOverIp)]
1358 #[generic_over_ip(I, Ip)]
1359 struct WrapAddressStatus<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
1360
1361 I::map_ip(
1362 WrapAddressStatus(status),
1363 |WrapAddressStatus(status)| match status {
1364 Ipv4PresentAddressStatus::UnicastAssigned
1365 | Ipv4PresentAddressStatus::LoopbackSubnet => true,
1366 Ipv4PresentAddressStatus::UnicastTentative
1367 | Ipv4PresentAddressStatus::LimitedBroadcast
1368 | Ipv4PresentAddressStatus::SubnetBroadcast
1369 | Ipv4PresentAddressStatus::Multicast => false,
1370 },
1371 |WrapAddressStatus(status)| match status {
1372 Ipv6PresentAddressStatus::UnicastAssigned => true,
1373 Ipv6PresentAddressStatus::Multicast | Ipv6PresentAddressStatus::UnicastTentative => {
1374 false
1375 }
1376 },
1377 )
1378}
1379
1380fn is_local_assigned_address<I: Ip + IpLayerIpExt, CC: IpDeviceIngressStateContext<I>>(
1381 core_ctx: &mut CC,
1382 device: &CC::DeviceId,
1383 addr: IpDeviceAddr<I::Addr>,
1384) -> bool {
1385 match core_ctx.address_status_for_device(addr.into(), device) {
1386 AddressStatus::Present(status) => is_unicast_assigned::<I>(&status),
1387 AddressStatus::Unassigned => false,
1388 }
1389}
1390
1391fn get_device_with_assigned_address<I, CC>(
1392 core_ctx: &mut CC,
1393 addr: IpDeviceAddr<I::Addr>,
1394) -> Option<(CC::DeviceId, I::AddressStatus)>
1395where
1396 I: IpLayerIpExt,
1397 CC: IpDeviceContext<I>,
1398{
1399 core_ctx.with_address_statuses(addr.into(), |mut it| {
1400 it.find_map(|(device, status)| {
1401 is_unicast_assigned::<I>(&status).then_some((device, status))
1402 })
1403 })
1404}
1405
1406fn get_local_addr<I: Ip + IpLayerIpExt, CC: IpDeviceContext<I>>(
1410 core_ctx: &mut CC,
1411 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1412 device: &CC::DeviceId,
1413 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1414) -> Result<IpDeviceAddr<I::Addr>, ResolveRouteError> {
1415 match local_ip_and_policy {
1416 Some((local_ip, NonLocalSrcAddrPolicy::Allow)) => Ok(local_ip),
1417 Some((local_ip, NonLocalSrcAddrPolicy::Deny)) => {
1418 is_local_assigned_address(core_ctx, device, local_ip)
1419 .then_some(local_ip)
1420 .ok_or(ResolveRouteError::NoSrcAddr)
1421 }
1422 None => core_ctx
1423 .get_local_addr_for_remote(device, remote_addr.map(Into::into))
1424 .ok_or(ResolveRouteError::NoSrcAddr),
1425 }
1426}
1427
1428#[derive(Error, Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
1430#[generic_over_ip()]
1431pub enum ResolveRouteError {
1432 #[error("a source address could not be selected")]
1434 NoSrcAddr,
1435 #[error("no route exists to the destination IP address")]
1437 Unreachable,
1438}
1439
1440fn get_local_addr_with_internal_forwarding<I, CC>(
1442 core_ctx: &mut CC,
1443 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1444 device: &CC::DeviceId,
1445 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1446) -> Result<(IpDeviceAddr<I::Addr>, InternalForwarding<CC::DeviceId>), ResolveRouteError>
1447where
1448 I: IpLayerIpExt,
1449 CC: IpDeviceContext<I>,
1450{
1451 match get_local_addr(core_ctx, local_ip_and_policy, device, remote_addr) {
1452 Ok(src_addr) => Ok((src_addr, InternalForwarding::NotUsed)),
1453 Err(e) => {
1454 if let Some((local_ip, _policy)) = local_ip_and_policy {
1462 if let Some((device, _addr_status)) =
1463 get_device_with_assigned_address(core_ctx, local_ip)
1464 {
1465 if core_ctx.is_device_unicast_forwarding_enabled(&device) {
1466 return Ok((local_ip, InternalForwarding::Used(device)));
1467 }
1468 }
1469 }
1470 Err(e)
1471 }
1472 }
1473}
1474
1475#[derive(Debug, PartialEq, Eq)]
1478struct RuleWalkInfo<O> {
1479 observed_source_address_matcher: bool,
1481 inner: O,
1484}
1485
1486fn walk_rules<
1500 I: IpLayerIpExt,
1501 BT: IpRoutingBindingsTypes + MatcherBindingsTypes,
1502 CC: IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>,
1503 O,
1504 State,
1505 F: FnMut(
1506 State,
1507 &mut CC::IpDeviceIdCtx<'_>,
1508 &RoutingTable<I, CC::DeviceId>,
1509 ) -> ControlFlow<O, State>,
1510>(
1511 core_ctx: &mut CC,
1512 rules: &RulesTable<I, CC::DeviceId, BT>,
1513 init: State,
1514 rule_input: &RuleInput<'_, I, CC::DeviceId>,
1515 mut lookup_table: F,
1516) -> ControlFlow<RuleAction<RuleWalkInfo<O>>, RuleWalkInfo<State>> {
1517 rules.iter().try_fold(
1518 RuleWalkInfo { inner: init, observed_source_address_matcher: false },
1519 |RuleWalkInfo { inner: state, observed_source_address_matcher },
1520 Rule { action, matcher }| {
1521 let observed_source_address_matcher =
1522 observed_source_address_matcher || matcher.source_address_matcher.is_some();
1523 if !matcher.matches(rule_input) {
1524 return ControlFlow::Continue(RuleWalkInfo {
1525 inner: state,
1526 observed_source_address_matcher,
1527 });
1528 }
1529 match action {
1530 RuleAction::Unreachable => return ControlFlow::Break(RuleAction::Unreachable),
1531 RuleAction::Lookup(table_id) => core_ctx.with_ip_routing_table(
1532 &table_id,
1533 |core_ctx, table| match lookup_table(state, core_ctx, table) {
1534 ControlFlow::Break(out) => {
1535 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1536 inner: out,
1537 observed_source_address_matcher,
1538 }))
1539 }
1540 ControlFlow::Continue(state) => ControlFlow::Continue(RuleWalkInfo {
1541 inner: state,
1542 observed_source_address_matcher,
1543 }),
1544 },
1545 ),
1546 }
1547 },
1548 )
1549}
1550
1551pub fn resolve_output_route_to_destination<
1562 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1563 BC: IpDeviceBindingsContext<I, CC::DeviceId> + IpLayerBindingsContext<I, CC::DeviceId>,
1564 CC: IpStateContext<I, BC> + IpDeviceContext<I> + device::IpDeviceConfigurationContext<I, BC>,
1565>(
1566 core_ctx: &mut CC,
1567 device: Option<&CC::DeviceId>,
1568 src_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1569 dst_ip: Option<RoutableIpAddr<I::Addr>>,
1570 marks: &Marks,
1571) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1572 enum LocalDelivery<A, D> {
1573 WeakLoopback { dst_ip: A, device: D },
1574 StrongForDevice(D),
1575 }
1576
1577 let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1594 let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1595 match (device, dst_ip) {
1596 (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1597 .then_some(LocalDelivery::StrongForDevice(device.clone())),
1598 (None, Some(dst_ip)) => {
1599 get_device_with_assigned_address(core_ctx, dst_ip).map(
1600 |(dst_device, _addr_status)| {
1601 if src_ip_and_policy
1606 .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1607 || dst_ip.as_ref().must_have_zone()
1608 {
1609 LocalDelivery::StrongForDevice(dst_device)
1610 } else {
1611 LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1612 }
1613 },
1614 )
1615 }
1616 (_, None) => None,
1617 }
1618 };
1619
1620 if let Some(local_delivery) = local_delivery_instructions {
1621 let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1622
1623 let (src_addr, dest_device) = match local_delivery {
1624 LocalDelivery::WeakLoopback { dst_ip, device } => {
1625 let src_ip = match src_ip_and_policy {
1626 Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1627 let _device = get_device_with_assigned_address(core_ctx, src_ip)
1628 .ok_or(ResolveRouteError::NoSrcAddr)?;
1629 src_ip
1630 }
1631 Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1632 None => dst_ip,
1633 };
1634 (src_ip, device)
1635 }
1636 LocalDelivery::StrongForDevice(device) => {
1637 (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1638 }
1639 };
1640 return Ok(ResolvedRoute {
1641 src_addr,
1642 local_delivery_device: Some(dest_device),
1643 device: loopback,
1644 next_hop: NextHop::RemoteAsNeighbor,
1645 internal_forwarding: InternalForwarding::NotUsed,
1646 });
1647 }
1648 let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1649 let rule_input = RuleInput {
1650 packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1651 marks,
1652 };
1653 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
1654 let mut walk_rules = |rule_input, src_ip_and_policy| {
1655 walk_rules(
1656 core_ctx,
1657 rules,
1658 None, rule_input,
1660 |first_error, core_ctx, table| {
1661 let mut matching_with_addr = table.lookup_filter_map(
1662 core_ctx,
1663 device,
1664 dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1665 |core_ctx, d| {
1666 Some(get_local_addr_with_internal_forwarding(
1667 core_ctx,
1668 src_ip_and_policy,
1669 d,
1670 dst_ip,
1671 ))
1672 },
1673 );
1674
1675 let first_error_in_this_table = match matching_with_addr.next() {
1676 Some((
1677 Destination { device, next_hop },
1678 Ok((local_addr, internal_forwarding)),
1679 )) => {
1680 return ControlFlow::Break(Ok((
1681 Destination { device: device.clone(), next_hop },
1682 local_addr,
1683 internal_forwarding,
1684 )));
1685 }
1686 Some((_, Err(e))) => e,
1687 None => return ControlFlow::Continue(first_error),
1691 };
1692
1693 matching_with_addr
1694 .filter_map(|(destination, local_addr)| {
1695 local_addr.ok_checked::<ResolveRouteError>().map(
1698 |(local_addr, internal_forwarding)| {
1699 (destination, local_addr, internal_forwarding)
1700 },
1701 )
1702 })
1703 .next()
1704 .map_or(
1705 ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1706 |(
1707 Destination { device, next_hop },
1708 local_addr,
1709 internal_forwarding,
1710 )| {
1711 ControlFlow::Break(Ok((
1712 Destination { device: device.clone(), next_hop },
1713 local_addr,
1714 internal_forwarding,
1715 )))
1716 },
1717 )
1718 },
1719 )
1720 };
1721
1722 let result = match walk_rules(&rule_input, src_ip_and_policy) {
1723 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1730 inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1731 observed_source_address_matcher: true,
1732 })) if src_ip_and_policy.is_none() => walk_rules(
1733 &RuleInput {
1734 packet_origin: PacketOrigin::Local {
1735 bound_address: Some(selected_src_addr.into()),
1736 bound_device: device,
1737 },
1738 marks,
1739 },
1740 Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1741 ),
1742 result => result,
1743 };
1744
1745 match result {
1746 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1747 inner: result,
1748 observed_source_address_matcher: _,
1749 })) => {
1750 result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1751 ResolvedRoute {
1752 src_addr,
1753 device,
1754 local_delivery_device: None,
1755 next_hop,
1756 internal_forwarding,
1757 }
1758 })
1759 }
1760 ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1761 ControlFlow::Continue(RuleWalkInfo {
1762 inner: first_error,
1763 observed_source_address_matcher: _,
1764 }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1765 }
1766 })
1767}
1768
1769pub trait UseIpSocketContextBlanket {}
1774
1775impl<I, BC, CC> IpSocketContext<I, BC> for CC
1776where
1777 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1778 BC: IpDeviceBindingsContext<I, CC::DeviceId>
1779 + IpLayerBindingsContext<I, CC::DeviceId>
1780 + IpSocketBindingsContext<CC::DeviceId>,
1781 CC: IpLayerEgressContext<I, BC>
1782 + IpStateContext<I, BC>
1783 + IpDeviceContext<I>
1784 + IpDeviceConfirmReachableContext<I, BC>
1785 + IpDeviceMtuContext<I>
1786 + device::IpDeviceConfigurationContext<I, BC>
1787 + IcmpErrorHandler<I, BC>
1788 + UseIpSocketContextBlanket,
1789{
1790 fn lookup_route(
1791 &mut self,
1792 _bindings_ctx: &mut BC,
1793 device: Option<&CC::DeviceId>,
1794 local_ip: Option<IpDeviceAddr<I::Addr>>,
1795 addr: RoutableIpAddr<I::Addr>,
1796 transparent: bool,
1797 marks: &Marks,
1798 ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1799 let src_ip_and_policy = local_ip.map(|local_ip| {
1800 (
1801 local_ip,
1802 if transparent {
1803 NonLocalSrcAddrPolicy::Allow
1804 } else {
1805 NonLocalSrcAddrPolicy::Deny
1806 },
1807 )
1808 });
1809 let res =
1810 resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1811 trace!(
1812 "lookup_route(\
1813 device={device:?}, \
1814 local_ip={local_ip:?}, \
1815 addr={addr:?}, \
1816 transparent={transparent:?}, \
1817 marks={marks:?}) => {res:?}"
1818 );
1819 res
1820 }
1821
1822 fn send_ip_packet<S>(
1823 &mut self,
1824 bindings_ctx: &mut BC,
1825 meta: SendIpPacketMeta<
1826 I,
1827 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1828 SpecifiedAddr<I::Addr>,
1829 >,
1830 body: S,
1831 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1832 ) -> Result<(), IpSendFrameError<S>>
1833 where
1834 S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
1835 S::Buffer: BufferMut,
1836 {
1837 send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1838 }
1839
1840 fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1841 device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1842 }
1843
1844 fn confirm_reachable(
1845 &mut self,
1846 bindings_ctx: &mut BC,
1847 dst: SpecifiedAddr<I::Addr>,
1848 input: RuleInput<'_, I, Self::DeviceId>,
1849 ) {
1850 match lookup_route_table(self, dst.get(), input) {
1851 Some(Destination { next_hop, device }) => {
1852 let neighbor = match next_hop {
1853 NextHop::RemoteAsNeighbor => dst,
1854 NextHop::Gateway(gateway) => gateway,
1855 NextHop::Broadcast(marker) => {
1856 I::map_ip::<_, ()>(
1857 WrapBroadcastMarker(marker),
1858 |WrapBroadcastMarker(())| {
1859 debug!(
1860 "can't confirm {dst:?}@{device:?} as reachable: \
1861 dst is a broadcast address"
1862 );
1863 },
1864 |WrapBroadcastMarker(never)| match never {},
1865 );
1866 return;
1867 }
1868 };
1869 IpDeviceConfirmReachableContext::confirm_reachable(
1870 self,
1871 bindings_ctx,
1872 &device,
1873 neighbor,
1874 );
1875 }
1876 None => {
1877 debug!("can't confirm {dst:?} as reachable: no route");
1878 }
1879 }
1880 }
1881}
1882
1883pub trait SocketMetadata<CC>
1886where
1887 CC: ?Sized,
1888{
1889 fn socket_info(&self, core_ctx: &mut CC) -> SocketInfo;
1891 fn marks(&self, _core_ctx: &mut CC) -> Marks;
1893}
1894
1895impl<T, O, CC> SocketMetadata<CC> for EitherStack<T, O>
1896where
1897 CC: ?Sized,
1898 T: SocketMetadata<CC>,
1899 O: SocketMetadata<CC>,
1900{
1901 fn socket_info(&self, core_ctx: &mut CC) -> SocketInfo {
1902 match self {
1903 Self::ThisStack(t) => t.socket_info(core_ctx),
1904 Self::OtherStack(o) => o.socket_info(core_ctx),
1905 }
1906 }
1907
1908 fn marks(&self, core_ctx: &mut CC) -> Marks {
1909 match self {
1910 Self::ThisStack(t) => t.marks(core_ctx),
1911 Self::OtherStack(o) => o.marks(core_ctx),
1912 }
1913 }
1914}
1915
1916pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1921 type EarlyDemuxSocket: SocketMetadata<Self>;
1923
1924 fn early_demux<B: ParseBuffer>(
1926 &mut self,
1927 device: &Self::DeviceId,
1928 frame_dst: Option<LocalFrameDestination>,
1929 src_ip: I::Addr,
1930 dst_ip: I::Addr,
1931 proto: I::Proto,
1932 body: B,
1933 ) -> Option<Self::EarlyDemuxSocket>;
1934
1935 fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1939 &mut self,
1940 bindings_ctx: &mut BC,
1941 device: &Self::DeviceId,
1942 src_ip: I::RecvSrcAddr,
1943 dst_ip: SpecifiedAddr<I::Addr>,
1944 proto: I::Proto,
1945 body: B,
1946 info: &mut LocalDeliveryPacketInfo<I, H>,
1947 early_demux_socket: Option<Self::EarlyDemuxSocket>,
1948 ) -> Result<(), I::IcmpError>;
1949}
1950
1951pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1953 IpTransportDispatchContext<
1954 I,
1955 BC,
1956 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1957 > + IpDeviceIngressStateContext<I>
1958 + IpDeviceMtuContext<I>
1959 + IpDeviceSendContext<I, BC>
1960 + IcmpErrorHandler<I, BC>
1961 + IpLayerContext<I, BC>
1962 + FragmentHandler<I, BC>
1963 + FilterHandlerProvider<I, BC>
1964 + RawIpSocketHandler<I, BC>
1965{
1966}
1967
1968impl<
1969 I: IpLayerIpExt,
1970 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1971 CC: IpTransportDispatchContext<
1972 I,
1973 BC,
1974 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1975 > + IpDeviceIngressStateContext<I>
1976 + IpDeviceMtuContext<I>
1977 + IpDeviceSendContext<I, BC>
1978 + IcmpErrorHandler<I, BC>
1979 + IpLayerContext<I, BC>
1980 + FragmentHandler<I, BC>
1981 + FilterHandlerProvider<I, BC>
1982 + RawIpSocketHandler<I, BC>,
1983> IpLayerIngressContext<I, BC> for CC
1984{
1985}
1986
1987pub trait IpLayerEgressContext<I, BC>:
1989 IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1990 + FilterHandlerProvider<I, BC>
1991 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1992where
1993 I: IpLayerIpExt,
1994 BC: FilterBindingsContext<Self::DeviceId> + TxMetadataBindingsTypes,
1995{
1996}
1997
1998impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1999where
2000 I: IpLayerIpExt,
2001 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes,
2002 CC: IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
2003 + FilterHandlerProvider<I, BC>
2004 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
2005{
2006}
2007
2008pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
2010 IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
2011{
2012}
2013
2014impl<
2015 I: IpLayerIpExt,
2016 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2017 CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
2018> IpLayerForwardingContext<I, BC> for CC
2019{
2020}
2021
2022#[derive(Copy, Clone, Default)]
2024pub struct Ipv4StateBuilder {
2025 icmp: Icmpv4StateBuilder,
2026}
2027
2028impl Ipv4StateBuilder {
2029 #[cfg(any(test, feature = "testutils"))]
2031 pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
2032 &mut self.icmp
2033 }
2034
2035 pub fn build<
2037 CC: CoreTimerContext<IpLayerTimerId, BC>,
2038 StrongDeviceId: StrongDeviceIdentifier,
2039 BC: TimerContext + RngContext + IpLayerBindingsTypes,
2040 >(
2041 self,
2042 bindings_ctx: &mut BC,
2043 ) -> Ipv4State<StrongDeviceId, BC> {
2044 let Ipv4StateBuilder { icmp } = self;
2045
2046 Ipv4State {
2047 inner: IpStateInner::new::<CC>(bindings_ctx),
2048 icmp: icmp.build(),
2049 next_packet_id: Default::default(),
2050 }
2051 }
2052}
2053
2054#[derive(Copy, Clone)]
2058pub struct Ipv6StateBuilder {
2059 icmp: Icmpv6StateBuilder,
2060 slaac_stable_secret_key: Option<IidSecret>,
2061}
2062
2063impl Ipv6StateBuilder {
2064 pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
2069 self.slaac_stable_secret_key = Some(secret_key);
2070 self
2071 }
2072
2073 pub fn build<
2079 CC: CoreTimerContext<IpLayerTimerId, BC>,
2080 StrongDeviceId: StrongDeviceIdentifier,
2081 BC: TimerContext + RngContext + IpLayerBindingsTypes,
2082 >(
2083 self,
2084 bindings_ctx: &mut BC,
2085 ) -> Ipv6State<StrongDeviceId, BC> {
2086 let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
2087
2088 let slaac_stable_secret_key = slaac_stable_secret_key
2089 .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
2090
2091 Ipv6State {
2092 inner: IpStateInner::new::<CC>(bindings_ctx),
2093 icmp: icmp.build(),
2094 slaac_counters: Default::default(),
2095 slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
2096 slaac_stable_secret_key,
2097 }
2098 }
2099}
2100
2101impl Default for Ipv6StateBuilder {
2102 fn default() -> Self {
2103 #[cfg(any(test, feature = "testutils"))]
2104 let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
2105
2106 #[cfg(not(any(test, feature = "testutils")))]
2107 let slaac_stable_secret_key = None;
2108
2109 Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
2110 }
2111}
2112
2113pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
2115 pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
2117 pub icmp: Icmpv4State<BT>,
2119 pub next_packet_id: AtomicU16,
2121}
2122
2123impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2124 AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
2125{
2126 fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
2127 &self.inner
2128 }
2129}
2130
2131pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
2135 core_ctx: &mut CC,
2136) -> I::PacketId {
2137 core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
2138}
2139
2140pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
2142 pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
2144 pub icmp: Icmpv6State<BT>,
2146 pub slaac_counters: SlaacCounters,
2148 pub slaac_temp_secret_key: IidSecret,
2150 pub slaac_stable_secret_key: IidSecret,
2155}
2156
2157impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2158 AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
2159{
2160 fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
2161 &self.inner
2162 }
2163}
2164
2165impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2166 OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
2167{
2168 type Lock = Mutex<IpPacketFragmentCache<I, BT>, BT::Mutex>;
2169 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2170 OrderedLockRef::new(&self.fragment_cache)
2171 }
2172}
2173
2174impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2175 OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
2176{
2177 type Lock = Mutex<PmtuCache<I, BT>, BT::Mutex>;
2178 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2179 OrderedLockRef::new(&self.pmtu_cache)
2180 }
2181}
2182
2183impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2184 OrderedLockAccess<RulesTable<I, D, BT>> for IpStateInner<I, D, BT>
2185{
2186 type Lock = RwLock<RulesTable<I, D, BT>, BT::RwLock>;
2187 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2188 OrderedLockRef::new(&self.rules_table)
2189 }
2190}
2191
2192impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2193 OrderedLockAccess<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>
2194 for IpStateInner<I, D, BT>
2195{
2196 type Lock = Mutex<
2197 HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>,
2198 BT::Mutex,
2199 >;
2200 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2201 OrderedLockRef::new(&self.tables)
2202 }
2203}
2204
2205impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpRoutingBindingsTypes>
2206 OrderedLockAccess<RoutingTable<I, D>> for RoutingTableId<I, D, BT>
2207{
2208 type Lock = RwLock<RoutingTable<I, D>, BT::RwLock>;
2209 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2210 let Self(inner) = self;
2211 OrderedLockRef::new(&inner.routing_table)
2212 }
2213}
2214
2215impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2216 OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
2217{
2218 type Lock = RwLock<MulticastForwardingState<I, D, BT>, BT::RwLock>;
2219 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2220 OrderedLockRef::new(&self.multicast_forwarding)
2221 }
2222}
2223
2224impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2225 OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
2226{
2227 type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>, BT::RwLock>;
2228 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2229 OrderedLockRef::new(&self.raw_sockets)
2230 }
2231}
2232
2233impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2234 OrderedLockAccess<filter::State<I, WeakAddressId<I, BT>, BT>> for IpStateInner<I, D, BT>
2235{
2236 type Lock = RwLock<filter::State<I, WeakAddressId<I, BT>, BT>, BT::RwLock>;
2237 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2238 OrderedLockRef::new(&self.filter)
2239 }
2240}
2241
2242pub trait IpStateBindingsTypes:
2244 PmtuBindingsTypes
2245 + FragmentBindingsTypes
2246 + RawIpSocketsBindingsTypes
2247 + FilterBindingsTypes
2248 + MulticastForwardingBindingsTypes
2249 + IpDeviceStateBindingsTypes
2250 + IpRoutingBindingsTypes
2251{
2252}
2253impl<BT> IpStateBindingsTypes for BT where
2254 BT: PmtuBindingsTypes
2255 + FragmentBindingsTypes
2256 + RawIpSocketsBindingsTypes
2257 + FilterBindingsTypes
2258 + MulticastForwardingBindingsTypes
2259 + IpDeviceStateBindingsTypes
2260 + IpRoutingBindingsTypes
2261{
2262}
2263
2264#[derive(Derivative)]
2266#[derivative(Debug(bound = ""))]
2267#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2268pub enum RoutingTableCookie<BT: IpRoutingBindingsTypes> {
2269 Main,
2271 BindingsId(BT::RoutingTableId),
2273}
2274
2275#[derive(Derivative)]
2277#[derivative(Debug(bound = "D: Debug"))]
2278pub struct BaseRoutingTableState<I: Ip, D, BT: IpRoutingBindingsTypes> {
2279 routing_table: RwLock<RoutingTable<I, D>, BT::RwLock>,
2280 bindings_id: RoutingTableCookie<BT>,
2281}
2282
2283impl<I: Ip, D, BT: IpRoutingBindingsTypes> BaseRoutingTableState<I, D, BT> {
2284 pub(crate) fn with_bindings_id(bindings_id: RoutingTableCookie<BT>) -> Self {
2285 Self { bindings_id, routing_table: Default::default() }
2286 }
2287}
2288
2289#[derive(Derivative)]
2291#[derivative(PartialEq(bound = ""))]
2292#[derivative(Eq(bound = ""))]
2293#[derivative(Hash(bound = ""))]
2294#[derivative(Clone(bound = ""))]
2295pub struct RoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes>(
2296 StrongRc<BaseRoutingTableState<I, D, BT>>,
2297);
2298
2299impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for RoutingTableId<I, D, BT> {
2300 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2301 let Self(rc) = self;
2302 f.debug_tuple("RoutingTableId").field(&I::NAME).field(&rc.bindings_id).finish()
2303 }
2304}
2305
2306impl<I: Ip, D, BT: IpRoutingBindingsTypes> RoutingTableId<I, D, BT> {
2307 pub(crate) fn new(rc: StrongRc<BaseRoutingTableState<I, D, BT>>) -> Self {
2309 Self(rc)
2310 }
2311
2312 #[cfg(any(test, feature = "testutils"))]
2314 pub fn table(&self) -> &RwLock<RoutingTable<I, D>, BT::RwLock> {
2315 let Self(inner) = self;
2316 &inner.routing_table
2317 }
2318
2319 pub fn downgrade(&self) -> WeakRoutingTableId<I, D, BT>
2321 where
2322 BT::RoutingTableId: Clone,
2323 {
2324 let Self(rc) = self;
2325 WeakRoutingTableId { rc: StrongRc::downgrade(rc), bindings_id: rc.bindings_id.clone() }
2326 }
2327
2328 #[cfg(test)]
2329 fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2330 let Self(rc) = self;
2331 rc.routing_table.write()
2332 }
2333
2334 pub fn bindings_id(&self) -> &RoutingTableCookie<BT> {
2336 let Self(rc) = self;
2337 &rc.bindings_id
2338 }
2339}
2340
2341#[derive(Derivative)]
2343#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2344#[derivative(PartialEq, Eq, Hash)]
2345pub struct WeakRoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes> {
2346 rc: WeakRc<BaseRoutingTableState<I, D, BT>>,
2347 #[derivative(PartialEq = "ignore")]
2348 #[derivative(Hash = "ignore")]
2349 bindings_id: RoutingTableCookie<BT>,
2350}
2351
2352impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for WeakRoutingTableId<I, D, BT> {
2353 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2354 let Self { bindings_id, .. } = self;
2355 f.debug_tuple("WeakRoutingTableId").field(&I::NAME).field(bindings_id).finish()
2356 }
2357}
2358
2359#[derive(GenericOverIp)]
2361#[generic_over_ip(I, Ip)]
2362pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2363 rules_table: RwLock<RulesTable<I, D, BT>, BT::RwLock>,
2364 main_table_id: RoutingTableId<I, D, BT>,
2366 multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>, BT::RwLock>,
2367 multicast_forwarding_counters: MulticastForwardingCounters<I>,
2368 fragment_cache: Mutex<IpPacketFragmentCache<I, BT>, BT::Mutex>,
2369 pmtu_cache: Mutex<PmtuCache<I, BT>, BT::Mutex>,
2370 counters: IpCounters<I>,
2371 raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>, BT::RwLock>,
2372 raw_socket_counters: RawIpSocketCounters<I>,
2373 filter: RwLock<filter::State<I, WeakAddressId<I, BT>, BT>, BT::RwLock>,
2374 tables: Mutex<
2380 HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>,
2381 BT::Mutex,
2382 >,
2383 igmp_counters: IgmpCounters,
2384 mld_counters: MldCounters,
2385}
2386
2387impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2388 pub fn counters(&self) -> &IpCounters<I> {
2390 &self.counters
2391 }
2392
2393 pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2395 &self.multicast_forwarding_counters
2396 }
2397
2398 pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2400 &self.raw_socket_counters
2401 }
2402
2403 pub fn main_table_id(&self) -> &RoutingTableId<I, D, BT> {
2405 &self.main_table_id
2406 }
2407
2408 #[cfg(any(test, feature = "testutils"))]
2410 pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>, BT::Mutex> {
2411 &self.pmtu_cache
2412 }
2413
2414 #[cfg(any(test, feature = "testutils"))]
2416 pub fn filter(&self) -> &RwLock<filter::State<I, WeakAddressId<I, BT>, BT>, BT::RwLock> {
2417 &self.filter
2418 }
2419
2420 pub fn igmp_counters(&self) -> &IgmpCounters {
2422 &self.igmp_counters
2423 }
2424
2425 pub fn mld_counters(&self) -> &MldCounters {
2427 &self.mld_counters
2428 }
2429}
2430
2431impl<
2432 I: IpLayerIpExt,
2433 D: StrongDeviceIdentifier,
2434 BC: TimerContext + RngContext + IpStateBindingsTypes + IpRoutingBindingsTypes,
2435> IpStateInner<I, D, BC>
2436{
2437 fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2439 let main_table: PrimaryRc<BaseRoutingTableState<I, D, BC>> =
2440 PrimaryRc::new(BaseRoutingTableState::with_bindings_id(RoutingTableCookie::Main));
2441 let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2442 Self {
2443 rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2444 tables: Mutex::new(HashMap::from_iter(core::iter::once((
2445 main_table_id.clone(),
2446 main_table,
2447 )))),
2448 main_table_id,
2449 multicast_forwarding: Default::default(),
2450 multicast_forwarding_counters: Default::default(),
2451 fragment_cache: Mutex::new(
2452 IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2453 ),
2454 pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2455 counters: Default::default(),
2456 raw_sockets: Default::default(),
2457 raw_socket_counters: Default::default(),
2458 filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2459 igmp_counters: Default::default(),
2460 mld_counters: Default::default(),
2461 }
2462 }
2463}
2464
2465#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2467#[generic_over_ip()]
2468pub enum IpLayerTimerId {
2469 ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2471 ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2473 PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2475 PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2477 FilterTimerv4(FilterTimerId<Ipv4>),
2479 FilterTimerv6(FilterTimerId<Ipv6>),
2481 MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2483 MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2485}
2486
2487impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2488 fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2489 I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2490 }
2491}
2492
2493impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2494 fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2495 I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2496 }
2497}
2498
2499impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2500 fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2501 I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2502 }
2503}
2504
2505impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2506 fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2507 I::map_ip(
2508 timer,
2509 IpLayerTimerId::MulticastForwardingTimerv4,
2510 IpLayerTimerId::MulticastForwardingTimerv6,
2511 )
2512 }
2513}
2514
2515impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2516where
2517 CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2518 + TimerHandler<BC, FragmentTimerId<Ipv6>>
2519 + TimerHandler<BC, PmtuTimerId<Ipv4>>
2520 + TimerHandler<BC, PmtuTimerId<Ipv6>>
2521 + TimerHandler<BC, FilterTimerId<Ipv4>>
2522 + TimerHandler<BC, FilterTimerId<Ipv6>>
2523 + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2524 + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2525 BC: TimerBindingsTypes,
2526{
2527 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2528 match self {
2529 IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2530 core_ctx.handle_timer(bindings_ctx, id, timer)
2531 }
2532 IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2533 core_ctx.handle_timer(bindings_ctx, id, timer)
2534 }
2535 IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2536 IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2537 IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2538 IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2539 IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2540 core_ctx.handle_timer(bindings_ctx, id, timer)
2541 }
2542 IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2543 core_ctx.handle_timer(bindings_ctx, id, timer)
2544 }
2545 }
2546 }
2547}
2548
2549pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2556 err: I::IcmpError,
2558 src_ip: SocketIpAddr<I::Addr>,
2561 dst_ip: SocketIpAddr<I::Addr>,
2564 frame_dst: Option<LocalFrameDestination>,
2566 device: &'a D,
2568 meta: ParseMetadata,
2571 marks: Marks,
2573 proto: I::Proto,
2575}
2576
2577impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2578 pub fn new<CC, B>(
2579 core_ctx: &mut CC,
2580 err: I::IcmpError,
2581 packet: &I::Packet<B>,
2582 frame_dst: Option<LocalFrameDestination>,
2583 device: &'a D,
2584 marks: Marks,
2585 ) -> Option<Self>
2586 where
2587 I: IpCountersIpExt,
2588 CC: ResourceCounterContext<D, IpCounters<I>>,
2589 B: SplitByteSlice,
2590 {
2591 let Some(src_ip) = SocketIpAddr::new(packet.src_ip()) else {
2592 core_ctx.increment_both(device, |c| &c.unspecified_source);
2593 return None;
2594 };
2595 let Some(dst_ip) = SocketIpAddr::new(packet.dst_ip()) else {
2596 return None;
2597 };
2598
2599 let is_ipv4_fragment = I::map_ip_in(
2601 packet,
2602 |p| {
2603 packet_formats::ipv4::Ipv4Header::fragment_type(p)
2604 == Ipv4FragmentType::NonInitialFragment
2605 },
2606 |_| false,
2607 );
2608 if is_ipv4_fragment {
2609 return None;
2610 }
2611
2612 let meta = packet.parse_metadata();
2613 let proto = packet.proto();
2614 Some(Self { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto })
2615 }
2616
2617 pub fn send<B, BC, CC>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, mut body: B)
2624 where
2625 B: BufferMut,
2626 CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2627 {
2628 let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto } = self;
2629 let header_len = meta.header_len();
2630
2631 body.undo_parse(meta);
2635
2636 core_ctx.send_icmp_error_message(
2637 bindings_ctx,
2638 Some(device),
2639 frame_dst,
2640 src_ip,
2641 dst_ip,
2642 body,
2643 err,
2644 header_len,
2645 proto,
2646 &marks,
2647 );
2648 }
2649}
2650
2651#[derive(PartialEq, Eq)]
2657struct EarlyDemuxResult<I: Ip, S> {
2658 socket: S,
2659 src_addr: I::Addr,
2660 src_port: Option<u16>,
2661}
2662
2663impl<I: FilterIpExt, S> EarlyDemuxResult<I, S> {
2664 fn new<P: IpPacket<I>>(socket: S, packet: &P) -> Self {
2665 let src_port =
2666 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port_or_id());
2667 Self { socket, src_addr: packet.src_addr(), src_port }
2668 }
2669
2670 fn take_socket<P: IpPacket<I>>(self, packet: &P) -> Option<S> {
2672 let src_port =
2673 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port_or_id());
2674 (self.src_addr == packet.src_addr() && self.src_port == src_port).then_some(self.socket)
2675 }
2676
2677 fn update_packet_metadata<CC, BC>(
2678 &self,
2679 core_ctx: &mut CC,
2680 packet_metadata: &mut IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2681 ) where
2682 I: IpLayerIpExt,
2683 S: SocketMetadata<CC>,
2684 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2685 CC: IpLayerIngressContext<I, BC>,
2686 {
2687 packet_metadata.socket_info = Some(self.socket.socket_info(core_ctx));
2688 packet_metadata.marks =
2689 BC::update_ingress_marks(packet_metadata.marks, &self.socket.marks(core_ctx));
2690 }
2691}
2692
2693pub(crate) fn reject_type_to_icmpv4_error(reject_type: RejectType) -> Option<Icmpv4Error> {
2694 let error = match reject_type {
2695 RejectType::NetUnreachable => Icmpv4Error::NetUnreachable,
2696 RejectType::ProtoUnreachable => Icmpv4Error::ProtocolUnreachable,
2697 RejectType::PortUnreachable => Icmpv4Error::PortUnreachable,
2698 RejectType::HostUnreachable => Icmpv4Error::HostUnreachable,
2699 RejectType::RoutePolicyFail => Icmpv4Error::NetworkProhibited,
2700 RejectType::RejectRoute => Icmpv4Error::HostProhibited,
2701 RejectType::AdminProhibited => Icmpv4Error::AdminProhibited,
2702 RejectType::TcpReset => return None,
2704 };
2705 Some(error)
2706}
2707
2708pub(crate) fn reject_type_to_icmpv6_error(reject_type: RejectType) -> Option<Icmpv6Error> {
2709 let error = match reject_type {
2710 RejectType::NetUnreachable => Icmpv6Error::NetUnreachable,
2711 RejectType::PortUnreachable => Icmpv6Error::PortUnreachable,
2712 RejectType::HostUnreachable => Icmpv6Error::AddressUnreachable,
2713 RejectType::AdminProhibited => Icmpv6Error::AdminProhibited,
2714 RejectType::RoutePolicyFail => Icmpv6Error::SourceAddressPolicyFailed,
2715 RejectType::RejectRoute => Icmpv6Error::RejectRoute,
2716 RejectType::TcpReset | RejectType::ProtoUnreachable => return None,
2718 };
2719 Some(error)
2720}
2721fn dispatch_receive_ipv4_packet<
2742 'a,
2743 'b,
2744 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2745 CC: IpLayerIngressContext<Ipv4, BC>,
2746>(
2747 core_ctx: &'a mut CC,
2748 bindings_ctx: &'a mut BC,
2749 device: &'b CC::DeviceId,
2750 frame_dst: Option<LocalFrameDestination>,
2751 mut packet: Ipv4Packet<&'a mut [u8]>,
2752 mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2753 receive_meta: ReceiveIpPacketMeta<Ipv4>,
2754) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2755 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2756
2757 let early_demux_result = receive_meta
2760 .transparent_override
2761 .is_none()
2762 .then(|| {
2763 core_ctx.early_demux(
2764 device,
2765 frame_dst,
2766 packet.src_ip(),
2767 packet.dst_ip(),
2768 packet.proto(),
2769 packet.body(),
2770 )
2771 })
2772 .flatten()
2773 .map(|socket| {
2774 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2775 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2776 early_demux_result
2777 });
2778
2779 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2780 bindings_ctx,
2781 &mut packet,
2782 device,
2783 &mut packet_metadata,
2784 );
2785
2786 let marks = packet_metadata.marks;
2787 let packet_type = packet_metadata.packet_type;
2788 let gso_info = packet_metadata.gso_info;
2789 packet_metadata.acknowledge_drop();
2790
2791 match filter_verdict {
2792 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2793 return Ok(());
2794 }
2795 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2796 return match reject_type_to_icmpv4_error(reject_type) {
2797 Some(icmp_error) => {
2798 match IcmpErrorSender::new(
2799 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2800 ) {
2801 Some(icmp_sender) => Err(icmp_sender),
2802 None => Ok(()),
2803 }
2804 }
2805 None => {
2806 debug!("Unsupported reject type: {:?}", reject_type);
2807 return Ok(());
2808 }
2809 };
2810 }
2811 filter::Verdict::Proceed(filter::Accept) => (),
2812 };
2813
2814 let Some(src_ip) = packet.src_ipv4() else {
2818 debug!(
2819 "dispatch_receive_ipv4_packet: received packet from invalid source {} after the \
2820 LOCAL_INGRESS hook; dropping",
2821 packet.src_ip()
2822 );
2823 core_ctx.increment_both(device, |c| &c.invalid_source);
2824 return Ok(());
2825 };
2826 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2827 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2828 debug!(
2829 "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2830 after the LOCAL_INGRESS hook; dropping"
2831 );
2832 return Ok(());
2833 };
2834
2835 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2836
2837 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2839
2840 let proto = packet.proto();
2841 let (prefix, options, body) = packet.parts_with_body_mut();
2842 let buffer = Buf::new(body, ..);
2843 let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2844 let mut receive_info =
2845 LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks, packet_type, gso_info };
2846
2847 core_ctx
2848 .dispatch_receive_ip_packet(
2849 bindings_ctx,
2850 device,
2851 src_ip,
2852 dst_ip,
2853 proto,
2854 buffer,
2855 &mut receive_info,
2856 early_demux_socket,
2857 )
2858 .or_else(|icmp_error| {
2859 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2860 Some(icmp_sender) => Err(icmp_sender),
2861 None => Ok(()),
2862 }
2863 })
2864}
2865
2866fn dispatch_receive_ipv6_packet<
2871 'a,
2872 'b,
2873 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2874 CC: IpLayerIngressContext<Ipv6, BC>,
2875>(
2876 core_ctx: &'a mut CC,
2877 bindings_ctx: &'a mut BC,
2878 device: &'b CC::DeviceId,
2879 frame_dst: Option<LocalFrameDestination>,
2880 mut packet: Ipv6Packet<&'a mut [u8]>,
2881 mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2882 meta: ReceiveIpPacketMeta<Ipv6>,
2883) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2884 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2891
2892 let early_demux_result = meta
2895 .transparent_override
2896 .is_none()
2897 .then(|| {
2898 core_ctx.early_demux(
2899 device,
2900 frame_dst,
2901 packet.src_ip(),
2902 packet.dst_ip(),
2903 packet.proto(),
2904 packet.body(),
2905 )
2906 })
2907 .flatten()
2908 .map(|socket| {
2909 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2910 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2911 early_demux_result
2912 });
2913
2914 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2915 bindings_ctx,
2916 &mut packet,
2917 device,
2918 &mut packet_metadata,
2919 );
2920
2921 let marks = packet_metadata.marks;
2922 let packet_type = packet_metadata.packet_type;
2923 let gso_info = packet_metadata.gso_info;
2924 packet_metadata.acknowledge_drop();
2925
2926 match filter_verdict {
2927 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2928 return Ok(());
2929 }
2930 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2931 return match reject_type_to_icmpv6_error(reject_type) {
2932 Some(icmp_error) => {
2933 match IcmpErrorSender::new(
2934 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2935 ) {
2936 Some(icmp_sender) => Err(icmp_sender),
2937 None => Ok(()),
2938 }
2939 }
2940 None => {
2941 debug!("Unsupported reject type: {:?}", reject_type);
2942 return Ok(());
2943 }
2944 };
2945 }
2946 filter::Verdict::Proceed(filter::Accept) => {}
2947 }
2948
2949 let Some(src_ip) = packet.src_ipv6() else {
2953 debug!(
2954 "dispatch_receive_ipv6_packet: received packet from invalid source {} after the \
2955 LOCAL_INGRESS hook; dropping",
2956 packet.src_ip()
2957 );
2958
2959 core_ctx.increment_both(device, |c| &c.invalid_source);
2960 return Ok(());
2961 };
2962 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2963 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2964 debug!(
2965 "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2966 after the LOCAL_INGRESS hook; dropping"
2967 );
2968 return Ok(());
2969 };
2970
2971 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2972
2973 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2975
2976 let proto = packet.proto();
2977 let (fixed, extension, body) = packet.parts_with_body_mut();
2978 let buffer = Buf::new(body, ..);
2979 let header_info = Ipv6HeaderInfo { fixed, extension };
2980 let mut receive_info =
2981 LocalDeliveryPacketInfo { meta, header_info, marks, packet_type, gso_info };
2982
2983 core_ctx
2984 .dispatch_receive_ip_packet(
2985 bindings_ctx,
2986 device,
2987 src_ip,
2988 dst_ip,
2989 proto,
2990 buffer,
2991 &mut receive_info,
2992 early_demux_socket,
2993 )
2994 .or_else(|icmp_error| {
2995 let marks = receive_info.marks;
2996 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2997 Some(icmp_sender) => Err(icmp_sender),
2998 None => Ok(()),
2999 }
3000 })
3001}
3002
3003pub(crate) struct IpPacketForwarder<
3010 'a,
3011 I: IpLayerIpExt,
3012 D,
3013 A,
3014 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
3015> {
3016 inbound_device: &'a D,
3017 outbound_device: &'a D,
3018 packet_meta: IpLayerPacketMetadata<I, A, BT>,
3019 src_ip: I::RecvSrcAddr,
3020 dst_ip: SpecifiedAddr<I::Addr>,
3021 destination: IpPacketDestination<I, &'a D>,
3022 proto: I::Proto,
3023 parse_meta: ParseMetadata,
3024 frame_dst: Option<LocalFrameDestination>,
3025}
3026
3027impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
3028where
3029 I: IpLayerIpExt,
3030 BC: IpLayerBindingsContext<I, D>,
3031{
3032 fn forward_with_buffer<CC, B>(
3034 self,
3035 core_ctx: &mut CC,
3036 bindings_ctx: &mut BC,
3037 buffer: B,
3038 max_fragment_len: Option<usize>,
3039 ) where
3040 B: BufferMut,
3041 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
3042 {
3043 let Self {
3044 inbound_device,
3045 outbound_device,
3046 packet_meta,
3047 src_ip,
3048 dst_ip,
3049 destination,
3050 proto,
3051 parse_meta,
3052 frame_dst,
3053 } = self;
3054
3055 let outbound_mtu = core_ctx.get_mtu(outbound_device);
3056 let marks = packet_meta.marks;
3057
3058 let send_icmp_packet_too_big = |core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B| {
3059 debug!("failed to forward {} packet: MTU exceeded", I::NAME);
3060 core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
3061 let Some(err) = I::IcmpError::mtu_exceeded(outbound_mtu) else {
3063 return;
3064 };
3065 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
3068 return;
3069 };
3070
3071 let Some(dst_ip) = SocketIpAddr::new(dst_ip.get()) else {
3072 return;
3073 };
3074
3075 core_ctx.send_icmp_error_message(
3085 bindings_ctx,
3086 Some(inbound_device),
3087 frame_dst,
3088 src_ip,
3089 dst_ip,
3090 buffer,
3091 err,
3092 parse_meta.header_len(),
3093 proto,
3094 &marks,
3095 );
3096 };
3097
3098 let max_fragment_len = max_fragment_len
3104 .map(|l| Mtu::new(u32::try_from(l).expect("fragment size must fit in u32")));
3105 if I::VERSION == IpVersion::V6
3106 && max_fragment_len.is_some_and(|max_fragment_len| max_fragment_len > outbound_mtu)
3107 {
3108 packet_meta.acknowledge_drop();
3109 send_icmp_packet_too_big(core_ctx, bindings_ctx, buffer);
3110 return;
3111 }
3112 let (was_reassembled, limit_mtu) = match max_fragment_len {
3113 None => (false, Mtu::no_limit()),
3114 Some(max_fragment_len) => (true, max_fragment_len),
3115 };
3116
3117 let packet = ForwardedPacket::new(
3118 src_ip.get(),
3119 dst_ip.get(),
3120 proto,
3121 parse_meta,
3122 buffer,
3123 was_reassembled,
3124 );
3125
3126 trace!("forward_with_buffer: forwarding {} packet", I::NAME);
3127
3128 match send_ip_frame(
3129 core_ctx,
3130 bindings_ctx,
3131 outbound_device,
3132 destination,
3133 packet,
3134 packet_meta,
3135 limit_mtu,
3136 ) {
3137 Ok(()) => (),
3138 Err(IpSendFrameError { serializer, error }) => {
3139 match error {
3140 IpSendFrameErrorReason::Device(
3141 SendFrameErrorReason::SizeConstraintsViolation,
3142 ) => {
3143 send_icmp_packet_too_big(core_ctx, bindings_ctx, serializer.into_buffer());
3144 }
3145 IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
3146 | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
3147 | IpSendFrameErrorReason::Device(
3148 SendFrameErrorReason::AddressResolutionFailed,
3149 )
3150 | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
3151 }
3152 debug!("failed to forward {} packet: {error:?}", I::NAME);
3153 }
3154 }
3155 }
3156}
3157
3158pub(crate) enum ForwardingAction<
3160 'a,
3161 I: IpLayerIpExt,
3162 D,
3163 A,
3164 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
3165> {
3166 SilentlyDrop,
3168 Forward(IpPacketForwarder<'a, I, D, A, BT>),
3170 DropWithIcmpError(IcmpErrorSender<'a, I, D>),
3173}
3174
3175impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
3176where
3177 I: IpLayerIpExt,
3178 BC: IpLayerBindingsContext<I, D>,
3179{
3180 pub(crate) fn perform_action_with_buffer<CC, B>(
3182 self,
3183 core_ctx: &mut CC,
3184 bindings_ctx: &mut BC,
3185 buffer: B,
3186 max_fragment_len: Option<usize>,
3187 ) where
3188 B: BufferMut,
3189 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
3190 {
3191 match self {
3192 ForwardingAction::SilentlyDrop => {}
3193 ForwardingAction::Forward(forwarder) => {
3194 forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer, max_fragment_len)
3195 }
3196 ForwardingAction::DropWithIcmpError(icmp_sender) => {
3197 icmp_sender.send(core_ctx, bindings_ctx, buffer)
3198 }
3199 }
3200 }
3201}
3202
3203pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
3205 core_ctx: &'a mut CC,
3206 mut packet: I::Packet<&'a mut [u8]>,
3207 mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3208 minimum_ttl: Option<NonZeroU8>,
3209 inbound_device: &'b CC::DeviceId,
3210 outbound_device: &'b CC::DeviceId,
3211 destination: IpPacketDestination<I, &'b CC::DeviceId>,
3212 frame_dst: Option<LocalFrameDestination>,
3213 src_ip: I::RecvSrcAddr,
3214 dst_ip: SpecifiedAddr<I::Addr>,
3215) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
3216where
3217 I: IpLayerIpExt,
3218 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3219 CC: IpLayerForwardingContext<I, BC>,
3220{
3221 const DEFAULT_MIN_TTL: u8 = 1;
3226 let minimum_ttl = minimum_ttl.map(NonZeroU8::get).unwrap_or(DEFAULT_MIN_TTL);
3227 let ttl = packet.ttl();
3228 if ttl <= minimum_ttl {
3229 debug!(
3230 "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
3231 I::NAME
3232 );
3233 if ttl > 1 {
3245 packet_meta.acknowledge_drop();
3246 return ForwardingAction::SilentlyDrop;
3247 }
3248
3249 core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
3250
3251 let marks = packet_meta.marks;
3252 packet_meta.acknowledge_drop();
3253
3254 match IcmpErrorSender::new(
3256 core_ctx,
3257 I::IcmpError::ttl_expired(),
3258 &packet,
3259 frame_dst,
3260 inbound_device,
3261 marks,
3262 ) {
3263 Some(icmp_sender) => return ForwardingAction::DropWithIcmpError(icmp_sender),
3264 None => return ForwardingAction::SilentlyDrop,
3265 }
3266 }
3267
3268 trace!("determine_ip_packet_forwarding_action: adequate TTL");
3269
3270 let maybe_ipv6_packet_action = I::map_ip_in(
3276 &packet,
3277 |_packet| None,
3278 |packet| {
3279 Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
3280 },
3281 );
3282 match maybe_ipv6_packet_action {
3283 None => {} Some(Ipv6PacketAction::_Discard) => {
3285 core_ctx.increment_both(inbound_device, |c| {
3286 #[derive(GenericOverIp)]
3287 #[generic_over_ip(I, Ip)]
3288 struct InCounters<'a, I: IpLayerIpExt>(
3289 &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<Counter>,
3290 );
3291 I::map_ip_in::<_, _>(
3292 InCounters(&c.version_rx),
3293 |_counters| {
3294 unreachable!(
3295 "`I` must be `Ipv6` because we're handling IPv6 extension headers"
3296 )
3297 },
3298 |InCounters(counters)| &counters.extension_header_discard,
3299 )
3300 });
3301 trace!(
3302 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3303 discarding packet"
3304 );
3305 packet_meta.acknowledge_drop();
3306 return ForwardingAction::SilentlyDrop;
3307 }
3308 Some(Ipv6PacketAction::Continue) => {
3309 trace!(
3310 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3311 forwarding packet"
3312 );
3313 }
3314 Some(Ipv6PacketAction::ProcessFragment) => {
3315 unreachable!(
3316 "When forwarding packets, we should only ever look at the hop by hop \
3317 options extension header (if present)"
3318 )
3319 }
3320 };
3321
3322 match core_ctx.filter_handler().forwarding_hook(
3323 I::as_filter_packet(&mut packet),
3324 inbound_device,
3325 outbound_device,
3326 &mut packet_meta,
3327 ) {
3328 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3329 packet_meta.acknowledge_drop();
3330 trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
3331 return ForwardingAction::SilentlyDrop;
3332 }
3333 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
3334 packet_meta.acknowledge_drop();
3336 trace!(
3337 "determine_ip_packet_forwarding_action: filter verdict: Reject({:?})",
3338 reject_type
3339 );
3340 return ForwardingAction::SilentlyDrop;
3341 }
3342 filter::Verdict::Proceed(filter::Accept) => {}
3343 }
3344
3345 packet.set_ttl(ttl - 1);
3346 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
3347 ForwardingAction::Forward(IpPacketForwarder {
3348 inbound_device,
3349 outbound_device,
3350 packet_meta,
3351 src_ip,
3352 dst_ip,
3353 destination,
3354 proto,
3355 parse_meta,
3356 frame_dst,
3357 })
3358}
3359
3360pub(crate) fn send_ip_frame<I, CC, BC, S>(
3361 core_ctx: &mut CC,
3362 bindings_ctx: &mut BC,
3363 device: &CC::DeviceId,
3364 destination: IpPacketDestination<I, &CC::DeviceId>,
3365 mut body: S,
3366 mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3367 limit_mtu: Mtu,
3368) -> Result<(), IpSendFrameError<S>>
3369where
3370 I: IpLayerIpExt,
3371 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3372 CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
3373 S: FragmentableIpSerializer<I, Buffer: BufferMut>
3374 + MaybeSegmentableIpSerializer<I>
3375 + FilterIpPacket<I>,
3376{
3377 let (verdict, proof) = core_ctx.filter_handler().egress_hook(
3378 bindings_ctx,
3379 &mut body,
3380 device,
3381 &mut packet_metadata,
3382 );
3383 match verdict {
3384 filter::Verdict::Stop(filter::DropPacket) => {
3385 packet_metadata.acknowledge_drop();
3386 return Ok(());
3387 }
3388 filter::Verdict::Proceed(filter::Accept) => {}
3389 }
3390
3391 let (
3395 conntrack_connection_and_direction,
3396 tx_metadata,
3397 marks,
3398 _socket_cookie,
3399 gso_info,
3400 packet_type,
3401 ) = packet_metadata.into_parts();
3402 let conntrack_entry = if device.is_loopback() {
3403 conntrack_connection_and_direction
3404 .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
3405 } else {
3406 None
3407 };
3408
3409 let mut device_layer_marks = Marks::default();
3410 for mark in BC::marks_to_keep_on_egress() {
3411 *device_layer_marks.get_mut(*mark) = *marks.get(*mark);
3412 }
3413
3414 let device_ip_layer_metadata = DeviceIpLayerMetadata {
3415 conntrack_entry,
3416 tx_metadata,
3417 marks: device_layer_marks,
3418 packet_type,
3419 };
3420
3421 if !device.is_loopback()
3425 && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
3426 || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
3427 {
3428 core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
3429 return Err(IpSendFrameError {
3430 serializer: body,
3431 error: IpSendFrameErrorReason::IllegalLoopbackAddress,
3432 });
3433 }
3434
3435 let mtu = limit_mtu.min(core_ctx.get_mtu(device));
3437
3438 let Some(gso_info) = gso_info else {
3439 return send_ip_frame_possibly_fragmented(
3442 core_ctx,
3443 bindings_ctx,
3444 device,
3445 destination,
3446 body,
3447 device_ip_layer_metadata,
3448 mtu,
3449 proof,
3450 );
3451 };
3452
3453 match send_ip_frame_segmented(
3454 core_ctx,
3455 bindings_ctx,
3456 device,
3457 destination.clone(),
3458 &body,
3459 gso_info,
3460 device_ip_layer_metadata,
3461 mtu,
3462 proof,
3463 ) {
3464 Ok(()) => Ok(()),
3465 Err(SendIpFrameSegmentedError::NotSegmentable(error, device_ip_layer_metadata, proof)) => {
3466 debug_assert!(
3471 false,
3472 "GRO or GSO produced a packet that can't be resegmented: {error:?}"
3473 );
3474 error!("GRO or GSO produced a packet that can't be resegmented: {error:?}");
3475 send_ip_frame_possibly_fragmented(
3476 core_ctx,
3477 bindings_ctx,
3478 device,
3479 destination,
3480 body,
3481 device_ip_layer_metadata,
3482 mtu,
3483 proof,
3484 )
3485 }
3486 Err(SendIpFrameSegmentedError::Send(error)) => {
3487 Err(IpSendFrameError { serializer: body, error })
3488 }
3489 }
3490}
3491
3492enum SendIpFrameSegmentedError<BT: TxMetadataBindingsTypes> {
3494 NotSegmentable(GsoError, DeviceIpLayerMetadata<BT>, ProofOfEgressCheck),
3499 Send(IpSendFrameErrorReason),
3501}
3502
3503fn send_ip_frame_segmented<I, CC, BC, S>(
3510 core_ctx: &mut CC,
3511 bindings_ctx: &mut BC,
3512 device: &CC::DeviceId,
3513 destination: IpPacketDestination<I, &CC::DeviceId>,
3514 body: &S,
3515 gso_info: GsoInfo,
3516 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3517 mtu: Mtu,
3518 proof: ProofOfEgressCheck,
3519) -> Result<(), SendIpFrameSegmentedError<BC>>
3520where
3521 I: IpLayerIpExt,
3522 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3523 CC: IpLayerEgressContext<I, BC>,
3524 S: FragmentableIpSerializer<I, Buffer: BufferMut> + MaybeSegmentableIpSerializer<I>,
3525{
3526 core_ctx.increment_both(device, |c| &c.gso.for_source(S::SOURCE).segmentation_required);
3527
3528 let segmenter = match body.try_segmenter(gso_info) {
3529 Ok(segmenter) => segmenter,
3530 Err(error) => {
3531 core_ctx.increment_both(device, |c| c.gso.for_source(S::SOURCE).error_counter(&error));
3532 return Err(SendIpFrameSegmentedError::NotSegmentable(
3533 error,
3534 device_ip_layer_metadata,
3535 proof,
3536 ));
3537 }
3538 };
3539
3540 let mut device_ip_layer_metadata = device_ip_layer_metadata;
3541 let mut proof = proof;
3542
3543 for (segment, has_more) in segmenter {
3544 let (segment_metadata, segment_proof, remaining) = if has_more {
3545 let SplitDeviceIpLayerMetadata { primary, secondary } =
3546 device_ip_layer_metadata.split_for_multiple_frames();
3547 (secondary, proof.clone_for_multiple_frames(), Some((primary, proof)))
3548 } else {
3549 (device_ip_layer_metadata, proof, None)
3550 };
3551
3552 send_ip_frame_possibly_fragmented(
3553 core_ctx,
3554 bindings_ctx,
3555 device,
3556 destination.clone(),
3557 segment,
3558 segment_metadata,
3559 mtu,
3560 segment_proof,
3561 )
3562 .map_err(|IpSendFrameError { serializer: _, error }| {
3563 SendIpFrameSegmentedError::Send(error)
3564 })?;
3565
3566 core_ctx.increment_both(device, |c| &c.gso.for_source(S::SOURCE).segments);
3567
3568 match remaining {
3569 Some((m, p)) => {
3570 device_ip_layer_metadata = m;
3571 proof = p;
3572 }
3573 None => break,
3574 }
3575 }
3576
3577 Ok(())
3578}
3579
3580fn send_ip_frame_possibly_fragmented<I, CC, BC, S>(
3582 core_ctx: &mut CC,
3583 bindings_ctx: &mut BC,
3584 device: &CC::DeviceId,
3585 destination: IpPacketDestination<I, &CC::DeviceId>,
3586 body: S,
3587 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3588 mtu: Mtu,
3589 proof: ProofOfEgressCheck,
3590) -> Result<(), IpSendFrameError<S>>
3591where
3592 I: IpLayerIpExt,
3593 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3594 CC: IpLayerEgressContext<I, BC>,
3595 S: FragmentableIpSerializer<I, Buffer: BufferMut>,
3596{
3597 let body = body.with_size_limit(mtu.into());
3598
3599 let fits_mtu = match body.serialize_new_buf(
3600 &mut NetworkSerializationContext::default(),
3601 PacketConstraints::UNCONSTRAINED,
3602 AlwaysFailBufferAlloc,
3603 ) {
3604 Err(SerializeError::Alloc(())) => true,
3607 Err(SerializeError::SizeLimitExceeded) => false,
3609 };
3610
3611 if fits_mtu {
3612 return core_ctx
3613 .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
3614 .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
3615 serializer: serializer.into_inner(),
3616 error: error.into(),
3617 });
3618 }
3619
3620 core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
3623
3624 let body = body.into_inner();
3625 let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
3626 Ok(mut fragmenter) => {
3627 let mut device_ip_layer_metadata = device_ip_layer_metadata;
3628 loop {
3629 let Some((fragment, has_more)) = fragmenter.next() else {
3630 break Ok(());
3631 };
3632
3633 let (fragment_metadata, remaining_metadata) = if has_more {
3634 let SplitDeviceIpLayerMetadata { primary, secondary } =
3635 device_ip_layer_metadata.split_for_multiple_frames();
3636 (secondary, Some(primary))
3637 } else {
3638 (device_ip_layer_metadata, None)
3639 };
3640
3641 match core_ctx.send_ip_frame(
3642 bindings_ctx,
3643 device,
3644 destination.clone(),
3645 fragment_metadata,
3646 fragment,
3647 proof.clone_for_multiple_frames(),
3648 ) {
3649 Ok(()) => {
3650 core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
3651 }
3652 Err(ErrorAndSerializer { serializer: _, error }) => {
3653 core_ctx.increment_both(device, |c| {
3654 &c.fragmentation.error_fragmented_serializer
3655 });
3656 break Err(error);
3657 }
3658 }
3659
3660 match remaining_metadata {
3661 Some(m) => device_ip_layer_metadata = m,
3662 None => break Ok(()),
3663 }
3664 }
3665 }
3666 Err(e) => {
3667 core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
3668 Err(SendFrameErrorReason::SizeConstraintsViolation)
3669 }
3670 };
3671 result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
3672}
3673
3674struct AlwaysFailBufferAlloc;
3679
3680impl LayoutBufferAlloc<!> for AlwaysFailBufferAlloc {
3681 type Error = ();
3682 fn layout_alloc(self, _prefix: usize, _body: usize, _suffix: usize) -> Result<!, Self::Error> {
3683 Err(())
3684 }
3685}
3686
3687macro_rules! drop_packet_and_undo_parse {
3696 ($packet:expr, $buffer:expr) => {{
3697 let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
3698 $buffer.undo_parse(meta);
3699 (src_ip, dst_ip, proto, meta)
3700 }};
3701}
3702
3703enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
3706 Done,
3709
3710 NotNeeded(I::Packet<&'a mut [u8]>),
3713
3714 Reassembled { buffer: Vec<u8>, max_fragment_len: usize },
3717}
3718
3719fn process_fragment<'a, I, CC, BC>(
3725 core_ctx: &mut CC,
3726 bindings_ctx: &mut BC,
3727 device: &CC::DeviceId,
3728 packet: I::Packet<&'a mut [u8]>,
3729) -> ProcessFragmentResult<'a, I>
3730where
3731 I: IpLayerIpExt,
3732 for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3733 CC: IpLayerIngressContext<I, BC>,
3734 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3735{
3736 match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3737 FragmentProcessingState::NotNeeded(packet) => {
3739 trace!("receive_ip_packet: not fragmented");
3740 ProcessFragmentResult::NotNeeded(packet)
3741 }
3742 FragmentProcessingState::Ready { key, packet_len } => {
3744 trace!("receive_ip_packet: fragmented, ready for reassembly");
3745 let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3747
3748 let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3750 core_ctx,
3751 bindings_ctx,
3752 &key,
3753 buffer.buffer_view_mut(),
3754 ) {
3755 Ok(max_fragment_len) => ProcessFragmentResult::Reassembled {
3757 buffer: buffer.into_inner(),
3758 max_fragment_len,
3759 },
3760 Err(e) => {
3761 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3762 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3763 ProcessFragmentResult::Done
3764 }
3765 };
3766 reassemble_result
3767 }
3768 FragmentProcessingState::NeedMoreFragments => {
3771 core_ctx.increment_both(device, |c| &c.need_more_fragments);
3772 trace!("receive_ip_packet: fragmented, need more before reassembly");
3773 ProcessFragmentResult::Done
3774 }
3775 FragmentProcessingState::InvalidFragment => {
3777 core_ctx.increment_both(device, |c| &c.invalid_fragment);
3778 trace!("receive_ip_packet: fragmented, invalid");
3779 ProcessFragmentResult::Done
3780 }
3781 FragmentProcessingState::OutOfMemory => {
3782 core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3783 trace!("receive_ip_packet: fragmented, dropped because OOM");
3784 ProcessFragmentResult::Done
3785 }
3786 }
3787}
3788
3789fn reassemble_ipv6_atomic_fragment<B: SplitByteSlice>(
3808 packet: &Ipv6Packet<B>,
3809) -> Result<(Vec<u8>, usize), Ipv6ParseError> {
3810 let body = packet.body();
3811 let max_fragment_len = packet.header_len() + body.len();
3812 let header = packet.copy_header_bytes_for_fragment();
3813 let mut buffer = Buf::new(alloc::vec![0; header.len() + body.len()], ..);
3814 Ipv6Packet::reassemble_fragmented_packet(
3815 buffer.buffer_view_mut(),
3816 &header,
3817 core::iter::once(body),
3818 )?;
3819 Ok((buffer.into_inner(), max_fragment_len))
3820}
3821
3822macro_rules! try_parse_ip_packet {
3832 ($buffer:expr) => {{
3833 let p_len = $buffer.prefix_len();
3834 let s_len = $buffer.suffix_len();
3835
3836 let result = $buffer.parse_mut();
3837
3838 if let Err(err) = result {
3839 let n_p_len = $buffer.prefix_len();
3841 let n_s_len = $buffer.suffix_len();
3842
3843 if n_p_len > p_len {
3844 $buffer.grow_front(n_p_len - p_len);
3845 }
3846
3847 if n_s_len > s_len {
3848 $buffer.grow_back(n_s_len - s_len);
3849 }
3850
3851 Err(err)
3852 } else {
3853 result
3854 }
3855 }};
3856}
3857
3858macro_rules! clone_packet_for_mcast_forwarding {
3876 {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3877 let mut $new_data = $packet.to_vec();
3878 let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3879 let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3880 };
3881}
3882
3883pub fn receive_ipv4_packet<
3888 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3889 B: BufferMut,
3890 CC: IpLayerIngressContext<Ipv4, BC>,
3891>(
3892 core_ctx: &mut CC,
3893 bindings_ctx: &mut BC,
3894 device: &CC::DeviceId,
3895 frame_dst: Option<LocalFrameDestination>,
3896 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3897 parsing_context: NetworkParsingContext,
3898 gso_info: Option<GsoInfo>,
3899 buffer: B,
3900) {
3901 if !core_ctx.is_ip_device_enabled(&device) {
3902 return;
3903 }
3904
3905 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3908
3909 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3910 trace!("receive_ip_packet({device:?})");
3911
3912 let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3913 Ok(packet) => packet,
3914 Err(ParseError::Format)
3915 | Err(ParseError::Checksum)
3916 | Err(ParseError::NotSupported)
3917 | Err(ParseError::NotExpected) => {
3918 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3919 return;
3920 }
3921 };
3922
3923 if packet.src_ipv4().is_none() {
3927 debug!(
3928 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3929 packet.src_ip()
3930 );
3931 core_ctx.increment_both(device, |c| &c.invalid_source);
3932 return;
3933 };
3934 if !packet.dst_ip().is_specified() {
3935 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3936 debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3937 return;
3938 };
3939
3940 if !device.is_loopback()
3944 && (Ipv4::LOOPBACK_SUBNET.contains(&packet.src_ip())
3945 || Ipv4::LOOPBACK_SUBNET.contains(&packet.dst_ip()))
3946 {
3947 debug!(
3948 "receive_ipv4_packet: received loopback packet (src={}, dst={}) \
3949 on non-loopback interface; dropping",
3950 packet.src_ip(),
3951 packet.dst_ip(),
3952 );
3953 return;
3954 }
3955
3956 if let Some(src_ip) = SpecifiedAddr::new(packet.src_ip()) {
3959 let is_broadcast = core_ctx
3962 .address_status_for_device(src_ip, device)
3963 .into_present()
3964 .and_then(|status| status.to_broadcast_marker())
3965 .is_some();
3966
3967 if is_broadcast {
3968 debug!(
3969 "receive_ipv4_packet: received packet from broadcast source {}; dropping",
3970 packet.src_ip()
3971 );
3972 core_ctx.increment_both(device, |c| &c.invalid_source);
3973 return;
3974 }
3975 }
3976
3977 let (mut packet, max_fragment_len) =
3990 match process_fragment(core_ctx, bindings_ctx, device, packet) {
3991 ProcessFragmentResult::Done => return,
3992 ProcessFragmentResult::NotNeeded(packet) => (packet, None),
3993 ProcessFragmentResult::Reassembled { buffer: buf, max_fragment_len } => {
3994 let buf = Buf::new(buf, ..);
3995 buffer = packet::Either::B(buf);
3996
3997 match buffer.parse_mut() {
3998 Ok(packet) => (packet, Some(max_fragment_len)),
3999 Err(err) => {
4000 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4001 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
4002 return;
4003 }
4004 }
4005 }
4006 };
4007
4008 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
4011 core_ctx,
4012 device,
4013 device_ip_layer_metadata,
4014 gso_info,
4015 );
4016 let mut filter = core_ctx.filter_handler();
4017 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
4018 filter::Verdict::Proceed(filter::Accept) => {}
4019 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
4020 packet_metadata.acknowledge_drop();
4021 return;
4022 }
4023 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
4024 addr,
4025 port,
4026 }) => {
4027 drop(filter);
4030
4031 let Some(addr) = SpecifiedAddr::new(addr) else {
4032 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4033 debug!("cannot perform transparent delivery to unspecified destination; dropping");
4034 packet_metadata.acknowledge_drop();
4035 return;
4036 };
4037
4038 let receive_meta = ReceiveIpPacketMeta {
4039 broadcast: None,
4043 transparent_override: Some(TransparentLocalDelivery { addr, port }),
4044 parsing_context,
4045 };
4046
4047 dispatch_receive_ipv4_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_ipv4() else {
4068 core_ctx.increment_both(device, |c| &c.invalid_source);
4069 debug!(
4070 "receive_ipv4_packet: received packet from invalid source {}; dropping",
4071 packet.src_ip()
4072 );
4073 packet_metadata.acknowledge_drop();
4074 return;
4075 };
4076
4077 let action = receive_ipv4_packet_action(
4078 core_ctx,
4079 bindings_ctx,
4080 device,
4081 &packet,
4082 frame_dst,
4083 &packet_metadata.marks,
4084 max_fragment_len,
4085 );
4086 match action {
4087 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
4088 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
4094 clone_packet_for_mcast_forwarding! {
4095 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
4096 };
4097 let SplitMulticastPacketMetadata { primary: this_packet_metadata, secondary } =
4098 packet_metadata.split_for_multicast();
4099 packet_metadata = secondary;
4100 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
4101 core_ctx,
4102 copy_of_packet,
4103 this_packet_metadata,
4104 Some(*min_ttl),
4105 device,
4106 &output_interface,
4107 IpPacketDestination::from_addr(dst_ip),
4108 frame_dst,
4109 src_ip,
4110 dst_ip,
4111 )
4112 .perform_action_with_buffer(
4113 core_ctx,
4114 bindings_ctx,
4115 copy_of_buffer,
4116 max_fragment_len,
4117 );
4118 }
4119
4120 if let Some(address_status) = address_status {
4122 let receive_meta = ReceiveIpPacketMeta {
4123 broadcast: address_status.to_broadcast_marker(),
4124 transparent_override: None,
4125 parsing_context,
4126 };
4127 dispatch_receive_ipv4_packet(
4128 core_ctx,
4129 bindings_ctx,
4130 device,
4131 frame_dst,
4132 packet,
4133 packet_metadata,
4134 receive_meta,
4135 )
4136 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4137 } else {
4138 packet_metadata.acknowledge_drop();
4139 }
4140 }
4141 ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
4142 match internal_forwarding {
4145 InternalForwarding::Used(outbound_device) => {
4146 core_ctx.increment_both(device, |c| &c.forward);
4147 match core_ctx.filter_handler().forwarding_hook(
4148 &mut packet,
4149 device,
4150 &outbound_device,
4151 &mut packet_metadata,
4152 ) {
4153 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
4154 packet_metadata.acknowledge_drop();
4155 return;
4156 }
4157 filter::Verdict::Stop(filter::DropOrReject::Reject(_reject_type)) => {
4158 packet_metadata.acknowledge_drop();
4160 return;
4161 }
4162 filter::Verdict::Proceed(filter::Accept) => {}
4163 }
4164 }
4165 InternalForwarding::NotUsed => {}
4166 }
4167
4168 let receive_meta = ReceiveIpPacketMeta {
4169 broadcast: address_status.to_broadcast_marker(),
4170 transparent_override: None,
4171 parsing_context,
4172 };
4173 dispatch_receive_ipv4_packet(
4174 core_ctx,
4175 bindings_ctx,
4176 device,
4177 frame_dst,
4178 packet,
4179 packet_metadata,
4180 receive_meta,
4181 )
4182 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4183 }
4184 ReceivePacketAction::Forward {
4185 original_dst,
4186 dst: Destination { device: dst_device, next_hop },
4187 } => {
4188 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
4189 core_ctx,
4190 packet,
4191 packet_metadata,
4192 None,
4193 device,
4194 &dst_device,
4195 IpPacketDestination::from_next_hop(next_hop, original_dst),
4196 frame_dst,
4197 src_ip,
4198 original_dst,
4199 )
4200 .perform_action_with_buffer(
4201 core_ctx,
4202 bindings_ctx,
4203 buffer,
4204 max_fragment_len,
4205 );
4206 }
4207 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
4208 debug!("received IPv4 packet with no known route to destination {}", dst_ip);
4209
4210 let marks = packet_metadata.marks;
4211 packet_metadata.acknowledge_drop();
4212
4213 if let Some(sender) = IcmpErrorSender::new(
4214 core_ctx,
4215 Icmpv4Error::NetUnreachable,
4216 &packet,
4217 frame_dst,
4218 device,
4219 marks,
4220 ) {
4221 sender.send(core_ctx, bindings_ctx, buffer);
4222 }
4223 }
4224 ReceivePacketAction::Drop { reason } => {
4225 let src_ip = packet.src_ip();
4226 let dst_ip = packet.dst_ip();
4227 packet_metadata.acknowledge_drop();
4228 core_ctx.increment_both(device, |c| &c.dropped);
4229 debug!(
4230 "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
4231 {device:?}: {reason:?}",
4232 );
4233 }
4234 }
4235}
4236
4237fn handle_ipv6_parse_error<BC, B, CC>(
4238 core_ctx: &mut CC,
4239 bindings_ctx: &mut BC,
4240 device: &CC::DeviceId,
4241 frame_dst: Option<LocalFrameDestination>,
4242 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
4243 mut buffer: B,
4244 error: Ipv6ParseError,
4245) where
4246 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4247 B: BufferMut,
4248 CC: IpLayerIngressContext<Ipv6, BC>,
4249{
4250 let Ipv6ParseError::ParameterProblem { src_ip, dst_ip, code, pointer, must_send_icmp, action } =
4256 error
4257 else {
4258 core_ctx.increment_both(device, |c| &c.unparsable_packet);
4259 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
4260 return;
4261 };
4262 if !must_send_icmp || !action.should_send_icmp(&dst_ip) {
4263 return;
4264 }
4265 core_ctx.increment_both(device, |c| &c.parameter_problem);
4266 let dst_ip = match SocketIpAddr::new(dst_ip) {
4267 Some(ip) => ip,
4268 None => {
4269 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4270 debug!("receive_ipv6_packet: Dropping packet with unspecified destination IP");
4271 return;
4272 }
4273 };
4274
4275 let src_ip = match Ipv6SourceAddr::new(src_ip) {
4276 None => {
4277 core_ctx.increment_both(device, |c| &c.invalid_source);
4278 return;
4279 }
4280 Some(Ipv6SourceAddr::Unspecified) => {
4281 core_ctx.increment_both(device, |c| &c.unspecified_source);
4282 return;
4283 }
4284 Some(Ipv6SourceAddr::Unicast(src_ip)) => {
4285 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
4286 }
4287 };
4288
4289 let raw_packet: Ipv6PacketRaw<_> = match try_parse_ip_packet!(buffer) {
4292 Ok(packet) => packet,
4293 Err(error) => {
4294 core_ctx.increment_both(device, |c| &c.unparsable_packet);
4295 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
4296 return;
4297 }
4298 };
4299 let proto = match raw_packet.proto() {
4300 Ok(proto) => proto,
4301 Err(error) => {
4302 core_ctx.increment_both(device, |c| &c.unparsable_packet);
4303 debug!("receive_ipv6_packet: Failed to get protocol from IPv6 packet: {:?}", error);
4304 return;
4305 }
4306 };
4307 let parse_metadata = raw_packet.parse_metadata();
4308 let header_len = parse_metadata.header_len();
4309 buffer.undo_parse(parse_metadata);
4310
4311 let err = Icmpv6Error::ParameterProblem {
4312 code,
4313 pointer,
4314 allow_dst_multicast: action.should_send_icmp_to_multicast(),
4315 };
4316
4317 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
4318 core_ctx,
4319 bindings_ctx,
4320 Some(device),
4321 frame_dst,
4322 src_ip,
4323 dst_ip,
4324 buffer,
4325 err,
4326 header_len,
4327 proto,
4328 &device_ip_layer_metadata.marks,
4329 );
4330}
4331
4332pub fn receive_ipv6_packet<
4337 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4338 B: BufferMut,
4339 CC: IpLayerIngressContext<Ipv6, BC>,
4340>(
4341 core_ctx: &mut CC,
4342 bindings_ctx: &mut BC,
4343 device: &CC::DeviceId,
4344 frame_dst: Option<LocalFrameDestination>,
4345 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
4346 parsing_context: NetworkParsingContext,
4347 gso_info: Option<GsoInfo>,
4348 buffer: B,
4349) {
4350 if !core_ctx.is_ip_device_enabled(&device) {
4351 return;
4352 }
4353
4354 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
4357
4358 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
4359 trace!("receive_ipv6_packet({:?})", device);
4360
4361 let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
4362 Ok(packet) => packet,
4363 Err(error) => {
4364 handle_ipv6_parse_error(
4365 core_ctx,
4366 bindings_ctx,
4367 device,
4368 frame_dst,
4369 device_ip_layer_metadata,
4370 buffer,
4371 error,
4372 );
4373 return;
4374 }
4375 };
4376
4377 trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
4378
4379 if packet.src_ipv6().is_none() {
4385 debug!(
4386 "receive_ipv6_packet: received packet from invalid source {}; dropping",
4387 packet.src_ip()
4388 );
4389 core_ctx.increment_both(device, |c| &c.invalid_source);
4390 return;
4391 };
4392 if !packet.dst_ip().is_specified() {
4393 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4394 debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
4395 return;
4396 };
4397
4398 if !device.is_loopback()
4406 && (Ipv6::LOOPBACK_SUBNET.contains(&packet.src_ip())
4407 || Ipv6::LOOPBACK_SUBNET.contains(&packet.dst_ip()))
4408 {
4409 debug!(
4410 "receive_ipv6_packet: received loopback packet (src={}, dst={}) \
4411 on non-loopback interface; dropping",
4412 packet.src_ip(),
4413 packet.dst_ip(),
4414 );
4415 return;
4416 }
4417
4418 let (mut packet, delivery_extension_header_action, max_fragment_len) =
4429 match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
4430 Ipv6PacketAction::_Discard => {
4431 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4432 trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
4433 return;
4434 }
4435 Ipv6PacketAction::Continue => {
4436 trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
4437 (packet, Some(Ipv6PacketAction::Continue), None)
4438 }
4439 Ipv6PacketAction::ProcessFragment => {
4440 trace!(
4441 "receive_ipv6_packet: handled IPv6 extension headers: handling \
4442 fragmented packet"
4443 );
4444
4445 let (buf, max_fragment_len) =
4457 match process_fragment(core_ctx, bindings_ctx, device, packet) {
4458 ProcessFragmentResult::Done => return,
4459 ProcessFragmentResult::NotNeeded(packet) => {
4460 match reassemble_ipv6_atomic_fragment(&packet) {
4468 Ok(result) => result,
4469 Err(err) => {
4470 core_ctx
4471 .increment_both(device, |c| &c.fragment_reassembly_error);
4472 debug!(
4473 "receive_ip_packet: failed to reassemble atomic \
4474 fragment: {:?}",
4475 err
4476 );
4477 return;
4478 }
4479 }
4480 }
4481 ProcessFragmentResult::Reassembled { buffer: buf, max_fragment_len } => {
4482 (buf, max_fragment_len)
4483 }
4484 };
4485
4486 let buf = Buf::new(buf, ..);
4487 buffer = packet::Either::B(buf);
4488
4489 match try_parse_ip_packet!(buffer) {
4493 Ok(packet) => {
4494 let packet: Ipv6Packet<_> = packet;
4495 if packet
4498 .iter_extension_hdrs()
4499 .any(|h| matches!(h, Ipv6ExtensionHeader::Fragment { .. }))
4500 {
4501 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4502 debug!(
4503 "receive_ipv6_packet: found fragment header after reassembly; \
4504 dropping"
4505 );
4506 return;
4507 }
4508 (packet, None, Some(max_fragment_len))
4509 }
4510 Err(error) => {
4511 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4512 debug!(
4513 "receive_ip_packet: fragmented, failed to parse reassembled packet: \
4514 {:?}",
4515 error
4516 );
4517 handle_ipv6_parse_error(
4518 core_ctx,
4519 bindings_ctx,
4520 device,
4521 frame_dst,
4522 device_ip_layer_metadata,
4523 buffer,
4524 error,
4525 );
4526 return;
4527 }
4528 }
4529 }
4530 };
4531
4532 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
4533 core_ctx,
4534 device,
4535 device_ip_layer_metadata,
4536 gso_info,
4537 );
4538 let mut filter = core_ctx.filter_handler();
4539
4540 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
4541 filter::Verdict::Proceed(filter::Accept) => {}
4542 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
4543 packet_metadata.acknowledge_drop();
4544 return;
4545 }
4546 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
4547 addr,
4548 port,
4549 }) => {
4550 drop(filter);
4553
4554 let Some(addr) = SpecifiedAddr::new(addr) else {
4555 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4556 debug!("cannot perform transparent delivery to unspecified destination; dropping");
4557 packet_metadata.acknowledge_drop();
4558 return;
4559 };
4560
4561 let receive_meta = ReceiveIpPacketMeta {
4562 broadcast: None,
4563 transparent_override: Some(TransparentLocalDelivery { addr, port }),
4564 parsing_context,
4565 };
4566
4567 dispatch_receive_ipv6_packet(
4571 core_ctx,
4572 bindings_ctx,
4573 device,
4574 frame_dst,
4575 packet,
4576 packet_metadata,
4577 receive_meta,
4578 )
4579 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4580 return;
4581 }
4582 }
4583 drop(filter);
4586
4587 let Some(src_ip) = packet.src_ipv6() else {
4588 debug!(
4589 "receive_ipv6_packet: received packet from invalid source {}; dropping",
4590 packet.src_ip()
4591 );
4592 core_ctx.increment_both(device, |c| &c.invalid_source);
4593 packet_metadata.acknowledge_drop();
4594 return;
4595 };
4596
4597 match receive_ipv6_packet_action(
4598 core_ctx,
4599 bindings_ctx,
4600 device,
4601 &packet,
4602 frame_dst,
4603 &packet_metadata.marks,
4604 max_fragment_len,
4605 ) {
4606 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
4607 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
4613 clone_packet_for_mcast_forwarding! {
4614 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
4615 };
4616 let SplitMulticastPacketMetadata { primary: this_packet_metadata, secondary } =
4617 packet_metadata.split_for_multicast();
4618 packet_metadata = secondary;
4619 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4620 core_ctx,
4621 copy_of_packet,
4622 this_packet_metadata,
4623 Some(*min_ttl),
4624 device,
4625 &output_interface,
4626 IpPacketDestination::from_addr(dst_ip),
4627 frame_dst,
4628 src_ip,
4629 dst_ip,
4630 )
4631 .perform_action_with_buffer(
4632 core_ctx,
4633 bindings_ctx,
4634 copy_of_buffer,
4635 max_fragment_len,
4636 );
4637 }
4638
4639 if let Some(_) = address_status {
4641 let receive_meta = ReceiveIpPacketMeta {
4642 broadcast: None,
4643 transparent_override: None,
4644 parsing_context,
4645 };
4646
4647 dispatch_receive_ipv6_packet(
4648 core_ctx,
4649 bindings_ctx,
4650 device,
4651 frame_dst,
4652 packet,
4653 packet_metadata,
4654 receive_meta,
4655 )
4656 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4657 } else {
4658 packet_metadata.acknowledge_drop();
4659 }
4660 }
4661 ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
4662 trace!("receive_ipv6_packet: delivering locally");
4663
4664 let action = if let Some(action) = delivery_extension_header_action {
4665 action
4666 } else {
4667 ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
4668 };
4669 match action {
4670 Ipv6PacketAction::_Discard => {
4671 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4672 trace!(
4673 "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
4674 );
4675 packet_metadata.acknowledge_drop();
4676 }
4677 Ipv6PacketAction::Continue => {
4678 trace!(
4679 "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
4680 );
4681
4682 match internal_forwarding {
4685 InternalForwarding::Used(outbound_device) => {
4686 core_ctx.increment_both(device, |c| &c.forward);
4687 match core_ctx.filter_handler().forwarding_hook(
4688 &mut packet,
4689 device,
4690 &outbound_device,
4691 &mut packet_metadata,
4692 ) {
4693 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
4694 packet_metadata.acknowledge_drop();
4695 return;
4696 }
4697 filter::Verdict::Stop(filter::DropOrReject::Reject(
4698 _reject_type,
4699 )) => {
4700 packet_metadata.acknowledge_drop();
4702 return;
4703 }
4704 filter::Verdict::Proceed(filter::Accept) => {}
4705 }
4706 }
4707 InternalForwarding::NotUsed => {}
4708 }
4709
4710 let meta = ReceiveIpPacketMeta {
4711 broadcast: None,
4712 transparent_override: None,
4713 parsing_context,
4714 };
4715 dispatch_receive_ipv6_packet(
4716 core_ctx,
4717 bindings_ctx,
4718 device,
4719 frame_dst,
4720 packet,
4721 packet_metadata,
4722 meta,
4723 )
4724 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4725 }
4726 Ipv6PacketAction::ProcessFragment => {
4727 unreachable!("found fragment header after reassembly")
4730 }
4731 }
4732 }
4733 ReceivePacketAction::Forward {
4734 original_dst,
4735 dst: Destination { device: dst_device, next_hop },
4736 } => {
4737 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4738 core_ctx,
4739 packet,
4740 packet_metadata,
4741 None,
4742 device,
4743 &dst_device,
4744 IpPacketDestination::from_next_hop(next_hop, original_dst),
4745 frame_dst,
4746 src_ip,
4747 original_dst,
4748 )
4749 .perform_action_with_buffer(
4750 core_ctx,
4751 bindings_ctx,
4752 buffer,
4753 max_fragment_len,
4754 );
4755 }
4756 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
4757 let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
4758 drop_packet_and_undo_parse!(packet, buffer);
4759 debug!("received IPv6 packet with no known route to destination {}", dst_ip);
4760 let marks = packet_metadata.marks;
4761 packet_metadata.acknowledge_drop();
4762
4763 let src_ip = match src_ip {
4764 Ipv6SourceAddr::Unspecified => {
4765 core_ctx.increment_both(device, |c| &c.unspecified_source);
4766 return;
4767 }
4768 Ipv6SourceAddr::Unicast(src_ip) => {
4769 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
4770 }
4771 };
4772
4773 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
4774 core_ctx,
4775 bindings_ctx,
4776 Some(device),
4777 frame_dst,
4778 src_ip,
4779 SocketIpAddr::new_from_witness(dst_ip),
4780 buffer,
4781 Icmpv6Error::NetUnreachable,
4782 meta.header_len(),
4783 proto,
4784 &marks,
4785 );
4786 }
4787 ReceivePacketAction::Drop { reason } => {
4788 core_ctx.increment_both(device, |c| &c.dropped);
4789 let src_ip = packet.src_ip();
4790 let dst_ip = packet.dst_ip();
4791 packet_metadata.acknowledge_drop();
4792 debug!(
4793 "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
4794 {device:?}: {reason:?}",
4795 );
4796 }
4797 }
4798}
4799
4800#[derive(Debug, PartialEq)]
4802pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
4803 Deliver {
4805 address_status: I::AddressStatus,
4807 internal_forwarding: InternalForwarding<DeviceId>,
4810 },
4811
4812 Forward {
4814 original_dst: SpecifiedAddr<I::Addr>,
4816 dst: Destination<I::Addr, DeviceId>,
4818 },
4819
4820 MulticastForward {
4828 targets: MulticastRouteTargets<DeviceId>,
4830 address_status: Option<I::AddressStatus>,
4833 dst_ip: SpecifiedAddr<I::Addr>,
4835 },
4836
4837 SendNoRouteToDest {
4843 dst: NonMappedAddr<SpecifiedAddr<I::Addr>>,
4845 },
4846
4847 #[allow(missing_docs)]
4851 Drop { reason: DropReason },
4852}
4853
4854fn choose_highest_priority_address_status<I: IpLayerIpExt>(
4857 address_statuses: impl Iterator<Item = I::AddressStatus>,
4858) -> Option<I::AddressStatus> {
4859 address_statuses.max_by_key(|status| {
4860 #[derive(GenericOverIp)]
4861 #[generic_over_ip(I, Ip)]
4862 struct Wrap<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
4863 I::map_ip_in(
4864 Wrap(status),
4865 |Wrap(v4_status)| match v4_status {
4866 Ipv4PresentAddressStatus::UnicastTentative => 0,
4867 _ => 1,
4868 },
4869 |Wrap(v6_status)| match v6_status {
4870 Ipv6PresentAddressStatus::UnicastTentative => 0,
4871 _ => 1,
4872 },
4873 )
4874 })
4875}
4876
4877#[derive(Debug, PartialEq)]
4879pub enum DropReason {
4880 Tentative,
4882 UnspecifiedDestination,
4884 InvalidDestination,
4886 ForwardUnspecifiedSource,
4888 ForwardLinkLocal,
4890 ForwardingDisabledInboundIface,
4893 MulticastNoInterest,
4899}
4900
4901pub fn receive_ipv4_packet_action<BC, CC, B>(
4903 core_ctx: &mut CC,
4904 bindings_ctx: &mut BC,
4905 device: &CC::DeviceId,
4906 packet: &Ipv4Packet<B>,
4907 frame_dst: Option<LocalFrameDestination>,
4908 marks: &Marks,
4909 max_fragment_len: Option<usize>,
4910) -> ReceivePacketAction<Ipv4, CC::DeviceId>
4911where
4912 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
4913 CC: IpLayerContext<Ipv4, BC>,
4914 B: SplitByteSlice,
4915{
4916 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4917 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4918 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4919 };
4920
4921 let highest_priority = if device.is_loopback() {
4934 core_ctx.with_address_statuses(dst_ip, |it| {
4935 let it = it.map(|(_device, status)| status);
4936 choose_highest_priority_address_status::<Ipv4>(it)
4937 })
4938 } else {
4939 core_ctx.address_status_for_device(dst_ip, device).into_present()
4940 };
4941 match highest_priority {
4942 Some(
4943 address_status @ (Ipv4PresentAddressStatus::UnicastAssigned
4944 | Ipv4PresentAddressStatus::LoopbackSubnet),
4945 ) => {
4946 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4947 ReceivePacketAction::Deliver {
4948 address_status,
4949 internal_forwarding: InternalForwarding::NotUsed,
4950 }
4951 }
4952 Some(Ipv4PresentAddressStatus::UnicastTentative) => {
4953 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4959 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4960 }
4961
4962 Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4963 receive_ip_multicast_packet_action(
4964 core_ctx,
4965 bindings_ctx,
4966 device,
4967 packet,
4968 Some(address_status),
4969 dst_ip,
4970 frame_dst,
4971 *marks,
4972 max_fragment_len,
4973 )
4974 }
4975 Some(
4976 address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4977 | Ipv4PresentAddressStatus::SubnetBroadcast),
4978 ) => {
4979 core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
4980 ReceivePacketAction::Deliver {
4981 address_status,
4982 internal_forwarding: InternalForwarding::NotUsed,
4983 }
4984 }
4985 None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4986 core_ctx,
4987 bindings_ctx,
4988 dst_ip,
4989 device,
4990 packet,
4991 frame_dst,
4992 marks,
4993 max_fragment_len,
4994 ),
4995 }
4996}
4997
4998pub fn receive_ipv6_packet_action<BC, CC, B>(
5000 core_ctx: &mut CC,
5001 bindings_ctx: &mut BC,
5002 device: &CC::DeviceId,
5003 packet: &Ipv6Packet<B>,
5004 frame_dst: Option<LocalFrameDestination>,
5005 marks: &Marks,
5006 max_fragment_len: Option<usize>,
5007) -> ReceivePacketAction<Ipv6, CC::DeviceId>
5008where
5009 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
5010 CC: IpLayerContext<Ipv6, BC>,
5011 B: SplitByteSlice,
5012{
5013 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
5014 core_ctx.increment_both(device, |c| &c.unspecified_destination);
5015 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
5016 };
5017
5018 let highest_priority = if device.is_loopback() {
5031 core_ctx.with_address_statuses(dst_ip, |it| {
5032 let it = it.map(|(_device, status)| status);
5033 choose_highest_priority_address_status::<Ipv6>(it)
5034 })
5035 } else {
5036 core_ctx.address_status_for_device(dst_ip, device).into_present()
5037 };
5038 match highest_priority {
5039 Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
5040 receive_ip_multicast_packet_action(
5041 core_ctx,
5042 bindings_ctx,
5043 device,
5044 packet,
5045 Some(address_status),
5046 dst_ip,
5047 frame_dst,
5048 *marks,
5049 max_fragment_len,
5050 )
5051 }
5052 Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
5053 core_ctx.increment_both(device, |c| &c.deliver_unicast);
5054 ReceivePacketAction::Deliver {
5055 address_status,
5056 internal_forwarding: InternalForwarding::NotUsed,
5057 }
5058 }
5059 Some(Ipv6PresentAddressStatus::UnicastTentative) => {
5060 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
5091 ReceivePacketAction::Drop { reason: DropReason::Tentative }
5092 }
5093 None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
5094 core_ctx,
5095 bindings_ctx,
5096 dst_ip,
5097 device,
5098 packet,
5099 frame_dst,
5100 marks,
5101 max_fragment_len,
5102 ),
5103 }
5104}
5105
5106fn receive_ip_multicast_packet_action<
5109 I: IpLayerIpExt,
5110 B: SplitByteSlice,
5111 BC: IpLayerBindingsContext<I, CC::DeviceId>,
5112 CC: IpLayerContext<I, BC>,
5113>(
5114 core_ctx: &mut CC,
5115 bindings_ctx: &mut BC,
5116 device: &CC::DeviceId,
5117 packet: &I::Packet<B>,
5118 address_status: Option<I::AddressStatus>,
5119 dst_ip: SpecifiedAddr<I::Addr>,
5120 frame_dst: Option<LocalFrameDestination>,
5121 marks: Marks,
5122 max_fragment_len: Option<usize>,
5123) -> ReceivePacketAction<I, CC::DeviceId> {
5124 let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
5125 core_ctx,
5126 bindings_ctx,
5127 packet,
5128 device,
5129 frame_dst,
5130 max_fragment_len,
5131 marks,
5132 );
5133 match (targets, address_status) {
5134 (Some(targets), address_status) => {
5135 if address_status.is_some() {
5136 core_ctx.increment_both(device, |c| &c.deliver_multicast);
5137 }
5138 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
5139 }
5140 (None, Some(address_status)) => {
5141 core_ctx.increment_both(device, |c| &c.deliver_multicast);
5144 ReceivePacketAction::Deliver {
5145 address_status,
5146 internal_forwarding: InternalForwarding::NotUsed,
5147 }
5148 }
5149 (None, None) => {
5150 core_ctx.increment_both(device, |c| &c.multicast_no_interest);
5159 ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
5160 }
5161 }
5162}
5163
5164fn receive_ip_packet_action_common<
5167 I: IpLayerIpExt,
5168 B: SplitByteSlice,
5169 BC: IpLayerBindingsContext<I, CC::DeviceId>,
5170 CC: IpLayerContext<I, BC>,
5171>(
5172 core_ctx: &mut CC,
5173 bindings_ctx: &mut BC,
5174 dst_ip: SpecifiedAddr<I::Addr>,
5175 device_id: &CC::DeviceId,
5176 packet: &I::Packet<B>,
5177 frame_dst: Option<LocalFrameDestination>,
5178 marks: &Marks,
5179 max_fragment_len: Option<usize>,
5180) -> ReceivePacketAction<I, CC::DeviceId> {
5181 if dst_ip.is_multicast() {
5182 return receive_ip_multicast_packet_action(
5183 core_ctx,
5184 bindings_ctx,
5185 device_id,
5186 packet,
5187 None,
5188 dst_ip,
5189 frame_dst,
5190 *marks,
5191 max_fragment_len,
5192 );
5193 }
5194
5195 let Some(dst_ip) = NonMappedAddr::new(dst_ip) else {
5197 return ReceivePacketAction::Drop { reason: DropReason::InvalidDestination };
5198 };
5199
5200 if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
5202 core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
5215 return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
5216 }
5217 let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
5224 return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
5225 };
5226
5227 if let Some(dst_ip) = NonMulticastAddr::new(dst_ip) {
5234 if let Some((outbound_device, address_status)) =
5235 get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
5236 {
5237 return ReceivePacketAction::Deliver {
5238 address_status,
5239 internal_forwarding: InternalForwarding::Used(outbound_device),
5240 };
5241 }
5242 }
5243
5244 if I::map_ip_in(
5259 &packet,
5260 |_| false,
5261 |packet| packet.src_ip().is_link_local() || packet.dst_ip().is_link_local(),
5262 ) {
5263 return ReceivePacketAction::Drop { reason: DropReason::ForwardLinkLocal };
5264 }
5265
5266 match lookup_route_table(
5267 core_ctx,
5268 dst_ip.get(),
5269 RuleInput {
5270 packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
5271 marks,
5272 },
5273 ) {
5274 Some(dst) => {
5275 core_ctx.increment_both(device_id, |c| &c.forward);
5276 ReceivePacketAction::Forward { original_dst: *dst_ip, dst }
5277 }
5278 None => {
5279 core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
5280 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
5281 }
5282 }
5283}
5284
5285fn lookup_route_table<
5287 I: IpLayerIpExt,
5288 BC: IpLayerBindingsContext<I, CC::DeviceId>,
5289 CC: IpStateContext<I, BC>,
5290>(
5291 core_ctx: &mut CC,
5292 dst_ip: I::Addr,
5293 rule_input: RuleInput<'_, I, CC::DeviceId>,
5294) -> Option<Destination<I::Addr, CC::DeviceId>> {
5295 let bound_device = match rule_input.packet_origin {
5296 PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
5297 PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
5298 };
5299 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
5300 match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
5301 match table.lookup(core_ctx, bound_device, dst_ip) {
5302 Some(dst) => ControlFlow::Break(Some(dst)),
5303 None => ControlFlow::Continue(()),
5304 }
5305 }) {
5306 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
5307 inner: dst,
5308 observed_source_address_matcher: _,
5309 })) => dst,
5310 ControlFlow::Break(RuleAction::Unreachable) => None,
5311 ControlFlow::Continue(RuleWalkInfo {
5312 inner: (),
5313 observed_source_address_matcher: _,
5314 }) => None,
5315 }
5316 })
5317}
5318
5319#[derive(Debug, Derivative, Clone)]
5321#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
5322pub enum IpPacketDestination<I: BroadcastIpExt, D> {
5323 Broadcast(I::BroadcastMarker),
5325
5326 Multicast(MulticastAddr<I::Addr>),
5328
5329 Neighbor(SpecifiedAddr<I::Addr>),
5332
5333 Loopback(D),
5336}
5337
5338impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
5339 pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
5341 match MulticastAddr::new(addr.into_addr()) {
5342 Some(mc_addr) => Self::Multicast(mc_addr),
5343 None => Self::Neighbor(addr),
5344 }
5345 }
5346
5347 pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
5349 match next_hop {
5350 NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
5351 NextHop::Gateway(gateway) => Self::Neighbor(gateway),
5352 NextHop::Broadcast(marker) => Self::Broadcast(marker),
5353 }
5354 }
5355}
5356
5357#[derive(Debug, Clone)]
5359pub struct SendIpPacketMeta<I: IpExt, D, Src> {
5360 pub device: D,
5362
5363 pub src_ip: Src,
5365
5366 pub dst_ip: SpecifiedAddr<I::Addr>,
5368
5369 pub destination: IpPacketDestination<I, D>,
5371
5372 pub proto: I::Proto,
5374
5375 pub ttl: Option<NonZeroU8>,
5379
5380 pub mtu: Mtu,
5385
5386 pub dscp_and_ecn: DscpAndEcn,
5388}
5389
5390impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5391 for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
5392{
5393 fn from(
5394 SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
5395 I,
5396 D,
5397 SpecifiedAddr<I::Addr>,
5398 >,
5399 ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
5400 SendIpPacketMeta {
5401 device,
5402 src_ip: Some(src_ip),
5403 dst_ip,
5404 destination,
5405 proto,
5406 ttl,
5407 mtu,
5408 dscp_and_ecn,
5409 }
5410 }
5411}
5412
5413pub trait IpLayerHandler<I: IpExt + FragmentationIpExt + GsoIpExt + FilterIpExt, BC>:
5419 DeviceIdContext<AnyDevice>
5420{
5421 fn send_ip_packet_from_device<S>(
5424 &mut self,
5425 bindings_ctx: &mut BC,
5426 meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
5427 body: S,
5428 ) -> Result<(), IpSendFrameError<S>>
5429 where
5430 S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
5431 S::Buffer: BufferMut;
5432
5433 fn send_ip_frame<S>(
5440 &mut self,
5441 bindings_ctx: &mut BC,
5442 device: &Self::DeviceId,
5443 destination: IpPacketDestination<I, &Self::DeviceId>,
5444 body: S,
5445 ) -> Result<(), IpSendFrameError<S>>
5446 where
5447 S: FragmentableIpSerializer<I, Buffer: BufferMut>
5448 + MaybeSegmentableIpSerializer<I>
5449 + FilterIpPacket<I>;
5450}
5451
5452impl<I, BC, CC> IpLayerHandler<I, BC> for CC
5453where
5454 I: IpLayerIpExt,
5455 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
5456 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
5457{
5458 fn send_ip_packet_from_device<S>(
5459 &mut self,
5460 bindings_ctx: &mut BC,
5461 meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
5462 body: S,
5463 ) -> Result<(), IpSendFrameError<S>>
5464 where
5465 S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
5466 S::Buffer: BufferMut,
5467 {
5468 send_ip_packet_from_device(
5469 self,
5470 bindings_ctx,
5471 meta,
5472 body,
5473 IpLayerPacketMetadata::new_local_tx(Default::default(), Default::default(), None),
5474 )
5475 }
5476
5477 fn send_ip_frame<S>(
5478 &mut self,
5479 bindings_ctx: &mut BC,
5480 device: &Self::DeviceId,
5481 destination: IpPacketDestination<I, &Self::DeviceId>,
5482 body: S,
5483 ) -> Result<(), IpSendFrameError<S>>
5484 where
5485 S: FragmentableIpSerializer<I, Buffer: BufferMut>
5486 + MaybeSegmentableIpSerializer<I>
5487 + FilterIpPacket<I>,
5488 {
5489 send_ip_frame(
5490 self,
5491 bindings_ctx,
5492 device,
5493 destination,
5494 body,
5495 IpLayerPacketMetadata::new_local_tx(Default::default(), Default::default(), None),
5496 Mtu::no_limit(),
5497 )
5498 }
5499}
5500
5501pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
5508 core_ctx: &mut CC,
5509 bindings_ctx: &mut BC,
5510 meta: SendIpPacketMeta<
5511 I,
5512 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
5513 Option<SpecifiedAddr<I::Addr>>,
5514 >,
5515 body: S,
5516 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
5517) -> Result<(), IpSendFrameError<S>>
5518where
5519 I: IpLayerIpExt,
5520 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
5521 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
5522 S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
5523 S::Buffer: BufferMut,
5524{
5525 let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
5526 meta;
5527 core_ctx.increment_both(device, |c| &c.send_ip_packet);
5528 let next_packet_id = gen_ip_packet_id(core_ctx);
5529 let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
5530 let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
5531 let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
5532
5533 #[derive(GenericOverIp)]
5534 #[generic_over_ip(I, Ip)]
5535 struct Wrap<'a, I: IpLayerIpExt> {
5536 builder: &'a mut I::PacketBuilder<NetworkSerializationContext>,
5537 next_packet_id: I::PacketId,
5538 }
5539
5540 I::map_ip::<_, ()>(
5541 Wrap { builder: &mut builder, next_packet_id },
5542 |Wrap { builder, next_packet_id }| {
5543 builder.id(next_packet_id);
5544 },
5545 |Wrap { builder: _, next_packet_id: () }| {
5546 },
5548 );
5549
5550 builder.set_dscp_and_ecn(dscp_and_ecn);
5551
5552 let ip_frame = builder.wrap_body(body);
5553 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
5554 .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
5555}
5556
5557pub trait FilterHandlerProvider<I: FilterIpExt, BT: FilterBindingsTypes>:
5559 IpDeviceAddressIdContext<I, DeviceId: netstack3_base::InterfaceProperties<BT::DeviceClass>>
5560{
5561 type Handler<'a>: filter::FilterHandler<I, BT, DeviceId = Self::DeviceId, WeakAddressId = Self::WeakAddressId>
5563 where
5564 Self: 'a;
5565
5566 fn filter_handler(&mut self) -> Self::Handler<'_>;
5568}
5569
5570#[cfg(any(test, feature = "testutils"))]
5571pub(crate) mod testutil {
5572 use super::*;
5573
5574 use netstack3_base::testutil::{FakeBindingsCtx, FakeCoreCtx, FakeStrongDeviceId};
5575 use netstack3_base::{
5576 AssignedAddrIpExt, NetworkSerializer, SendFrameContext, SendFrameError, SendableFrameMeta,
5577 };
5578
5579 #[derive(Debug, GenericOverIp)]
5581 #[generic_over_ip()]
5582 #[allow(missing_docs)]
5583 pub enum DualStackSendIpPacketMeta<D> {
5584 V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
5585 V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
5586 }
5587
5588 impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5589 for DualStackSendIpPacketMeta<D>
5590 {
5591 fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
5592 #[derive(GenericOverIp)]
5593 #[generic_over_ip(I, Ip)]
5594 struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
5595 use DualStackSendIpPacketMeta::*;
5596 I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
5597 }
5598 }
5599
5600 impl<I: IpExt, S, DeviceId, BC>
5601 SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
5602 for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
5603 {
5604 fn send_meta<SS>(
5605 self,
5606 core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
5607 bindings_ctx: &mut BC,
5608 frame: SS,
5609 ) -> Result<(), SendFrameError<SS>>
5610 where
5611 SS: NetworkSerializer,
5612 SS::Buffer: BufferMut,
5613 {
5614 SendFrameContext::send_frame(
5615 &mut core_ctx.frames,
5616 bindings_ctx,
5617 DualStackSendIpPacketMeta::from(self),
5618 frame,
5619 )
5620 }
5621 }
5622
5623 #[derive(Debug)]
5625 pub struct WrongIpVersion;
5626
5627 impl<D> DualStackSendIpPacketMeta<D> {
5628 pub fn try_as<I: IpExt>(
5631 &self,
5632 ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
5633 #[derive(GenericOverIp)]
5634 #[generic_over_ip(I, Ip)]
5635 struct Wrap<'a, I: IpExt, D>(
5636 Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
5637 );
5638 use DualStackSendIpPacketMeta::*;
5639 let Wrap(dual_stack) = I::map_ip(
5640 self,
5641 |value| {
5642 Wrap(match value {
5643 V4(meta) => Some(meta),
5644 V6(_) => None,
5645 })
5646 },
5647 |value| {
5648 Wrap(match value {
5649 V4(_) => None,
5650 V6(meta) => Some(meta),
5651 })
5652 },
5653 );
5654 dual_stack.ok_or(WrongIpVersion)
5655 }
5656 }
5657
5658 impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
5659 where
5660 I: AssignedAddrIpExt + FilterIpExt,
5661 BC: FilterBindingsContext<DeviceId>,
5662 DeviceId: FakeStrongDeviceId + netstack3_base::InterfaceProperties<BC::DeviceClass>,
5663 {
5664 type Handler<'a>
5665 = filter::testutil::NoopImpl<DeviceId>
5666 where
5667 Self: 'a;
5668
5669 fn filter_handler(&mut self) -> Self::Handler<'_> {
5670 filter::testutil::NoopImpl::default()
5671 }
5672 }
5673
5674 impl<TimerId, Event: Debug, State, FrameMeta> MarksBindingsContext
5675 for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
5676 {
5677 fn marks_to_keep_on_egress() -> &'static [MarkDomain] {
5678 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark1];
5679 &MARKS
5680 }
5681
5682 fn marks_to_set_on_ingress() -> &'static [MarkDomain] {
5683 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark2];
5684 &MARKS
5685 }
5686 }
5687}
5688
5689#[cfg(test)]
5690mod test {
5691 use super::*;
5692
5693 #[test]
5694 fn highest_priority_address_status_v4() {
5695 assert_eq!(
5697 choose_highest_priority_address_status::<Ipv4>(
5698 [
5699 Ipv4PresentAddressStatus::UnicastAssigned,
5700 Ipv4PresentAddressStatus::UnicastTentative
5701 ]
5702 .into_iter()
5703 ),
5704 Some(Ipv4PresentAddressStatus::UnicastAssigned)
5705 )
5706 }
5707
5708 #[test]
5709 fn highest_priority_address_status_v6() {
5710 assert_eq!(
5712 choose_highest_priority_address_status::<Ipv6>(
5713 [
5714 Ipv6PresentAddressStatus::UnicastAssigned,
5715 Ipv6PresentAddressStatus::UnicastTentative
5716 ]
5717 .into_iter()
5718 ),
5719 Some(Ipv6PresentAddressStatus::UnicastAssigned)
5720 )
5721 }
5722}