1use alloc::boxed::Box;
6use alloc::vec::Vec;
7use core::convert::Infallible as Never;
8use core::fmt::Debug;
9use core::hash::Hash;
10use core::marker::PhantomData;
11use core::num::NonZeroU8;
12use core::ops::ControlFlow;
13#[cfg(test)]
14use core::ops::DerefMut;
15use core::sync::atomic::{self, AtomicU16};
16
17use derivative::Derivative;
18use explicit::ResultExt as _;
19use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
20use log::{debug, trace};
21use net_types::ip::{
22 GenericOverIp, Ip, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu, Subnet,
23};
24use net_types::{
25 LinkLocalAddress, MulticastAddr, MulticastAddress, NonMappedAddr, NonMulticastAddr,
26 SpecifiedAddr, SpecifiedAddress as _, Witness,
27};
28use netstack3_base::socket::SocketIpAddrExt as _;
29use netstack3_base::sync::{Mutex, PrimaryRc, RwLock, StrongRc, WeakRc};
30use netstack3_base::{
31 AnyDevice, BroadcastIpExt, CoreTimerContext, Counter, CounterCollectionSpec, CounterContext,
32 DeviceIdContext, DeviceIdentifier as _, ErrorAndSerializer, EventContext, FrameDestination,
33 HandleableTimer, InstantContext, InterfaceProperties, IpAddressId, IpDeviceAddr,
34 IpDeviceAddressIdContext, IpExt, MarkDomain, Marks, Matcher as _, MatcherBindingsTypes,
35 NestedIntoCoreTimerCtx, NotFoundError, ResourceCounterContext, RngContext,
36 SendFrameErrorReason, StrongDeviceIdentifier, TimerBindingsTypes, TimerContext, TimerHandler,
37 TxMetadataBindingsTypes, WeakIpAddressId, WrapBroadcastMarker,
38};
39use netstack3_filter::{
40 self as filter, ConnectionDirection, ConntrackConnection, FilterBindingsContext,
41 FilterBindingsTypes, FilterHandler as _, FilterIpContext, FilterIpExt, FilterIpMetadata,
42 FilterMarkMetadata, FilterTimerId, ForwardedPacket, IngressVerdict, IpPacket, MarkAction,
43 TransportPacketSerializer, Tuple, WeakConnectionError, WeakConntrackConnection,
44};
45use netstack3_hashmap::HashMap;
46use packet::{
47 Buf, BufferMut, GrowBuffer, LayoutBufferAlloc, PacketBuilder as _, PacketConstraints,
48 ParseBufferMut, ParseMetadata, SerializeError, Serializer as _,
49};
50use packet_formats::error::IpParseError;
51use packet_formats::ip::{DscpAndEcn, IpPacket as _, IpPacketBuilder as _};
52use packet_formats::ipv4::{Ipv4FragmentType, Ipv4Packet};
53use packet_formats::ipv6::Ipv6Packet;
54use thiserror::Error;
55use zerocopy::SplitByteSlice;
56
57use crate::internal::counters::{IpCounters, IpCountersIpExt};
58use crate::internal::device::opaque_iid::IidSecret;
59use crate::internal::device::slaac::SlaacCounters;
60use crate::internal::device::state::{
61 IpAddressData, IpAddressFlags, IpDeviceStateBindingsTypes, IpDeviceStateIpExt, WeakAddressId,
62};
63use crate::internal::device::{
64 self, IpDeviceAddressContext, IpDeviceBindingsContext, IpDeviceIpExt, IpDeviceSendContext,
65};
66use crate::internal::fragmentation::{FragmentableIpSerializer, FragmentationIpExt, IpFragmenter};
67use crate::internal::gmp::GmpQueryHandler;
68use crate::internal::gmp::igmp::IgmpCounters;
69use crate::internal::gmp::mld::MldCounters;
70use crate::internal::icmp::{
71 IcmpBindingsTypes, IcmpErrorHandler, IcmpHandlerIpExt, Icmpv4Error, Icmpv4ErrorKind,
72 Icmpv4State, Icmpv4StateBuilder, Icmpv6ErrorKind, Icmpv6State, Icmpv6StateBuilder,
73};
74use crate::internal::ipv6::Ipv6PacketAction;
75use crate::internal::local_delivery::{
76 IpHeaderInfo, Ipv4HeaderInfo, Ipv6HeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta,
77 TransparentLocalDelivery,
78};
79use crate::internal::multicast_forwarding::counters::MulticastForwardingCounters;
80use crate::internal::multicast_forwarding::route::{
81 MulticastRouteIpExt, MulticastRouteTarget, MulticastRouteTargets,
82};
83use crate::internal::multicast_forwarding::state::{
84 MulticastForwardingState, MulticastForwardingStateContext,
85};
86use crate::internal::multicast_forwarding::{
87 MulticastForwardingBindingsTypes, MulticastForwardingDeviceContext, MulticastForwardingEvent,
88 MulticastForwardingTimerId,
89};
90use crate::internal::path_mtu::{PmtuBindingsTypes, PmtuCache, PmtuTimerId};
91use crate::internal::raw::counters::RawIpSocketCounters;
92use crate::internal::raw::{RawIpSocketHandler, RawIpSocketMap, RawIpSocketsBindingsTypes};
93use crate::internal::reassembly::{
94 FragmentBindingsTypes, FragmentHandler, FragmentProcessingState, FragmentTimerId,
95 FragmentablePacket, IpPacketFragmentCache, ReassemblyIpExt,
96};
97use crate::internal::routing::rules::{Rule, RuleAction, RuleInput, RulesTable};
98use crate::internal::routing::{
99 IpRoutingBindingsTypes, IpRoutingDeviceContext, NonLocalSrcAddrPolicy, PacketOrigin,
100 RoutingTable,
101};
102use crate::internal::socket::{IpSocketBindingsContext, IpSocketContext, IpSocketHandler};
103use crate::internal::types::{
104 self, Destination, InternalForwarding, NextHop, ResolvedRoute, RoutableIpAddr,
105};
106use crate::internal::{ipv6, multicast_forwarding};
107
108#[cfg(test)]
109mod tests;
110
111pub const DEFAULT_TTL: NonZeroU8 = NonZeroU8::new(64).unwrap();
113
114#[derive(Copy, Clone, Debug, Eq, PartialEq)]
116#[allow(missing_docs)]
117pub struct HopLimits {
118 pub unicast: NonZeroU8,
119 pub multicast: NonZeroU8,
120}
121
122pub const DEFAULT_HOP_LIMITS: HopLimits =
124 HopLimits { unicast: DEFAULT_TTL, multicast: NonZeroU8::new(1).unwrap() };
125
126pub const IPV6_DEFAULT_SUBNET: Subnet<Ipv6Addr> =
129 unsafe { Subnet::new_unchecked(Ipv6::UNSPECIFIED_ADDRESS, 0) };
130
131#[derive(Debug)]
133#[allow(missing_docs)]
134pub enum TransportReceiveError {
135 ProtocolUnsupported,
136 PortUnreachable,
137}
138
139impl TransportReceiveError {
140 fn into_icmpv4_error(self, header_len: usize) -> Icmpv4Error {
141 let kind = match self {
142 TransportReceiveError::ProtocolUnsupported => Icmpv4ErrorKind::ProtocolUnreachable,
143 TransportReceiveError::PortUnreachable => Icmpv4ErrorKind::PortUnreachable,
144 };
145 Icmpv4Error { kind, header_len }
146 }
147
148 fn into_icmpv6_error(self, header_len: usize) -> Icmpv6ErrorKind {
149 match self {
150 TransportReceiveError::ProtocolUnsupported => {
151 Icmpv6ErrorKind::ProtocolUnreachable { header_len }
152 }
153 TransportReceiveError::PortUnreachable => Icmpv6ErrorKind::PortUnreachable,
154 }
155 }
156}
157
158#[derive(Derivative)]
164#[derivative(Default(bound = ""))]
165pub struct IpLayerPacketMetadata<
166 I: packet_formats::ip::IpExt,
167 A,
168 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
169> {
170 conntrack_connection_and_direction:
171 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
172 tx_metadata: BT::TxMetadata,
177 marks: Marks,
179 #[cfg(debug_assertions)]
180 drop_check: IpLayerPacketMetadataDropCheck,
181}
182
183#[cfg(debug_assertions)]
190#[derive(Default)]
191struct IpLayerPacketMetadataDropCheck {
192 okay_to_drop: bool,
193}
194
195#[derive(Derivative)]
198#[derivative(Debug(bound = ""), Default(bound = ""))]
199pub struct DeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
200 conntrack_entry: Option<(WeakConntrackConnection, ConnectionDirection)>,
208 tx_metadata: BT::TxMetadata,
213 marks: Marks,
220}
221
222impl<BT: TxMetadataBindingsTypes> DeviceIpLayerMetadata<BT> {
223 pub fn into_tx_metadata(self) -> BT::TxMetadata {
226 self.tx_metadata
227 }
228 #[cfg(any(test, feature = "testutils"))]
230 pub fn with_marks(marks: Marks) -> Self {
231 Self { conntrack_entry: None, tx_metadata: Default::default(), marks }
232 }
233}
234
235impl<
236 I: IpLayerIpExt,
237 A: WeakIpAddressId<I::Addr>,
238 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
239> IpLayerPacketMetadata<I, A, BT>
240{
241 fn from_device_ip_layer_metadata<CC, D>(
242 core_ctx: &mut CC,
243 device: &D,
244 DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks }: DeviceIpLayerMetadata<BT>,
245 ) -> Self
246 where
247 CC: ResourceCounterContext<D, IpCounters<I>>,
248 {
249 let conntrack_connection_and_direction = match conntrack_entry
250 .map(|(conn, dir)| conn.into_inner().map(|conn| (conn, dir)))
251 .transpose()
252 {
253 Ok(conn_and_dir) => conn_and_dir,
256 Err(WeakConnectionError::EntryRemoved) => None,
258 Err(WeakConnectionError::InvalidEntry) => {
262 core_ctx.increment_both(device, |c| &c.invalid_cached_conntrack_entry);
263 None
264 }
265 };
266 Self {
267 conntrack_connection_and_direction,
268 tx_metadata,
269 marks,
270 #[cfg(debug_assertions)]
271 drop_check: Default::default(),
272 }
273 }
274}
275
276impl<I: IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
277 IpLayerPacketMetadata<I, A, BT>
278{
279 pub(crate) fn from_tx_metadata_and_marks(tx_metadata: BT::TxMetadata, marks: Marks) -> Self {
280 Self {
281 conntrack_connection_and_direction: None,
282 tx_metadata,
283 marks,
284 #[cfg(debug_assertions)]
285 drop_check: Default::default(),
286 }
287 }
288
289 pub(crate) fn into_parts(
290 self,
291 ) -> (Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>, BT::TxMetadata, Marks) {
292 let Self {
293 tx_metadata,
294 marks,
295 conntrack_connection_and_direction,
296 #[cfg(debug_assertions)]
297 mut drop_check,
298 } = self;
299 #[cfg(debug_assertions)]
300 {
301 drop_check.okay_to_drop = true;
302 }
303 (conntrack_connection_and_direction, tx_metadata, marks)
304 }
305
306 pub(crate) fn acknowledge_drop(self) {
311 #[cfg(debug_assertions)]
312 {
313 let mut this = self;
314 this.drop_check.okay_to_drop = true;
315 }
316 }
317
318 pub(crate) fn tx_metadata(&self) -> &BT::TxMetadata {
320 &self.tx_metadata
321 }
322
323 pub(crate) fn marks(&self) -> &Marks {
325 &self.marks
326 }
327}
328
329#[cfg(debug_assertions)]
330impl Drop for IpLayerPacketMetadataDropCheck {
331 fn drop(&mut self) {
332 if !self.okay_to_drop {
333 panic!(
334 "IpLayerPacketMetadata dropped without acknowledgement. https://fxbug.dev/334127474"
335 );
336 }
337 }
338}
339
340impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
341 FilterIpMetadata<I, A, BT> for IpLayerPacketMetadata<I, A, BT>
342{
343 fn take_connection_and_direction(
344 &mut self,
345 ) -> Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)> {
346 self.conntrack_connection_and_direction.take()
347 }
348
349 fn replace_connection_and_direction(
350 &mut self,
351 conn: ConntrackConnection<I, A, BT>,
352 direction: ConnectionDirection,
353 ) -> Option<ConntrackConnection<I, A, BT>> {
354 self.conntrack_connection_and_direction.replace((conn, direction)).map(|(conn, _dir)| conn)
355 }
356}
357
358impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
359 FilterMarkMetadata for IpLayerPacketMetadata<I, A, BT>
360{
361 fn apply_mark_action(&mut self, domain: MarkDomain, action: MarkAction) {
362 action.apply(self.marks.get_mut(domain))
363 }
364}
365
366pub type IpSendFrameError<S> = ErrorAndSerializer<IpSendFrameErrorReason, S>;
368
369#[derive(Debug, PartialEq)]
371pub enum IpSendFrameErrorReason {
372 Device(SendFrameErrorReason),
374 IllegalLoopbackAddress,
377}
378
379impl From<SendFrameErrorReason> for IpSendFrameErrorReason {
380 fn from(value: SendFrameErrorReason) -> Self {
381 Self::Device(value)
382 }
383}
384
385pub trait IpTransportContext<I: IpExt, BC, CC: DeviceIdContext<AnyDevice> + ?Sized> {
391 fn receive_icmp_error(
405 core_ctx: &mut CC,
406 bindings_ctx: &mut BC,
407 device: &CC::DeviceId,
408 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
409 original_dst_ip: SpecifiedAddr<I::Addr>,
410 original_body: &[u8],
411 err: I::ErrorCode,
412 );
413
414 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
420 core_ctx: &mut CC,
421 bindings_ctx: &mut BC,
422 device: &CC::DeviceId,
423 src_ip: I::RecvSrcAddr,
424 dst_ip: SpecifiedAddr<I::Addr>,
425 buffer: B,
426 info: &LocalDeliveryPacketInfo<I, H>,
427 ) -> Result<(), (B, TransportReceiveError)>;
428}
429
430impl<I: IpExt, BC, CC: DeviceIdContext<AnyDevice> + ?Sized> IpTransportContext<I, BC, CC> for () {
431 fn receive_icmp_error(
432 _core_ctx: &mut CC,
433 _bindings_ctx: &mut BC,
434 _device: &CC::DeviceId,
435 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
436 _original_dst_ip: SpecifiedAddr<I::Addr>,
437 _original_body: &[u8],
438 err: I::ErrorCode,
439 ) {
440 trace!(
441 "IpTransportContext::receive_icmp_error: Received ICMP error message ({:?}) for unsupported IP protocol",
442 err
443 );
444 }
445
446 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
447 _core_ctx: &mut CC,
448 _bindings_ctx: &mut BC,
449 _device: &CC::DeviceId,
450 _src_ip: I::RecvSrcAddr,
451 _dst_ip: SpecifiedAddr<I::Addr>,
452 buffer: B,
453 _info: &LocalDeliveryPacketInfo<I, H>,
454 ) -> Result<(), (B, TransportReceiveError)> {
455 Err((buffer, TransportReceiveError::ProtocolUnsupported))
456 }
457}
458
459pub trait BaseTransportIpContext<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
462 type DevicesWithAddrIter<'s>: Iterator<Item = Self::DeviceId>;
465
466 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
472 &mut self,
473 addr: SpecifiedAddr<I::Addr>,
474 cb: F,
475 ) -> O;
476
477 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits;
482
483 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)>;
487}
488
489pub trait TransportIpContext<I: IpExt + FilterIpExt, BC: TxMetadataBindingsTypes>:
492 BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>
493{
494}
495
496impl<I, CC, BC> TransportIpContext<I, BC> for CC
497where
498 I: IpExt + FilterIpExt,
499 CC: BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>,
500 BC: TxMetadataBindingsTypes,
501{
502}
503
504pub trait MulticastMembershipHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
506 fn join_multicast_group(
513 &mut self,
514 bindings_ctx: &mut BC,
515 device: &Self::DeviceId,
516 addr: MulticastAddr<I::Addr>,
517 );
518
519 fn leave_multicast_group(
527 &mut self,
528 bindings_ctx: &mut BC,
529 device: &Self::DeviceId,
530 addr: MulticastAddr<I::Addr>,
531 );
532
533 fn select_device_for_multicast_group(
538 &mut self,
539 addr: MulticastAddr<I::Addr>,
540 marks: &Marks,
541 ) -> Result<Self::DeviceId, ResolveRouteError>;
542}
543
544pub trait UseTransportIpContextBlanket {}
556
557pub struct AssignedAddressDeviceIterator<Iter, I, D>(Iter, PhantomData<(I, D)>);
560
561impl<Iter, I, D> Iterator for AssignedAddressDeviceIterator<Iter, I, D>
562where
563 Iter: Iterator<Item = (D, I::AddressStatus)>,
564 I: IpLayerIpExt,
565{
566 type Item = D;
567 fn next(&mut self) -> Option<D> {
568 let Self(iter, PhantomData) = self;
569 iter.by_ref().find_map(|(device, state)| is_unicast_assigned::<I>(&state).then_some(device))
570 }
571}
572
573impl<
574 I: IpLayerIpExt,
575 BC: FilterBindingsContext + TxMetadataBindingsTypes + IpRoutingBindingsTypes,
576 CC: IpDeviceContext<I>
577 + IpSocketHandler<I, BC>
578 + IpStateContext<I, BC>
579 + FilterIpContext<I, BC>
580 + UseTransportIpContextBlanket,
581> BaseTransportIpContext<I, BC> for CC
582{
583 type DevicesWithAddrIter<'s> =
584 AssignedAddressDeviceIterator<CC::DeviceAndAddressStatusIter<'s>, I, CC::DeviceId>;
585
586 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
587 &mut self,
588 addr: SpecifiedAddr<I::Addr>,
589 cb: F,
590 ) -> O {
591 self.with_address_statuses(addr, |it| cb(AssignedAddressDeviceIterator(it, PhantomData)))
592 }
593
594 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
595 match device {
596 Some(device) => HopLimits {
597 unicast: IpDeviceEgressStateContext::<I>::get_hop_limit(self, device),
598 ..DEFAULT_HOP_LIMITS
599 },
600 None => DEFAULT_HOP_LIMITS,
601 }
602 }
603
604 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)> {
605 self.with_filter_state(|state| {
606 let conn = state.conntrack.get_connection(&tuple)?;
607
608 if !conn.destination_nat() {
609 return None;
610 }
611
612 let original = conn.original_tuple();
616 Some((original.dst_addr, original.dst_port_or_id))
617 })
618 }
619}
620
621#[derive(Debug, PartialEq)]
623#[allow(missing_docs)]
624pub enum AddressStatus<S> {
625 Present(S),
626 Unassigned,
627}
628
629impl<S> AddressStatus<S> {
630 fn into_present(self) -> Option<S> {
631 match self {
632 Self::Present(s) => Some(s),
633 Self::Unassigned => None,
634 }
635 }
636}
637
638impl AddressStatus<Ipv4PresentAddressStatus> {
639 pub fn from_context_addr_v4<
641 BC: IpDeviceStateBindingsTypes,
642 CC: device::IpDeviceStateContext<Ipv4, BC> + GmpQueryHandler<Ipv4, BC>,
643 >(
644 core_ctx: &mut CC,
645 device: &CC::DeviceId,
646 addr: SpecifiedAddr<Ipv4Addr>,
647 ) -> AddressStatus<Ipv4PresentAddressStatus> {
648 if addr.is_limited_broadcast() {
649 return AddressStatus::Present(Ipv4PresentAddressStatus::LimitedBroadcast);
650 }
651
652 if MulticastAddr::new(addr.get())
653 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
654 {
655 return AddressStatus::Present(Ipv4PresentAddressStatus::Multicast);
656 }
657
658 core_ctx.with_address_ids(device, |mut addrs, core_ctx| {
659 addrs
660 .find_map(|addr_id| {
661 let dev_addr = addr_id.addr_sub();
662 let (dev_addr, subnet) = dev_addr.addr_subnet();
663
664 if **dev_addr == addr {
665 let assigned = core_ctx.with_ip_address_data(
666 device,
667 &addr_id,
668 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| {
669 *assigned
670 },
671 );
672
673 if assigned {
674 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastAssigned))
675 } else {
676 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastTentative))
677 }
678 } else if addr.get() == subnet.broadcast() {
679 Some(AddressStatus::Present(Ipv4PresentAddressStatus::SubnetBroadcast))
680 } else if device.is_loopback() && subnet.contains(addr.as_ref()) {
681 Some(AddressStatus::Present(Ipv4PresentAddressStatus::LoopbackSubnet))
682 } else {
683 None
684 }
685 })
686 .unwrap_or(AddressStatus::Unassigned)
687 })
688 }
689}
690
691impl AddressStatus<Ipv6PresentAddressStatus> {
692 pub fn from_context_addr_v6<
694 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
695 CC: device::Ipv6DeviceContext<BC> + GmpQueryHandler<Ipv6, BC>,
696 >(
697 core_ctx: &mut CC,
698 device: &CC::DeviceId,
699 addr: SpecifiedAddr<Ipv6Addr>,
700 ) -> AddressStatus<Ipv6PresentAddressStatus> {
701 if MulticastAddr::new(addr.get())
702 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
703 {
704 return AddressStatus::Present(Ipv6PresentAddressStatus::Multicast);
705 }
706
707 let addr_id = match core_ctx.get_address_id(device, addr) {
708 Ok(o) => o,
709 Err(NotFoundError) => return AddressStatus::Unassigned,
710 };
711
712 let assigned = core_ctx.with_ip_address_data(
713 device,
714 &addr_id,
715 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
716 );
717
718 if assigned {
719 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned)
720 } else {
721 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastTentative)
722 }
723 }
724}
725
726impl<S: GenericOverIp<I>, I: Ip> GenericOverIp<I> for AddressStatus<S> {
727 type Type = AddressStatus<S::Type>;
728}
729
730#[derive(Debug, PartialEq)]
732#[allow(missing_docs)]
733pub enum Ipv4PresentAddressStatus {
734 LimitedBroadcast,
735 SubnetBroadcast,
736 Multicast,
737 UnicastAssigned,
738 UnicastTentative,
739 LoopbackSubnet,
750}
751
752impl Ipv4PresentAddressStatus {
753 fn to_broadcast_marker(&self) -> Option<<Ipv4 as BroadcastIpExt>::BroadcastMarker> {
754 match self {
755 Self::LimitedBroadcast | Self::SubnetBroadcast => Some(()),
756 Self::Multicast
757 | Self::UnicastAssigned
758 | Self::UnicastTentative
759 | Self::LoopbackSubnet => None,
760 }
761 }
762}
763
764#[derive(Debug, PartialEq)]
766#[allow(missing_docs)]
767pub enum Ipv6PresentAddressStatus {
768 Multicast,
769 UnicastAssigned,
770 UnicastTentative,
771}
772
773pub trait IpLayerIpExt:
775 IpExt
776 + MulticastRouteIpExt
777 + IcmpHandlerIpExt
778 + FilterIpExt
779 + FragmentationIpExt
780 + IpDeviceIpExt
781 + IpCountersIpExt
782 + ReassemblyIpExt
783{
784 type AddressStatus: Debug;
786 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>: AsRef<
788 IpStateInner<Self, StrongDeviceId, BT>,
789 >;
790 type PacketIdState;
792 type PacketId;
794 fn next_packet_id_from_state(state: &Self::PacketIdState) -> Self::PacketId;
796}
797
798impl IpLayerIpExt for Ipv4 {
799 type AddressStatus = Ipv4PresentAddressStatus;
800 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
801 Ipv4State<StrongDeviceId, BT>;
802 type PacketIdState = AtomicU16;
803 type PacketId = u16;
804 fn next_packet_id_from_state(next_packet_id: &Self::PacketIdState) -> Self::PacketId {
805 next_packet_id.fetch_add(1, atomic::Ordering::Relaxed)
809 }
810}
811
812impl IpLayerIpExt for Ipv6 {
813 type AddressStatus = Ipv6PresentAddressStatus;
814 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
815 Ipv6State<StrongDeviceId, BT>;
816 type PacketIdState = ();
817 type PacketId = ();
818 fn next_packet_id_from_state((): &Self::PacketIdState) -> Self::PacketId {
819 ()
820 }
821}
822
823pub trait IpStateContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes + MatcherBindingsTypes>:
825 IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>
826{
827 type IpRouteTablesCtx<'a>: IpRouteTablesContext<I, BT, DeviceId = Self::DeviceId>;
829
830 fn with_rules_table<
832 O,
833 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId, BT>) -> O,
834 >(
835 &mut self,
836 cb: F,
837 ) -> O;
838
839 fn with_rules_table_mut<
841 O,
842 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId, BT>) -> O,
843 >(
844 &mut self,
845 cb: F,
846 ) -> O;
847}
848
849pub trait IpRouteTablesContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
851 IpRouteTableContext<I, BT> + IpDeviceContext<I>
852{
853 type Ctx<'a>: IpRouteTableContext<I, BT, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>;
855
856 fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId, BT>;
858
859 fn with_ip_routing_tables<
861 O,
862 F: FnOnce(
863 &mut Self::Ctx<'_>,
864 &HashMap<
865 RoutingTableId<I, Self::DeviceId, BT>,
866 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
867 >,
868 ) -> O,
869 >(
870 &mut self,
871 cb: F,
872 ) -> O;
873
874 fn with_ip_routing_tables_mut<
876 O,
877 F: FnOnce(
878 &mut HashMap<
879 RoutingTableId<I, Self::DeviceId, BT>,
880 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
881 >,
882 ) -> O,
883 >(
884 &mut self,
885 cb: F,
886 ) -> O;
887
888 fn with_main_ip_routing_table<
892 O,
893 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
894 >(
895 &mut self,
896 cb: F,
897 ) -> O {
898 let main_table_id = self.main_table_id();
899 self.with_ip_routing_table(&main_table_id, cb)
900 }
901
902 fn with_main_ip_routing_table_mut<
906 O,
907 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
908 >(
909 &mut self,
910 cb: F,
911 ) -> O {
912 let main_table_id = self.main_table_id();
913 self.with_ip_routing_table_mut(&main_table_id, cb)
914 }
915}
916
917pub trait IpRouteTableContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
919 IpDeviceContext<I>
920{
921 type IpDeviceIdCtx<'a>: DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
923 + IpRoutingDeviceContext<I>
924 + IpDeviceContext<I>;
925
926 fn with_ip_routing_table<
928 O,
929 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
930 >(
931 &mut self,
932 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
933 cb: F,
934 ) -> O;
935
936 fn with_ip_routing_table_mut<
938 O,
939 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
940 >(
941 &mut self,
942 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
943 cb: F,
944 ) -> O;
945}
946
947pub trait IpDeviceEgressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
949 fn with_next_packet_id<O, F: FnOnce(&I::PacketIdState) -> O>(&self, cb: F) -> O;
951
952 fn get_local_addr_for_remote(
954 &mut self,
955 device_id: &Self::DeviceId,
956 remote: Option<SpecifiedAddr<I::Addr>>,
957 ) -> Option<IpDeviceAddr<I::Addr>>;
958
959 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8;
961}
962
963pub trait IpDeviceIngressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
965 fn address_status_for_device(
971 &mut self,
972 addr: SpecifiedAddr<I::Addr>,
973 device_id: &Self::DeviceId,
974 ) -> AddressStatus<I::AddressStatus>;
975}
976
977pub trait IpDeviceContext<I: IpLayerIpExt>:
979 IpDeviceEgressStateContext<I> + IpDeviceIngressStateContext<I>
980{
981 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
983
984 type DeviceAndAddressStatusIter<'a>: Iterator<Item = (Self::DeviceId, I::AddressStatus)>;
986
987 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
993 &mut self,
994 addr: SpecifiedAddr<I::Addr>,
995 cb: F,
996 ) -> R;
997
998 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
1000}
1001
1002pub trait IpDeviceConfirmReachableContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1004 fn confirm_reachable(
1007 &mut self,
1008 bindings_ctx: &mut BC,
1009 device: &Self::DeviceId,
1010 neighbor: SpecifiedAddr<I::Addr>,
1011 );
1012}
1013
1014pub trait IpDeviceMtuContext<I: Ip>: DeviceIdContext<AnyDevice> {
1016 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu;
1020}
1021
1022#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
1024#[generic_over_ip(I, Ip)]
1025pub enum IpLayerEvent<DeviceId, I: IpLayerIpExt> {
1026 AddRoute(types::AddableEntry<I::Addr, DeviceId>),
1028 RemoveRoutes {
1030 subnet: Subnet<I::Addr>,
1032 device: DeviceId,
1034 gateway: Option<SpecifiedAddr<I::Addr>>,
1036 },
1037 MulticastForwarding(MulticastForwardingEvent<I, DeviceId>),
1039}
1040
1041impl<DeviceId, I: IpLayerIpExt> From<MulticastForwardingEvent<I, DeviceId>>
1042 for IpLayerEvent<DeviceId, I>
1043{
1044 fn from(event: MulticastForwardingEvent<I, DeviceId>) -> IpLayerEvent<DeviceId, I> {
1045 IpLayerEvent::MulticastForwarding(event)
1046 }
1047}
1048
1049impl<DeviceId, I: IpLayerIpExt> IpLayerEvent<DeviceId, I> {
1050 pub fn map_device<N, F: Fn(DeviceId) -> N>(self, map: F) -> IpLayerEvent<N, I> {
1052 match self {
1053 IpLayerEvent::AddRoute(types::AddableEntry { subnet, device, gateway, metric }) => {
1054 IpLayerEvent::AddRoute(types::AddableEntry {
1055 subnet,
1056 device: map(device),
1057 gateway,
1058 metric,
1059 })
1060 }
1061 IpLayerEvent::RemoveRoutes { subnet, device, gateway } => {
1062 IpLayerEvent::RemoveRoutes { subnet, device: map(device), gateway }
1063 }
1064 IpLayerEvent::MulticastForwarding(e) => {
1065 IpLayerEvent::MulticastForwarding(e.map_device(map))
1066 }
1067 }
1068 }
1069}
1070
1071#[derive(Derivative, PartialEq, Eq, Clone, Hash)]
1073#[derivative(Debug)]
1074pub struct RouterAdvertisementEvent<D> {
1075 #[derivative(Debug = "ignore")]
1078 pub options_bytes: Box<[u8]>,
1079 pub source: net_types::ip::Ipv6Addr,
1081 pub device: D,
1083}
1084
1085impl<D> RouterAdvertisementEvent<D> {
1086 pub fn map_device<N, F: Fn(D) -> N>(self, map: F) -> RouterAdvertisementEvent<N> {
1088 let Self { options_bytes, source, device } = self;
1089 RouterAdvertisementEvent { options_bytes, source, device: map(device) }
1090 }
1091}
1092
1093pub trait NdpBindingsContext<DeviceId>: EventContext<RouterAdvertisementEvent<DeviceId>> {}
1095impl<DeviceId, BC: EventContext<RouterAdvertisementEvent<DeviceId>>> NdpBindingsContext<DeviceId>
1096 for BC
1097{
1098}
1099
1100pub trait IpLayerBindingsContext<I: IpLayerIpExt, DeviceId>:
1102 InstantContext
1103 + EventContext<IpLayerEvent<DeviceId, I>>
1104 + FilterBindingsContext
1105 + TxMetadataBindingsTypes
1106 + IpRoutingBindingsTypes
1107{
1108}
1109impl<
1110 I: IpLayerIpExt,
1111 DeviceId,
1112 BC: InstantContext
1113 + EventContext<IpLayerEvent<DeviceId, I>>
1114 + FilterBindingsContext
1115 + TxMetadataBindingsTypes
1116 + IpRoutingBindingsTypes,
1117> IpLayerBindingsContext<I, DeviceId> for BC
1118{
1119}
1120
1121pub trait IpLayerBindingsTypes:
1123 IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes
1124{
1125}
1126impl<BT: IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes> IpLayerBindingsTypes
1127 for BT
1128{
1129}
1130
1131pub trait IpLayerContext<
1133 I: IpLayerIpExt,
1134 BC: IpLayerBindingsContext<I, <Self as DeviceIdContext<AnyDevice>>::DeviceId>,
1135>:
1136 IpStateContext<I, BC>
1137 + IpDeviceContext<I>
1138 + IpDeviceMtuContext<I>
1139 + IpDeviceSendContext<I, BC>
1140 + IcmpErrorHandler<I, BC>
1141 + MulticastForwardingStateContext<I, BC>
1142 + MulticastForwardingDeviceContext<I>
1143 + CounterContext<MulticastForwardingCounters<I>>
1144 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>
1145{
1146}
1147
1148impl<
1149 I: IpLayerIpExt,
1150 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
1151 CC: IpStateContext<I, BC>
1152 + IpDeviceContext<I>
1153 + IpDeviceMtuContext<I>
1154 + IpDeviceSendContext<I, BC>
1155 + IcmpErrorHandler<I, BC>
1156 + MulticastForwardingStateContext<I, BC>
1157 + MulticastForwardingDeviceContext<I>
1158 + CounterContext<MulticastForwardingCounters<I>>
1159 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>,
1160> IpLayerContext<I, BC> for CC
1161{
1162}
1163
1164fn is_unicast_assigned<I: IpLayerIpExt>(status: &I::AddressStatus) -> bool {
1165 #[derive(GenericOverIp)]
1166 #[generic_over_ip(I, Ip)]
1167 struct WrapAddressStatus<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
1168
1169 I::map_ip(
1170 WrapAddressStatus(status),
1171 |WrapAddressStatus(status)| match status {
1172 Ipv4PresentAddressStatus::UnicastAssigned
1173 | Ipv4PresentAddressStatus::LoopbackSubnet => true,
1174 Ipv4PresentAddressStatus::UnicastTentative
1175 | Ipv4PresentAddressStatus::LimitedBroadcast
1176 | Ipv4PresentAddressStatus::SubnetBroadcast
1177 | Ipv4PresentAddressStatus::Multicast => false,
1178 },
1179 |WrapAddressStatus(status)| match status {
1180 Ipv6PresentAddressStatus::UnicastAssigned => true,
1181 Ipv6PresentAddressStatus::Multicast | Ipv6PresentAddressStatus::UnicastTentative => {
1182 false
1183 }
1184 },
1185 )
1186}
1187
1188fn is_local_assigned_address<I: Ip + IpLayerIpExt, CC: IpDeviceIngressStateContext<I>>(
1189 core_ctx: &mut CC,
1190 device: &CC::DeviceId,
1191 addr: IpDeviceAddr<I::Addr>,
1192) -> bool {
1193 match core_ctx.address_status_for_device(addr.into(), device) {
1194 AddressStatus::Present(status) => is_unicast_assigned::<I>(&status),
1195 AddressStatus::Unassigned => false,
1196 }
1197}
1198
1199fn get_device_with_assigned_address<I, CC>(
1200 core_ctx: &mut CC,
1201 addr: IpDeviceAddr<I::Addr>,
1202) -> Option<(CC::DeviceId, I::AddressStatus)>
1203where
1204 I: IpLayerIpExt,
1205 CC: IpDeviceContext<I>,
1206{
1207 core_ctx.with_address_statuses(addr.into(), |mut it| {
1208 it.find_map(|(device, status)| {
1209 is_unicast_assigned::<I>(&status).then_some((device, status))
1210 })
1211 })
1212}
1213
1214fn get_local_addr<I: Ip + IpLayerIpExt, CC: IpDeviceContext<I>>(
1218 core_ctx: &mut CC,
1219 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1220 device: &CC::DeviceId,
1221 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1222) -> Result<IpDeviceAddr<I::Addr>, ResolveRouteError> {
1223 match local_ip_and_policy {
1224 Some((local_ip, NonLocalSrcAddrPolicy::Allow)) => Ok(local_ip),
1225 Some((local_ip, NonLocalSrcAddrPolicy::Deny)) => {
1226 is_local_assigned_address(core_ctx, device, local_ip)
1227 .then_some(local_ip)
1228 .ok_or(ResolveRouteError::NoSrcAddr)
1229 }
1230 None => core_ctx
1231 .get_local_addr_for_remote(device, remote_addr.map(Into::into))
1232 .ok_or(ResolveRouteError::NoSrcAddr),
1233 }
1234}
1235
1236#[derive(Error, Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
1238#[generic_over_ip()]
1239pub enum ResolveRouteError {
1240 #[error("a source address could not be selected")]
1242 NoSrcAddr,
1243 #[error("no route exists to the destination IP address")]
1245 Unreachable,
1246}
1247
1248fn get_local_addr_with_internal_forwarding<I, CC>(
1250 core_ctx: &mut CC,
1251 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1252 device: &CC::DeviceId,
1253 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1254) -> Result<(IpDeviceAddr<I::Addr>, InternalForwarding<CC::DeviceId>), ResolveRouteError>
1255where
1256 I: IpLayerIpExt,
1257 CC: IpDeviceContext<I>,
1258{
1259 match get_local_addr(core_ctx, local_ip_and_policy, device, remote_addr) {
1260 Ok(src_addr) => Ok((src_addr, InternalForwarding::NotUsed)),
1261 Err(e) => {
1262 if let Some((local_ip, _policy)) = local_ip_and_policy {
1270 if let Some((device, _addr_status)) =
1271 get_device_with_assigned_address(core_ctx, local_ip)
1272 {
1273 if core_ctx.is_device_unicast_forwarding_enabled(&device) {
1274 return Ok((local_ip, InternalForwarding::Used(device)));
1275 }
1276 }
1277 }
1278 Err(e)
1279 }
1280 }
1281}
1282
1283#[derive(Debug, PartialEq, Eq)]
1286struct RuleWalkInfo<O> {
1287 observed_source_address_matcher: bool,
1289 inner: O,
1292}
1293
1294fn walk_rules<
1308 I: IpLayerIpExt,
1309 BT: IpRoutingBindingsTypes + MatcherBindingsTypes,
1310 CC: IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>,
1311 O,
1312 State,
1313 F: FnMut(
1314 State,
1315 &mut CC::IpDeviceIdCtx<'_>,
1316 &RoutingTable<I, CC::DeviceId>,
1317 ) -> ControlFlow<O, State>,
1318>(
1319 core_ctx: &mut CC,
1320 rules: &RulesTable<I, CC::DeviceId, BT>,
1321 init: State,
1322 rule_input: &RuleInput<'_, I, CC::DeviceId>,
1323 mut lookup_table: F,
1324) -> ControlFlow<RuleAction<RuleWalkInfo<O>>, RuleWalkInfo<State>> {
1325 rules.iter().try_fold(
1326 RuleWalkInfo { inner: init, observed_source_address_matcher: false },
1327 |RuleWalkInfo { inner: state, observed_source_address_matcher },
1328 Rule { action, matcher }| {
1329 let observed_source_address_matcher =
1330 observed_source_address_matcher || matcher.source_address_matcher.is_some();
1331 if !matcher.matches(rule_input) {
1332 return ControlFlow::Continue(RuleWalkInfo {
1333 inner: state,
1334 observed_source_address_matcher,
1335 });
1336 }
1337 match action {
1338 RuleAction::Unreachable => return ControlFlow::Break(RuleAction::Unreachable),
1339 RuleAction::Lookup(table_id) => core_ctx.with_ip_routing_table(
1340 &table_id,
1341 |core_ctx, table| match lookup_table(state, core_ctx, table) {
1342 ControlFlow::Break(out) => {
1343 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1344 inner: out,
1345 observed_source_address_matcher,
1346 }))
1347 }
1348 ControlFlow::Continue(state) => ControlFlow::Continue(RuleWalkInfo {
1349 inner: state,
1350 observed_source_address_matcher,
1351 }),
1352 },
1353 ),
1354 }
1355 },
1356 )
1357}
1358
1359pub fn resolve_output_route_to_destination<
1370 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1371 BC: IpDeviceBindingsContext<I, CC::DeviceId> + IpLayerBindingsContext<I, CC::DeviceId>,
1372 CC: IpStateContext<I, BC> + IpDeviceContext<I> + device::IpDeviceConfigurationContext<I, BC>,
1373>(
1374 core_ctx: &mut CC,
1375 device: Option<&CC::DeviceId>,
1376 src_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1377 dst_ip: Option<RoutableIpAddr<I::Addr>>,
1378 marks: &Marks,
1379) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1380 enum LocalDelivery<A, D> {
1381 WeakLoopback { dst_ip: A, device: D },
1382 StrongForDevice(D),
1383 }
1384
1385 let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1403 let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1404 match (device, dst_ip) {
1405 (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1406 .then_some(LocalDelivery::StrongForDevice(device.clone())),
1407 (None, Some(dst_ip)) => {
1408 get_device_with_assigned_address(core_ctx, dst_ip).map(
1409 |(dst_device, _addr_status)| {
1410 if src_ip_and_policy
1415 .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1416 || dst_ip.as_ref().must_have_zone()
1417 {
1418 LocalDelivery::StrongForDevice(dst_device)
1419 } else {
1420 LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1421 }
1422 },
1423 )
1424 }
1425 (_, None) => None,
1426 }
1427 };
1428
1429 if let Some(local_delivery) = local_delivery_instructions {
1430 let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1431
1432 let (src_addr, dest_device) = match local_delivery {
1433 LocalDelivery::WeakLoopback { dst_ip, device } => {
1434 let src_ip = match src_ip_and_policy {
1435 Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1436 let _device = get_device_with_assigned_address(core_ctx, src_ip)
1437 .ok_or(ResolveRouteError::NoSrcAddr)?;
1438 src_ip
1439 }
1440 Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1441 None => dst_ip,
1442 };
1443 (src_ip, device)
1444 }
1445 LocalDelivery::StrongForDevice(device) => {
1446 (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1447 }
1448 };
1449 return Ok(ResolvedRoute {
1450 src_addr,
1451 local_delivery_device: Some(dest_device),
1452 device: loopback,
1453 next_hop: NextHop::RemoteAsNeighbor,
1454 internal_forwarding: InternalForwarding::NotUsed,
1455 });
1456 }
1457 let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1458 let rule_input = RuleInput {
1459 packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1460 marks,
1461 };
1462 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
1463 let mut walk_rules = |rule_input, src_ip_and_policy| {
1464 walk_rules(
1465 core_ctx,
1466 rules,
1467 None, rule_input,
1469 |first_error, core_ctx, table| {
1470 let mut matching_with_addr = table.lookup_filter_map(
1471 core_ctx,
1472 device,
1473 dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1474 |core_ctx, d| {
1475 Some(get_local_addr_with_internal_forwarding(
1476 core_ctx,
1477 src_ip_and_policy,
1478 d,
1479 dst_ip,
1480 ))
1481 },
1482 );
1483
1484 let first_error_in_this_table = match matching_with_addr.next() {
1485 Some((
1486 Destination { device, next_hop },
1487 Ok((local_addr, internal_forwarding)),
1488 )) => {
1489 return ControlFlow::Break(Ok((
1490 Destination { device: device.clone(), next_hop },
1491 local_addr,
1492 internal_forwarding,
1493 )));
1494 }
1495 Some((_, Err(e))) => e,
1496 None => return ControlFlow::Continue(first_error),
1500 };
1501
1502 matching_with_addr
1503 .filter_map(|(destination, local_addr)| {
1504 local_addr.ok_checked::<ResolveRouteError>().map(
1507 |(local_addr, internal_forwarding)| {
1508 (destination, local_addr, internal_forwarding)
1509 },
1510 )
1511 })
1512 .next()
1513 .map_or(
1514 ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1515 |(
1516 Destination { device, next_hop },
1517 local_addr,
1518 internal_forwarding,
1519 )| {
1520 ControlFlow::Break(Ok((
1521 Destination { device: device.clone(), next_hop },
1522 local_addr,
1523 internal_forwarding,
1524 )))
1525 },
1526 )
1527 },
1528 )
1529 };
1530
1531 let result = match walk_rules(&rule_input, src_ip_and_policy) {
1532 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1539 inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1540 observed_source_address_matcher: true,
1541 })) if src_ip_and_policy.is_none() => walk_rules(
1542 &RuleInput {
1543 packet_origin: PacketOrigin::Local {
1544 bound_address: Some(selected_src_addr.into()),
1545 bound_device: device,
1546 },
1547 marks,
1548 },
1549 Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1550 ),
1551 result => result,
1552 };
1553
1554 match result {
1555 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1556 inner: result,
1557 observed_source_address_matcher: _,
1558 })) => {
1559 result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1560 ResolvedRoute {
1561 src_addr,
1562 device,
1563 local_delivery_device: None,
1564 next_hop,
1565 internal_forwarding,
1566 }
1567 })
1568 }
1569 ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1570 ControlFlow::Continue(RuleWalkInfo {
1571 inner: first_error,
1572 observed_source_address_matcher: _,
1573 }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1574 }
1575 })
1576}
1577
1578pub trait UseIpSocketContextBlanket {}
1583
1584impl<
1585 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1586 BC: IpDeviceBindingsContext<I, CC::DeviceId>
1587 + IpLayerBindingsContext<I, CC::DeviceId>
1588 + IpSocketBindingsContext<CC::DeviceId>,
1589 CC: IpLayerEgressContext<I, BC>
1590 + IpStateContext<I, BC>
1591 + IpDeviceContext<I>
1592 + IpDeviceConfirmReachableContext<I, BC>
1593 + IpDeviceMtuContext<I>
1594 + device::IpDeviceConfigurationContext<I, BC>
1595 + UseIpSocketContextBlanket,
1596> IpSocketContext<I, BC> for CC
1597{
1598 fn lookup_route(
1599 &mut self,
1600 _bindings_ctx: &mut BC,
1601 device: Option<&CC::DeviceId>,
1602 local_ip: Option<IpDeviceAddr<I::Addr>>,
1603 addr: RoutableIpAddr<I::Addr>,
1604 transparent: bool,
1605 marks: &Marks,
1606 ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1607 let src_ip_and_policy = local_ip.map(|local_ip| {
1608 (
1609 local_ip,
1610 if transparent {
1611 NonLocalSrcAddrPolicy::Allow
1612 } else {
1613 NonLocalSrcAddrPolicy::Deny
1614 },
1615 )
1616 });
1617 let res =
1618 resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1619 trace!(
1620 "lookup_route(\
1621 device={device:?}, \
1622 local_ip={local_ip:?}, \
1623 addr={addr:?}, \
1624 transparent={transparent:?}, \
1625 marks={marks:?}) => {res:?}"
1626 );
1627 res
1628 }
1629
1630 fn send_ip_packet<S>(
1631 &mut self,
1632 bindings_ctx: &mut BC,
1633 meta: SendIpPacketMeta<
1634 I,
1635 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1636 SpecifiedAddr<I::Addr>,
1637 >,
1638 body: S,
1639 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1640 ) -> Result<(), IpSendFrameError<S>>
1641 where
1642 S: TransportPacketSerializer<I>,
1643 S::Buffer: BufferMut,
1644 {
1645 send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1646 }
1647
1648 fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1649 device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1650 }
1651
1652 fn confirm_reachable(
1653 &mut self,
1654 bindings_ctx: &mut BC,
1655 dst: SpecifiedAddr<I::Addr>,
1656 input: RuleInput<'_, I, Self::DeviceId>,
1657 ) {
1658 match lookup_route_table(self, dst.get(), input) {
1659 Some(Destination { next_hop, device }) => {
1660 let neighbor = match next_hop {
1661 NextHop::RemoteAsNeighbor => dst,
1662 NextHop::Gateway(gateway) => gateway,
1663 NextHop::Broadcast(marker) => {
1664 I::map_ip::<_, ()>(
1665 WrapBroadcastMarker(marker),
1666 |WrapBroadcastMarker(())| {
1667 debug!(
1668 "can't confirm {dst:?}@{device:?} as reachable: \
1669 dst is a broadcast address"
1670 );
1671 },
1672 |WrapBroadcastMarker(never)| match never {},
1673 );
1674 return;
1675 }
1676 };
1677 IpDeviceConfirmReachableContext::confirm_reachable(
1678 self,
1679 bindings_ctx,
1680 &device,
1681 neighbor,
1682 );
1683 }
1684 None => {
1685 debug!("can't confirm {dst:?} as reachable: no route");
1686 }
1687 }
1688 }
1689}
1690
1691pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1696 fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1698 &mut self,
1699 bindings_ctx: &mut BC,
1700 device: &Self::DeviceId,
1701 src_ip: I::RecvSrcAddr,
1702 dst_ip: SpecifiedAddr<I::Addr>,
1703 proto: I::Proto,
1704 body: B,
1705 info: &LocalDeliveryPacketInfo<I, H>,
1706 ) -> Result<(), TransportReceiveError>;
1707}
1708
1709pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1711 IpTransportDispatchContext<
1712 I,
1713 BC,
1714 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1715 > + IpDeviceIngressStateContext<I>
1716 + IpDeviceMtuContext<I>
1717 + IpDeviceSendContext<I, BC>
1718 + IcmpErrorHandler<I, BC>
1719 + IpLayerContext<I, BC>
1720 + FragmentHandler<I, BC>
1721 + FilterHandlerProvider<I, BC>
1722 + RawIpSocketHandler<I, BC>
1723{
1724}
1725
1726impl<
1727 I: IpLayerIpExt,
1728 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1729 CC: IpTransportDispatchContext<
1730 I,
1731 BC,
1732 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1733 > + IpDeviceIngressStateContext<I>
1734 + IpDeviceMtuContext<I>
1735 + IpDeviceSendContext<I, BC>
1736 + IcmpErrorHandler<I, BC>
1737 + IpLayerContext<I, BC>
1738 + FragmentHandler<I, BC>
1739 + FilterHandlerProvider<I, BC>
1740 + RawIpSocketHandler<I, BC>,
1741> IpLayerIngressContext<I, BC> for CC
1742{
1743}
1744
1745pub trait IpLayerEgressContext<I, BC>:
1747 IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1748 + FilterHandlerProvider<I, BC>
1749 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1750where
1751 I: IpLayerIpExt,
1752 BC: FilterBindingsContext + TxMetadataBindingsTypes,
1753{
1754}
1755
1756impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1757where
1758 I: IpLayerIpExt,
1759 BC: FilterBindingsContext + TxMetadataBindingsTypes,
1760 CC: IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1761 + FilterHandlerProvider<I, BC>
1762 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
1763{
1764}
1765
1766pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1768 IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
1769{
1770}
1771
1772impl<
1773 I: IpLayerIpExt,
1774 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1775 CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
1776> IpLayerForwardingContext<I, BC> for CC
1777{
1778}
1779
1780#[derive(Copy, Clone, Default)]
1782pub struct Ipv4StateBuilder {
1783 icmp: Icmpv4StateBuilder,
1784}
1785
1786impl Ipv4StateBuilder {
1787 #[cfg(any(test, feature = "testutils"))]
1789 pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
1790 &mut self.icmp
1791 }
1792
1793 pub fn build<
1795 CC: CoreTimerContext<IpLayerTimerId, BC>,
1796 StrongDeviceId: StrongDeviceIdentifier,
1797 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1798 >(
1799 self,
1800 bindings_ctx: &mut BC,
1801 ) -> Ipv4State<StrongDeviceId, BC> {
1802 let Ipv4StateBuilder { icmp } = self;
1803
1804 Ipv4State {
1805 inner: IpStateInner::new::<CC>(bindings_ctx),
1806 icmp: icmp.build(),
1807 next_packet_id: Default::default(),
1808 }
1809 }
1810}
1811
1812#[derive(Copy, Clone)]
1816pub struct Ipv6StateBuilder {
1817 icmp: Icmpv6StateBuilder,
1818 slaac_stable_secret_key: Option<IidSecret>,
1819}
1820
1821impl Ipv6StateBuilder {
1822 pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
1827 self.slaac_stable_secret_key = Some(secret_key);
1828 self
1829 }
1830
1831 pub fn build<
1837 CC: CoreTimerContext<IpLayerTimerId, BC>,
1838 StrongDeviceId: StrongDeviceIdentifier,
1839 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1840 >(
1841 self,
1842 bindings_ctx: &mut BC,
1843 ) -> Ipv6State<StrongDeviceId, BC> {
1844 let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
1845
1846 let slaac_stable_secret_key = slaac_stable_secret_key
1847 .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
1848
1849 Ipv6State {
1850 inner: IpStateInner::new::<CC>(bindings_ctx),
1851 icmp: icmp.build(),
1852 slaac_counters: Default::default(),
1853 slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
1854 slaac_stable_secret_key,
1855 }
1856 }
1857}
1858
1859impl Default for Ipv6StateBuilder {
1860 fn default() -> Self {
1861 #[cfg(any(test, feature = "testutils"))]
1862 let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
1863
1864 #[cfg(not(any(test, feature = "testutils")))]
1865 let slaac_stable_secret_key = None;
1866
1867 Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
1868 }
1869}
1870
1871pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1873 pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
1875 pub icmp: Icmpv4State<BT>,
1877 pub next_packet_id: AtomicU16,
1879}
1880
1881impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1882 AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
1883{
1884 fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
1885 &self.inner
1886 }
1887}
1888
1889pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
1893 core_ctx: &mut CC,
1894) -> I::PacketId {
1895 core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
1896}
1897
1898pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1900 pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
1902 pub icmp: Icmpv6State<BT>,
1904 pub slaac_counters: SlaacCounters,
1906 pub slaac_temp_secret_key: IidSecret,
1908 pub slaac_stable_secret_key: IidSecret,
1913}
1914
1915impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1916 AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
1917{
1918 fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
1919 &self.inner
1920 }
1921}
1922
1923impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1924 OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
1925{
1926 type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
1927 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1928 OrderedLockRef::new(&self.fragment_cache)
1929 }
1930}
1931
1932impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1933 OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
1934{
1935 type Lock = Mutex<PmtuCache<I, BT>>;
1936 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1937 OrderedLockRef::new(&self.pmtu_cache)
1938 }
1939}
1940
1941impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1942 OrderedLockAccess<RulesTable<I, D, BT>> for IpStateInner<I, D, BT>
1943{
1944 type Lock = RwLock<RulesTable<I, D, BT>>;
1945 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1946 OrderedLockRef::new(&self.rules_table)
1947 }
1948}
1949
1950impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1951 OrderedLockAccess<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>
1952 for IpStateInner<I, D, BT>
1953{
1954 type Lock =
1955 Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>;
1956 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1957 OrderedLockRef::new(&self.tables)
1958 }
1959}
1960
1961impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpRoutingBindingsTypes>
1962 OrderedLockAccess<RoutingTable<I, D>> for RoutingTableId<I, D, BT>
1963{
1964 type Lock = RwLock<RoutingTable<I, D>>;
1965 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1966 let Self(inner) = self;
1967 OrderedLockRef::new(&inner.routing_table)
1968 }
1969}
1970
1971impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1972 OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
1973{
1974 type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
1975 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1976 OrderedLockRef::new(&self.multicast_forwarding)
1977 }
1978}
1979
1980impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1981 OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
1982{
1983 type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
1984 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1985 OrderedLockRef::new(&self.raw_sockets)
1986 }
1987}
1988
1989impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1990 OrderedLockAccess<filter::State<I, WeakAddressId<I, BT>, BT>> for IpStateInner<I, D, BT>
1991{
1992 type Lock = RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>;
1993 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1994 OrderedLockRef::new(&self.filter)
1995 }
1996}
1997
1998pub trait IpStateBindingsTypes:
2000 PmtuBindingsTypes
2001 + FragmentBindingsTypes
2002 + RawIpSocketsBindingsTypes
2003 + FilterBindingsTypes
2004 + MulticastForwardingBindingsTypes
2005 + IpDeviceStateBindingsTypes
2006 + IpRoutingBindingsTypes
2007{
2008}
2009impl<BT> IpStateBindingsTypes for BT where
2010 BT: PmtuBindingsTypes
2011 + FragmentBindingsTypes
2012 + RawIpSocketsBindingsTypes
2013 + FilterBindingsTypes
2014 + MulticastForwardingBindingsTypes
2015 + IpDeviceStateBindingsTypes
2016 + IpRoutingBindingsTypes
2017{
2018}
2019
2020#[derive(Derivative)]
2022#[derivative(Debug(bound = ""))]
2023#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2024pub enum RoutingTableCookie<BT: IpRoutingBindingsTypes> {
2025 Main,
2027 BindingsId(BT::RoutingTableId),
2029}
2030
2031#[derive(Derivative)]
2033#[derivative(Debug(bound = "D: Debug"))]
2034pub struct BaseRoutingTableState<I: Ip, D, BT: IpRoutingBindingsTypes> {
2035 routing_table: RwLock<RoutingTable<I, D>>,
2036 bindings_id: RoutingTableCookie<BT>,
2037}
2038
2039impl<I: Ip, D, BT: IpRoutingBindingsTypes> BaseRoutingTableState<I, D, BT> {
2040 pub(crate) fn with_bindings_id(bindings_id: RoutingTableCookie<BT>) -> Self {
2041 Self { bindings_id, routing_table: Default::default() }
2042 }
2043}
2044
2045#[derive(Derivative)]
2047#[derivative(PartialEq(bound = ""))]
2048#[derivative(Eq(bound = ""))]
2049#[derivative(Hash(bound = ""))]
2050#[derivative(Clone(bound = ""))]
2051pub struct RoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes>(
2052 StrongRc<BaseRoutingTableState<I, D, BT>>,
2053);
2054
2055impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for RoutingTableId<I, D, BT> {
2056 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2057 let Self(rc) = self;
2058 f.debug_tuple("RoutingTableId").field(&I::NAME).field(&rc.bindings_id).finish()
2059 }
2060}
2061
2062impl<I: Ip, D, BT: IpRoutingBindingsTypes> RoutingTableId<I, D, BT> {
2063 pub(crate) fn new(rc: StrongRc<BaseRoutingTableState<I, D, BT>>) -> Self {
2065 Self(rc)
2066 }
2067
2068 #[cfg(any(test, feature = "testutils"))]
2070 pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
2071 let Self(inner) = self;
2072 &inner.routing_table
2073 }
2074
2075 pub fn downgrade(&self) -> WeakRoutingTableId<I, D, BT>
2077 where
2078 BT::RoutingTableId: Clone,
2079 {
2080 let Self(rc) = self;
2081 WeakRoutingTableId { rc: StrongRc::downgrade(rc), bindings_id: rc.bindings_id.clone() }
2082 }
2083
2084 #[cfg(test)]
2085 fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2086 let Self(rc) = self;
2087 rc.routing_table.write()
2088 }
2089
2090 pub fn bindings_id(&self) -> &RoutingTableCookie<BT> {
2092 let Self(rc) = self;
2093 &rc.bindings_id
2094 }
2095}
2096
2097#[derive(Derivative)]
2099#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2100#[derivative(PartialEq, Eq, Hash)]
2101pub struct WeakRoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes> {
2102 rc: WeakRc<BaseRoutingTableState<I, D, BT>>,
2103 #[derivative(PartialEq = "ignore")]
2104 #[derivative(Hash = "ignore")]
2105 bindings_id: RoutingTableCookie<BT>,
2106}
2107
2108impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for WeakRoutingTableId<I, D, BT> {
2109 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2110 let Self { bindings_id, .. } = self;
2111 f.debug_tuple("WeakRoutingTableId").field(&I::NAME).field(bindings_id).finish()
2112 }
2113}
2114
2115#[derive(GenericOverIp)]
2117#[generic_over_ip(I, Ip)]
2118pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2119 rules_table: RwLock<RulesTable<I, D, BT>>,
2120 main_table_id: RoutingTableId<I, D, BT>,
2122 multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2123 multicast_forwarding_counters: MulticastForwardingCounters<I>,
2124 fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2125 pmtu_cache: Mutex<PmtuCache<I, BT>>,
2126 counters: IpCounters<I>,
2127 raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2128 raw_socket_counters: RawIpSocketCounters<I>,
2129 filter: RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>,
2130 tables: Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>,
2136 igmp_counters: IgmpCounters,
2137 mld_counters: MldCounters,
2138}
2139
2140impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2141 pub fn counters(&self) -> &IpCounters<I> {
2143 &self.counters
2144 }
2145
2146 pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2148 &self.multicast_forwarding_counters
2149 }
2150
2151 pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2153 &self.raw_socket_counters
2154 }
2155
2156 pub fn main_table_id(&self) -> &RoutingTableId<I, D, BT> {
2158 &self.main_table_id
2159 }
2160
2161 #[cfg(any(test, feature = "testutils"))]
2163 pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2164 &self.pmtu_cache
2165 }
2166
2167 #[cfg(any(test, feature = "testutils"))]
2169 pub fn filter(&self) -> &RwLock<filter::State<I, WeakAddressId<I, BT>, BT>> {
2170 &self.filter
2171 }
2172
2173 pub fn igmp_counters(&self) -> &IgmpCounters {
2175 &self.igmp_counters
2176 }
2177
2178 pub fn mld_counters(&self) -> &MldCounters {
2180 &self.mld_counters
2181 }
2182}
2183
2184impl<
2185 I: IpLayerIpExt,
2186 D: StrongDeviceIdentifier,
2187 BC: TimerContext + RngContext + IpStateBindingsTypes + IpRoutingBindingsTypes,
2188> IpStateInner<I, D, BC>
2189{
2190 fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2192 let main_table: PrimaryRc<BaseRoutingTableState<I, D, BC>> =
2193 PrimaryRc::new(BaseRoutingTableState::with_bindings_id(RoutingTableCookie::Main));
2194 let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2195 Self {
2196 rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2197 tables: Mutex::new(HashMap::from_iter(core::iter::once((
2198 main_table_id.clone(),
2199 main_table,
2200 )))),
2201 main_table_id,
2202 multicast_forwarding: Default::default(),
2203 multicast_forwarding_counters: Default::default(),
2204 fragment_cache: Mutex::new(
2205 IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2206 ),
2207 pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2208 counters: Default::default(),
2209 raw_sockets: Default::default(),
2210 raw_socket_counters: Default::default(),
2211 filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2212 igmp_counters: Default::default(),
2213 mld_counters: Default::default(),
2214 }
2215 }
2216}
2217
2218#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2220#[generic_over_ip()]
2221pub enum IpLayerTimerId {
2222 ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2224 ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2226 PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2228 PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2230 FilterTimerv4(FilterTimerId<Ipv4>),
2232 FilterTimerv6(FilterTimerId<Ipv6>),
2234 MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2236 MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2238}
2239
2240impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2241 fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2242 I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2243 }
2244}
2245
2246impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2247 fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2248 I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2249 }
2250}
2251
2252impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2253 fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2254 I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2255 }
2256}
2257
2258impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2259 fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2260 I::map_ip(
2261 timer,
2262 IpLayerTimerId::MulticastForwardingTimerv4,
2263 IpLayerTimerId::MulticastForwardingTimerv6,
2264 )
2265 }
2266}
2267
2268impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2269where
2270 CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2271 + TimerHandler<BC, FragmentTimerId<Ipv6>>
2272 + TimerHandler<BC, PmtuTimerId<Ipv4>>
2273 + TimerHandler<BC, PmtuTimerId<Ipv6>>
2274 + TimerHandler<BC, FilterTimerId<Ipv4>>
2275 + TimerHandler<BC, FilterTimerId<Ipv6>>
2276 + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2277 + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2278 BC: TimerBindingsTypes,
2279{
2280 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2281 match self {
2282 IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2283 core_ctx.handle_timer(bindings_ctx, id, timer)
2284 }
2285 IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2286 core_ctx.handle_timer(bindings_ctx, id, timer)
2287 }
2288 IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2289 IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2290 IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2291 IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2292 IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2293 core_ctx.handle_timer(bindings_ctx, id, timer)
2294 }
2295 IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2296 core_ctx.handle_timer(bindings_ctx, id, timer)
2297 }
2298 }
2299 }
2300}
2301
2302pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2309 err: I::IcmpError,
2311 src_ip: I::SourceAddress,
2314 dst_ip: SpecifiedAddr<I::Addr>,
2317 frame_dst: Option<FrameDestination>,
2319 device: &'a D,
2321 meta: ParseMetadata,
2324 marks: Marks,
2326}
2327
2328impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2329 fn respond_with_icmp_error<B, BC, CC>(
2336 self,
2337 core_ctx: &mut CC,
2338 bindings_ctx: &mut BC,
2339 mut body: B,
2340 ) where
2341 B: BufferMut,
2342 CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2343 {
2344 let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks } = self;
2345 body.undo_parse(meta);
2349
2350 core_ctx.send_icmp_error_message(
2351 bindings_ctx,
2352 device,
2353 frame_dst,
2354 src_ip,
2355 dst_ip,
2356 body,
2357 err,
2358 &marks,
2359 );
2360 }
2361}
2362
2363fn dispatch_receive_ipv4_packet<
2384 'a,
2385 'b,
2386 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2387 CC: IpLayerIngressContext<Ipv4, BC>,
2388>(
2389 core_ctx: &'a mut CC,
2390 bindings_ctx: &'a mut BC,
2391 device: &'b CC::DeviceId,
2392 frame_dst: Option<FrameDestination>,
2393 mut packet: Ipv4Packet<&'a mut [u8]>,
2394 mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2395 receive_meta: ReceiveIpPacketMeta<Ipv4>,
2396) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2397 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2398
2399 match frame_dst {
2400 Some(FrameDestination::Individual { local: false }) => {
2401 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2402 }
2403 Some(FrameDestination::Individual { local: true })
2404 | Some(FrameDestination::Multicast)
2405 | Some(FrameDestination::Broadcast)
2406 | None => (),
2407 }
2408
2409 let proto = packet.proto();
2410
2411 match core_ctx.filter_handler().local_ingress_hook(
2412 bindings_ctx,
2413 &mut packet,
2414 device,
2415 &mut packet_metadata,
2416 ) {
2417 filter::Verdict::Drop => {
2418 packet_metadata.acknowledge_drop();
2419 return Ok(());
2420 }
2421 filter::Verdict::Accept(()) => {}
2422 }
2423 let marks = packet_metadata.marks;
2424 packet_metadata.acknowledge_drop();
2425
2426 let Some(src_ip) = packet.src_ipv4() else {
2430 debug!(
2431 "dispatch_receive_ipv4_packet: received packet from invalid source {} after the \
2432 LOCAL_INGRESS hook; dropping",
2433 packet.src_ip()
2434 );
2435 core_ctx.increment_both(device, |c| &c.invalid_source);
2436 return Ok(());
2437 };
2438 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2439 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2440 debug!(
2441 "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2442 after the LOCAL_INGRESS hook; dropping"
2443 );
2444 return Ok(());
2445 };
2446
2447 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2448
2449 let (prefix, options, body) = packet.parts_with_body_mut();
2450 let buffer = Buf::new(body, ..);
2451 let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2452 let receive_info = LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks };
2453
2454 core_ctx
2455 .dispatch_receive_ip_packet(
2456 bindings_ctx,
2457 device,
2458 src_ip,
2459 dst_ip,
2460 proto,
2461 buffer,
2462 &receive_info,
2463 )
2464 .or_else(|err| {
2465 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
2466 let (_, _, _, meta) = packet.into_metadata();
2467 Err(IcmpErrorSender {
2468 err: err.into_icmpv4_error(meta.header_len()),
2469 src_ip,
2470 dst_ip,
2471 frame_dst,
2472 device,
2473 meta,
2474 marks,
2475 })
2476 } else {
2477 Ok(())
2478 }
2479 })
2480}
2481
2482fn dispatch_receive_ipv6_packet<
2487 'a,
2488 'b,
2489 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2490 CC: IpLayerIngressContext<Ipv6, BC>,
2491>(
2492 core_ctx: &'a mut CC,
2493 bindings_ctx: &'a mut BC,
2494 device: &'b CC::DeviceId,
2495 frame_dst: Option<FrameDestination>,
2496 mut packet: Ipv6Packet<&'a mut [u8]>,
2497 mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2498 meta: ReceiveIpPacketMeta<Ipv6>,
2499) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2500 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2507
2508 match frame_dst {
2509 Some(FrameDestination::Individual { local: false }) => {
2510 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2511 }
2512 Some(FrameDestination::Individual { local: true })
2513 | Some(FrameDestination::Multicast)
2514 | Some(FrameDestination::Broadcast)
2515 | None => (),
2516 }
2517
2518 let proto = packet.proto();
2519
2520 match core_ctx.filter_handler().local_ingress_hook(
2521 bindings_ctx,
2522 &mut packet,
2523 device,
2524 &mut packet_metadata,
2525 ) {
2526 filter::Verdict::Drop => {
2527 packet_metadata.acknowledge_drop();
2528 return Ok(());
2529 }
2530 filter::Verdict::Accept(()) => {}
2531 }
2532
2533 let Some(src_ip) = packet.src_ipv6() else {
2537 debug!(
2538 "dispatch_receive_ipv6_packet: received packet from invalid source {} after the \
2539 LOCAL_INGRESS hook; dropping",
2540 packet.src_ip()
2541 );
2542
2543 core_ctx.increment_both(device, |c| &c.invalid_source);
2544 return Ok(());
2545 };
2546 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2547 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2548 debug!(
2549 "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2550 after the LOCAL_INGRESS hook; dropping"
2551 );
2552 return Ok(());
2553 };
2554
2555 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2556
2557 let (fixed, extension, body) = packet.parts_with_body_mut();
2558 let buffer = Buf::new(body, ..);
2559 let header_info = Ipv6HeaderInfo { fixed, extension };
2560 let receive_info = LocalDeliveryPacketInfo { meta, header_info, marks: packet_metadata.marks };
2561
2562 let result = core_ctx
2563 .dispatch_receive_ip_packet(
2564 bindings_ctx,
2565 device,
2566 src_ip,
2567 dst_ip,
2568 proto,
2569 buffer,
2570 &receive_info,
2571 )
2572 .or_else(|err| {
2573 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
2574 let (_, _, _, meta) = packet.into_metadata();
2575 Err(IcmpErrorSender {
2576 err: err.into_icmpv6_error(meta.header_len()),
2577 src_ip: *src_ip,
2578 dst_ip,
2579 frame_dst,
2580 device,
2581 meta,
2582 marks: receive_info.marks,
2583 })
2584 } else {
2585 Ok(())
2586 }
2587 });
2588 packet_metadata.acknowledge_drop();
2589 result
2590}
2591
2592pub(crate) struct IpPacketForwarder<
2599 'a,
2600 I: IpLayerIpExt,
2601 D,
2602 A,
2603 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2604> {
2605 inbound_device: &'a D,
2606 outbound_device: &'a D,
2607 packet_meta: IpLayerPacketMetadata<I, A, BT>,
2608 src_ip: I::RecvSrcAddr,
2609 dst_ip: SpecifiedAddr<I::Addr>,
2610 destination: IpPacketDestination<I, &'a D>,
2611 proto: I::Proto,
2612 parse_meta: ParseMetadata,
2613 frame_dst: Option<FrameDestination>,
2614}
2615
2616impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
2617where
2618 I: IpLayerIpExt,
2619 BC: IpLayerBindingsContext<I, D>,
2620{
2621 fn forward_with_buffer<CC, B>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B)
2623 where
2624 B: BufferMut,
2625 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2626 {
2627 let Self {
2628 inbound_device,
2629 outbound_device,
2630 packet_meta,
2631 src_ip,
2632 dst_ip,
2633 destination,
2634 proto,
2635 parse_meta,
2636 frame_dst,
2637 } = self;
2638
2639 let packet = ForwardedPacket::new(src_ip.get(), dst_ip.get(), proto, parse_meta, buffer);
2640
2641 trace!("forward_with_buffer: forwarding {} packet", I::NAME);
2642
2643 let marks = packet_meta.marks;
2644 match send_ip_frame(
2645 core_ctx,
2646 bindings_ctx,
2647 outbound_device,
2648 destination,
2649 packet,
2650 packet_meta,
2651 Mtu::no_limit(),
2652 ) {
2653 Ok(()) => (),
2654 Err(IpSendFrameError { serializer, error }) => {
2655 match error {
2656 IpSendFrameErrorReason::Device(
2657 SendFrameErrorReason::SizeConstraintsViolation,
2658 ) => {
2659 debug!("failed to forward {} packet: MTU exceeded", I::NAME);
2660 core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
2661 let mtu = core_ctx.get_mtu(inbound_device);
2662 let Some(err) = I::new_mtu_exceeded(proto, parse_meta.header_len(), mtu)
2664 else {
2665 return;
2666 };
2667 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2670 return;
2671 };
2672 core_ctx.send_icmp_error_message(
2682 bindings_ctx,
2683 inbound_device,
2684 frame_dst,
2685 src_ip,
2686 dst_ip,
2687 serializer.into_buffer(),
2688 err,
2689 &marks,
2690 );
2691 }
2692 IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
2693 | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
2694 | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
2695 }
2696 debug!("failed to forward {} packet: {error:?}", I::NAME);
2697 }
2698 }
2699 }
2700}
2701
2702pub(crate) enum ForwardingAction<
2704 'a,
2705 I: IpLayerIpExt,
2706 D,
2707 A,
2708 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2709> {
2710 SilentlyDrop,
2712 Forward(IpPacketForwarder<'a, I, D, A, BT>),
2714 DropWithIcmpError(IcmpErrorSender<'a, I, D>),
2717}
2718
2719impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
2720where
2721 I: IpLayerIpExt,
2722 BC: IpLayerBindingsContext<I, D>,
2723{
2724 pub(crate) fn perform_action_with_buffer<CC, B>(
2726 self,
2727 core_ctx: &mut CC,
2728 bindings_ctx: &mut BC,
2729 buffer: B,
2730 ) where
2731 B: BufferMut,
2732 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2733 {
2734 match self {
2735 ForwardingAction::SilentlyDrop => {}
2736 ForwardingAction::Forward(forwarder) => {
2737 forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer)
2738 }
2739 ForwardingAction::DropWithIcmpError(icmp_sender) => {
2740 icmp_sender.respond_with_icmp_error(core_ctx, bindings_ctx, buffer)
2741 }
2742 }
2743 }
2744}
2745
2746pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
2748 core_ctx: &'a mut CC,
2749 mut packet: I::Packet<&'a mut [u8]>,
2750 mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2751 minimum_ttl: Option<u8>,
2752 inbound_device: &'b CC::DeviceId,
2753 outbound_device: &'b CC::DeviceId,
2754 destination: IpPacketDestination<I, &'b CC::DeviceId>,
2755 frame_dst: Option<FrameDestination>,
2756 src_ip: I::RecvSrcAddr,
2757 dst_ip: SpecifiedAddr<I::Addr>,
2758) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
2759where
2760 I: IpLayerIpExt,
2761 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2762 CC: IpLayerForwardingContext<I, BC>,
2763{
2764 const DEFAULT_MINIMUM_FORWARDING_TTL: u8 = 2;
2769 let minimum_ttl = minimum_ttl.unwrap_or(DEFAULT_MINIMUM_FORWARDING_TTL);
2770
2771 let ttl = packet.ttl();
2772 if ttl < minimum_ttl {
2773 debug!(
2774 "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
2775 I::NAME
2776 );
2777 if ttl > 1 {
2789 packet_meta.acknowledge_drop();
2790 return ForwardingAction::SilentlyDrop;
2791 }
2792
2793 core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
2794
2795 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2797 core_ctx.increment_both(inbound_device, |c| &c.unspecified_source);
2798 packet_meta.acknowledge_drop();
2799 return ForwardingAction::SilentlyDrop;
2800 };
2801
2802 let version_specific_meta = packet.version_specific_meta();
2804 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
2805 let err = I::new_ttl_expired(proto, parse_meta.header_len(), version_specific_meta);
2806 let action = ForwardingAction::DropWithIcmpError(IcmpErrorSender {
2807 err,
2808 src_ip,
2809 dst_ip,
2810 frame_dst,
2811 device: inbound_device,
2812 meta: parse_meta,
2813 marks: packet_meta.marks,
2814 });
2815 packet_meta.acknowledge_drop();
2816 return action;
2817 }
2818
2819 trace!("determine_ip_packet_forwarding_action: adequate TTL");
2820
2821 let maybe_ipv6_packet_action = I::map_ip_in(
2827 &packet,
2828 |_packet| None,
2829 |packet| {
2830 Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
2831 },
2832 );
2833 match maybe_ipv6_packet_action {
2834 None => {} Some(Ipv6PacketAction::_Discard) => {
2836 core_ctx.increment_both(inbound_device, |c| {
2837 #[derive(GenericOverIp)]
2838 #[generic_over_ip(I, Ip)]
2839 struct InCounters<'a, I: IpLayerIpExt>(
2840 &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<Counter>,
2841 );
2842 I::map_ip_in::<_, _>(
2843 InCounters(&c.version_rx),
2844 |_counters| {
2845 unreachable!(
2846 "`I` must be `Ipv6` because we're handling IPv6 extension headers"
2847 )
2848 },
2849 |InCounters(counters)| &counters.extension_header_discard,
2850 )
2851 });
2852 trace!(
2853 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
2854 discarding packet"
2855 );
2856 packet_meta.acknowledge_drop();
2857 return ForwardingAction::SilentlyDrop;
2858 }
2859 Some(Ipv6PacketAction::Continue) => {
2860 trace!(
2861 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
2862 forwarding packet"
2863 );
2864 }
2865 Some(Ipv6PacketAction::ProcessFragment) => {
2866 unreachable!(
2867 "When forwarding packets, we should only ever look at the hop by hop \
2868 options extension header (if present)"
2869 )
2870 }
2871 };
2872
2873 match core_ctx.filter_handler().forwarding_hook(
2874 I::as_filter_packet(&mut packet),
2875 inbound_device,
2876 outbound_device,
2877 &mut packet_meta,
2878 ) {
2879 filter::Verdict::Drop => {
2880 packet_meta.acknowledge_drop();
2881 trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
2882 return ForwardingAction::SilentlyDrop;
2883 }
2884 filter::Verdict::Accept(()) => {}
2885 }
2886
2887 packet.set_ttl(ttl - 1);
2888 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
2889 ForwardingAction::Forward(IpPacketForwarder {
2890 inbound_device,
2891 outbound_device,
2892 packet_meta,
2893 src_ip,
2894 dst_ip,
2895 destination,
2896 proto,
2897 parse_meta,
2898 frame_dst,
2899 })
2900}
2901
2902pub(crate) fn send_ip_frame<I, CC, BC, S>(
2903 core_ctx: &mut CC,
2904 bindings_ctx: &mut BC,
2905 device: &CC::DeviceId,
2906 destination: IpPacketDestination<I, &CC::DeviceId>,
2907 mut body: S,
2908 mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2909 limit_mtu: Mtu,
2910) -> Result<(), IpSendFrameError<S>>
2911where
2912 I: IpLayerIpExt,
2913 BC: FilterBindingsContext + TxMetadataBindingsTypes,
2914 CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
2915 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>,
2916{
2917 let (verdict, proof) = core_ctx.filter_handler().egress_hook(
2918 bindings_ctx,
2919 &mut body,
2920 device,
2921 &mut packet_metadata,
2922 );
2923 match verdict {
2924 filter::Verdict::Drop => {
2925 packet_metadata.acknowledge_drop();
2926 return Ok(());
2927 }
2928 filter::Verdict::Accept(()) => {}
2929 }
2930
2931 let (conntrack_connection_and_direction, tx_metadata, marks) = packet_metadata.into_parts();
2935 let conntrack_entry = if device.is_loopback() {
2936 conntrack_connection_and_direction
2937 .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
2938 } else {
2939 None
2940 };
2941 let device_ip_layer_metadata = DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks };
2942
2943 if !device.is_loopback()
2947 && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
2948 || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
2949 {
2950 core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
2951 return Err(IpSendFrameError {
2952 serializer: body,
2953 error: IpSendFrameErrorReason::IllegalLoopbackAddress,
2954 });
2955 }
2956
2957 let mtu = limit_mtu.min(core_ctx.get_mtu(device));
2959
2960 let body = body.with_size_limit(mtu.into());
2961
2962 let fits_mtu =
2963 match body.serialize_new_buf(PacketConstraints::UNCONSTRAINED, AlwaysFailBufferAlloc) {
2964 Err(SerializeError::Alloc(())) => true,
2967 Err(SerializeError::SizeLimitExceeded) => false,
2969 };
2970
2971 if fits_mtu {
2972 return core_ctx
2973 .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
2974 .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
2975 serializer: serializer.into_inner(),
2976 error: error.into(),
2977 });
2978 }
2979
2980 core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
2983
2984 let mut device_ip_layer_metadata = Some(device_ip_layer_metadata);
2986 let body = body.into_inner();
2987 let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
2988 Ok(mut fragmenter) => loop {
2989 let (fragment, has_more) = match fragmenter.next() {
2990 None => break Ok(()),
2991 Some(f) => f,
2992 };
2993
2994 let device_ip_layer_metadata = if has_more {
2999 let device_ip_layer_metadata = device_ip_layer_metadata.as_ref().unwrap();
3001 DeviceIpLayerMetadata {
3002 conntrack_entry: device_ip_layer_metadata.conntrack_entry.clone(),
3003 tx_metadata: Default::default(),
3004 marks: device_ip_layer_metadata.marks,
3005 }
3006 } else {
3007 device_ip_layer_metadata.take().unwrap()
3009 };
3010
3011 match core_ctx.send_ip_frame(
3012 bindings_ctx,
3013 device,
3014 destination.clone(),
3015 device_ip_layer_metadata,
3016 fragment,
3017 proof.clone_for_fragmentation(),
3018 ) {
3019 Ok(()) => {
3020 core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
3021 }
3022 Err(ErrorAndSerializer { serializer: _, error }) => {
3023 core_ctx
3024 .increment_both(device, |c| &c.fragmentation.error_fragmented_serializer);
3025 break Err(error);
3026 }
3027 }
3028 },
3029 Err(e) => {
3030 core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
3031 Err(SendFrameErrorReason::SizeConstraintsViolation)
3032 }
3033 };
3034 result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
3035}
3036
3037struct AlwaysFailBufferAlloc;
3042
3043impl LayoutBufferAlloc<Never> for AlwaysFailBufferAlloc {
3044 type Error = ();
3045 fn layout_alloc(
3046 self,
3047 _prefix: usize,
3048 _body: usize,
3049 _suffix: usize,
3050 ) -> Result<Never, Self::Error> {
3051 Err(())
3052 }
3053}
3054
3055macro_rules! drop_packet_and_undo_parse {
3064 ($packet:expr, $buffer:expr) => {{
3065 let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
3066 $buffer.undo_parse(meta);
3067 (src_ip, dst_ip, proto, meta)
3068 }};
3069}
3070
3071enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
3074 Done,
3077
3078 NotNeeded(I::Packet<&'a mut [u8]>),
3081
3082 Reassembled(Vec<u8>),
3085}
3086
3087fn process_fragment<'a, I, CC, BC>(
3093 core_ctx: &mut CC,
3094 bindings_ctx: &mut BC,
3095 device: &CC::DeviceId,
3096 packet: I::Packet<&'a mut [u8]>,
3097) -> ProcessFragmentResult<'a, I>
3098where
3099 I: IpLayerIpExt,
3100 for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3101 CC: IpLayerIngressContext<I, BC>,
3102 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3103{
3104 match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3105 FragmentProcessingState::NotNeeded(packet) => {
3107 trace!("receive_ip_packet: not fragmented");
3108 ProcessFragmentResult::NotNeeded(packet)
3109 }
3110 FragmentProcessingState::Ready { key, packet_len } => {
3112 trace!("receive_ip_packet: fragmented, ready for reassembly");
3113 let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3115
3116 let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3118 core_ctx,
3119 bindings_ctx,
3120 &key,
3121 buffer.buffer_view_mut(),
3122 ) {
3123 Ok(()) => ProcessFragmentResult::Reassembled(buffer.into_inner()),
3125 Err(e) => {
3126 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3127 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3128 ProcessFragmentResult::Done
3129 }
3130 };
3131 reassemble_result
3132 }
3133 FragmentProcessingState::NeedMoreFragments => {
3136 core_ctx.increment_both(device, |c| &c.need_more_fragments);
3137 trace!("receive_ip_packet: fragmented, need more before reassembly");
3138 ProcessFragmentResult::Done
3139 }
3140 FragmentProcessingState::InvalidFragment => {
3142 core_ctx.increment_both(device, |c| &c.invalid_fragment);
3143 trace!("receive_ip_packet: fragmented, invalid");
3144 ProcessFragmentResult::Done
3145 }
3146 FragmentProcessingState::OutOfMemory => {
3147 core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3148 trace!("receive_ip_packet: fragmented, dropped because OOM");
3149 ProcessFragmentResult::Done
3150 }
3151 }
3152}
3153
3154macro_rules! try_parse_ip_packet {
3164 ($buffer:expr) => {{
3165 let p_len = $buffer.prefix_len();
3166 let s_len = $buffer.suffix_len();
3167
3168 let result = $buffer.parse_mut();
3169
3170 if let Err(err) = result {
3171 let n_p_len = $buffer.prefix_len();
3173 let n_s_len = $buffer.suffix_len();
3174
3175 if p_len > n_p_len {
3176 $buffer.grow_front(p_len - n_p_len);
3177 }
3178
3179 if s_len > n_s_len {
3180 $buffer.grow_back(s_len - n_s_len);
3181 }
3182
3183 Err(err)
3184 } else {
3185 result
3186 }
3187 }};
3188}
3189
3190macro_rules! clone_packet_for_mcast_forwarding {
3208 {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3209 let mut $new_data = $packet.to_vec();
3210 let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3211 let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3212 };
3213}
3214
3215pub fn receive_ipv4_packet<
3220 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3221 B: BufferMut,
3222 CC: IpLayerIngressContext<Ipv4, BC>,
3223>(
3224 core_ctx: &mut CC,
3225 bindings_ctx: &mut BC,
3226 device: &CC::DeviceId,
3227 frame_dst: Option<FrameDestination>,
3228 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3229 buffer: B,
3230) {
3231 if !core_ctx.is_ip_device_enabled(&device) {
3232 return;
3233 }
3234
3235 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3238
3239 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3240 trace!("receive_ip_packet({device:?})");
3241
3242 let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3243 Ok(packet) => packet,
3244 Err(IpParseError::ParameterProblem {
3253 src_ip,
3254 dst_ip,
3255 code,
3256 pointer,
3257 must_send_icmp,
3258 header_len,
3259 action,
3260 }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
3261 core_ctx.increment_both(device, |c| &c.parameter_problem);
3262 assert!(!action.should_send_icmp_to_multicast());
3264 let dst_ip = match SpecifiedAddr::new(dst_ip) {
3265 Some(ip) => ip,
3266 None => {
3267 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3268 debug!(
3269 "receive_ipv4_packet: Received packet with unspecified destination IP address; dropping"
3270 );
3271 return;
3272 }
3273 };
3274 let src_ip = match Ipv4SourceAddr::new(src_ip) {
3275 None => {
3276 core_ctx.increment_both(device, |c| &c.invalid_source);
3277 return;
3278 }
3279 Some(Ipv4SourceAddr::Unspecified) => {
3280 core_ctx.increment_both(device, |c| &c.unspecified_source);
3281 return;
3282 }
3283 Some(Ipv4SourceAddr::Specified(src_ip)) => src_ip,
3284 };
3285 IcmpErrorHandler::<Ipv4, _>::send_icmp_error_message(
3286 core_ctx,
3287 bindings_ctx,
3288 device,
3289 frame_dst,
3290 src_ip,
3291 dst_ip,
3292 buffer,
3293 Icmpv4Error {
3294 kind: Icmpv4ErrorKind::ParameterProblem {
3295 code,
3296 pointer,
3297 fragment_type: Ipv4FragmentType::InitialFragment,
3300 },
3301 header_len,
3302 },
3303 &device_ip_layer_metadata.marks,
3304 );
3305 return;
3306 }
3307 _ => return, };
3309
3310 if packet.src_ipv4().is_none() {
3314 debug!(
3315 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3316 packet.src_ip()
3317 );
3318 core_ctx.increment_both(device, |c| &c.invalid_source);
3319 return;
3320 };
3321 if !packet.dst_ip().is_specified() {
3322 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3323 debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3324 return;
3325 };
3326
3327 let mut packet = match process_fragment(core_ctx, bindings_ctx, device, packet) {
3340 ProcessFragmentResult::Done => return,
3341 ProcessFragmentResult::NotNeeded(packet) => packet,
3342 ProcessFragmentResult::Reassembled(buf) => {
3343 let buf = Buf::new(buf, ..);
3344 buffer = packet::Either::B(buf);
3345
3346 match buffer.parse_mut() {
3347 Ok(packet) => packet,
3348 Err(err) => {
3349 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3350 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3351 return;
3352 }
3353 }
3354 }
3355 };
3356
3357 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3360 core_ctx,
3361 device,
3362 device_ip_layer_metadata,
3363 );
3364 let mut filter = core_ctx.filter_handler();
3365 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3366 IngressVerdict::Verdict(filter::Verdict::Accept(())) => {}
3367 IngressVerdict::Verdict(filter::Verdict::Drop) => {
3368 packet_metadata.acknowledge_drop();
3369 return;
3370 }
3371 IngressVerdict::TransparentLocalDelivery { addr, port } => {
3372 drop(filter);
3375
3376 let Some(addr) = SpecifiedAddr::new(addr) else {
3377 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3378 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3379 return;
3380 };
3381
3382 let receive_meta = ReceiveIpPacketMeta {
3383 broadcast: None,
3387 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3388 };
3389
3390 dispatch_receive_ipv4_packet(
3394 core_ctx,
3395 bindings_ctx,
3396 device,
3397 frame_dst,
3398 packet,
3399 packet_metadata,
3400 receive_meta,
3401 )
3402 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3403 return;
3404 }
3405 }
3406 drop(filter);
3409
3410 let Some(src_ip) = packet.src_ipv4() else {
3411 core_ctx.increment_both(device, |c| &c.invalid_source);
3412 debug!(
3413 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3414 packet.src_ip()
3415 );
3416 return;
3417 };
3418
3419 let action = receive_ipv4_packet_action(
3420 core_ctx,
3421 bindings_ctx,
3422 device,
3423 &packet,
3424 frame_dst,
3425 &packet_metadata.marks,
3426 );
3427 match action {
3428 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3429 let mut packet_metadata = Some(packet_metadata);
3436 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3437 clone_packet_for_mcast_forwarding! {
3438 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3439 };
3440 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3441 core_ctx,
3442 copy_of_packet,
3443 packet_metadata.take().unwrap_or_default(),
3444 Some(*min_ttl),
3445 device,
3446 &output_interface,
3447 IpPacketDestination::from_addr(dst_ip),
3448 frame_dst,
3449 src_ip,
3450 dst_ip,
3451 )
3452 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3453 }
3454
3455 if let Some(address_status) = address_status {
3457 let receive_meta = ReceiveIpPacketMeta {
3458 broadcast: address_status.to_broadcast_marker(),
3459 transparent_override: None,
3460 };
3461 dispatch_receive_ipv4_packet(
3462 core_ctx,
3463 bindings_ctx,
3464 device,
3465 frame_dst,
3466 packet,
3467 packet_metadata.take().unwrap_or_default(),
3468 receive_meta,
3469 )
3470 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3471 }
3472 }
3473 ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
3474 match internal_forwarding {
3477 InternalForwarding::Used(outbound_device) => {
3478 core_ctx.increment_both(device, |c| &c.forward);
3479 match core_ctx.filter_handler().forwarding_hook(
3480 &mut packet,
3481 device,
3482 &outbound_device,
3483 &mut packet_metadata,
3484 ) {
3485 filter::Verdict::Drop => {
3486 packet_metadata.acknowledge_drop();
3487 return;
3488 }
3489 filter::Verdict::Accept(()) => {}
3490 }
3491 }
3492 InternalForwarding::NotUsed => {}
3493 }
3494
3495 let receive_meta = ReceiveIpPacketMeta {
3496 broadcast: address_status.to_broadcast_marker(),
3497 transparent_override: None,
3498 };
3499 dispatch_receive_ipv4_packet(
3500 core_ctx,
3501 bindings_ctx,
3502 device,
3503 frame_dst,
3504 packet,
3505 packet_metadata,
3506 receive_meta,
3507 )
3508 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3509 }
3510 ReceivePacketAction::Forward {
3511 original_dst,
3512 dst: Destination { device: dst_device, next_hop },
3513 } => {
3514 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3515 core_ctx,
3516 packet,
3517 packet_metadata,
3518 None,
3519 device,
3520 &dst_device,
3521 IpPacketDestination::from_next_hop(next_hop, original_dst),
3522 frame_dst,
3523 src_ip,
3524 original_dst,
3525 )
3526 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3527 }
3528 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3529 use packet_formats::ipv4::Ipv4Header as _;
3530 core_ctx.increment_both(device, |c| &c.no_route_to_host);
3531 debug!("received IPv4 packet with no known route to destination {}", dst_ip);
3532 let fragment_type = packet.fragment_type();
3533 let (_, _, proto, meta): (Ipv4Addr, Ipv4Addr, _, _) =
3534 drop_packet_and_undo_parse!(packet, buffer);
3535 let marks = packet_metadata.marks;
3536 packet_metadata.acknowledge_drop();
3537 let src_ip = match src_ip {
3538 Ipv4SourceAddr::Unspecified => {
3539 core_ctx.increment_both(device, |c| &c.unspecified_source);
3540 return;
3541 }
3542 Ipv4SourceAddr::Specified(src_ip) => src_ip,
3543 };
3544 IcmpErrorHandler::<Ipv4, _>::send_icmp_error_message(
3545 core_ctx,
3546 bindings_ctx,
3547 device,
3548 frame_dst,
3549 src_ip,
3550 dst_ip,
3551 buffer,
3552 Icmpv4Error {
3553 kind: Icmpv4ErrorKind::NetUnreachable { proto, fragment_type },
3554 header_len: meta.header_len(),
3555 },
3556 &marks,
3557 );
3558 }
3559 ReceivePacketAction::Drop { reason } => {
3560 let src_ip = packet.src_ip();
3561 let dst_ip = packet.dst_ip();
3562 packet_metadata.acknowledge_drop();
3563 core_ctx.increment_both(device, |c| &c.dropped);
3564 debug!(
3565 "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
3566 {device:?}: {reason:?}",
3567 );
3568 }
3569 }
3570}
3571
3572pub fn receive_ipv6_packet<
3577 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3578 B: BufferMut,
3579 CC: IpLayerIngressContext<Ipv6, BC>,
3580>(
3581 core_ctx: &mut CC,
3582 bindings_ctx: &mut BC,
3583 device: &CC::DeviceId,
3584 frame_dst: Option<FrameDestination>,
3585 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3586 buffer: B,
3587) {
3588 if !core_ctx.is_ip_device_enabled(&device) {
3589 return;
3590 }
3591
3592 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3595
3596 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3597 trace!("receive_ipv6_packet({:?})", device);
3598
3599 let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
3600 Ok(packet) => packet,
3601 Err(IpParseError::ParameterProblem {
3607 src_ip,
3608 dst_ip,
3609 code,
3610 pointer,
3611 must_send_icmp,
3612 header_len: _,
3613 action,
3614 }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
3615 core_ctx.increment_both(device, |c| &c.parameter_problem);
3616 let dst_ip = match SpecifiedAddr::new(dst_ip) {
3617 Some(ip) => ip,
3618 None => {
3619 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3620 debug!(
3621 "receive_ipv6_packet: Received packet with unspecified destination IP address; dropping"
3622 );
3623 return;
3624 }
3625 };
3626 let src_ip = match Ipv6SourceAddr::new(src_ip) {
3627 None => {
3628 core_ctx.increment_both(device, |c| &c.invalid_source);
3629 return;
3630 }
3631 Some(Ipv6SourceAddr::Unspecified) => {
3632 core_ctx.increment_both(device, |c| &c.unspecified_source);
3633 return;
3634 }
3635 Some(Ipv6SourceAddr::Unicast(src_ip)) => src_ip,
3636 };
3637 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3638 core_ctx,
3639 bindings_ctx,
3640 device,
3641 frame_dst,
3642 *src_ip,
3643 dst_ip,
3644 buffer,
3645 Icmpv6ErrorKind::ParameterProblem {
3646 code,
3647 pointer,
3648 allow_dst_multicast: action.should_send_icmp_to_multicast(),
3649 },
3650 &device_ip_layer_metadata.marks,
3651 );
3652 return;
3653 }
3654 _ => return, };
3656
3657 trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
3658
3659 if packet.src_ipv6().is_none() {
3665 debug!(
3666 "receive_ipv6_packet: received packet from invalid source {}; dropping",
3667 packet.src_ip()
3668 );
3669 core_ctx.increment_both(device, |c| &c.invalid_source);
3670 return;
3671 };
3672 if !packet.dst_ip().is_specified() {
3673 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3674 debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
3675 return;
3676 };
3677
3678 let (mut packet, delivery_extension_header_action) =
3689 match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
3690 Ipv6PacketAction::_Discard => {
3691 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3692 trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
3693 return;
3694 }
3695 Ipv6PacketAction::Continue => {
3696 trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
3697 (packet, Some(Ipv6PacketAction::Continue))
3698 }
3699 Ipv6PacketAction::ProcessFragment => {
3700 trace!(
3701 "receive_ipv6_packet: handled IPv6 extension headers: handling \
3702 fragmented packet"
3703 );
3704
3705 match process_fragment(core_ctx, bindings_ctx, device, packet) {
3717 ProcessFragmentResult::Done => return,
3718 ProcessFragmentResult::NotNeeded(packet) => {
3719 (packet, Some(Ipv6PacketAction::Continue))
3734 }
3735 ProcessFragmentResult::Reassembled(buf) => {
3736 let buf = Buf::new(buf, ..);
3737 buffer = packet::Either::B(buf);
3738
3739 match buffer.parse_mut() {
3740 Ok(packet) => (packet, None),
3741 Err(err) => {
3742 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3743 debug!(
3744 "receive_ip_packet: fragmented, failed to reassemble: {:?}",
3745 err
3746 );
3747 return;
3748 }
3749 }
3750 }
3751 }
3752 }
3753 };
3754
3755 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3756 core_ctx,
3757 device,
3758 device_ip_layer_metadata,
3759 );
3760 let mut filter = core_ctx.filter_handler();
3761
3762 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3763 IngressVerdict::Verdict(filter::Verdict::Accept(())) => {}
3764 IngressVerdict::Verdict(filter::Verdict::Drop) => {
3765 packet_metadata.acknowledge_drop();
3766 return;
3767 }
3768 IngressVerdict::TransparentLocalDelivery { addr, port } => {
3769 drop(filter);
3772
3773 let Some(addr) = SpecifiedAddr::new(addr) else {
3774 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3775 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3776 return;
3777 };
3778
3779 let receive_meta = ReceiveIpPacketMeta {
3780 broadcast: None,
3781 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3782 };
3783
3784 dispatch_receive_ipv6_packet(
3788 core_ctx,
3789 bindings_ctx,
3790 device,
3791 frame_dst,
3792 packet,
3793 packet_metadata,
3794 receive_meta,
3795 )
3796 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3797 return;
3798 }
3799 }
3800 drop(filter);
3803
3804 let Some(src_ip) = packet.src_ipv6() else {
3805 debug!(
3806 "receive_ipv6_packet: received packet from invalid source {}; dropping",
3807 packet.src_ip()
3808 );
3809 core_ctx.increment_both(device, |c| &c.invalid_source);
3810 return;
3811 };
3812
3813 match receive_ipv6_packet_action(
3814 core_ctx,
3815 bindings_ctx,
3816 device,
3817 &packet,
3818 frame_dst,
3819 &packet_metadata.marks,
3820 ) {
3821 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3822 let mut packet_metadata = Some(packet_metadata);
3829 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3830 clone_packet_for_mcast_forwarding! {
3831 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3832 };
3833 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
3834 core_ctx,
3835 copy_of_packet,
3836 packet_metadata.take().unwrap_or_default(),
3837 Some(*min_ttl),
3838 device,
3839 &output_interface,
3840 IpPacketDestination::from_addr(dst_ip),
3841 frame_dst,
3842 src_ip,
3843 dst_ip,
3844 )
3845 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3846 }
3847
3848 if let Some(_) = address_status {
3850 let receive_meta =
3851 ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
3852
3853 dispatch_receive_ipv6_packet(
3854 core_ctx,
3855 bindings_ctx,
3856 device,
3857 frame_dst,
3858 packet,
3859 packet_metadata.take().unwrap_or_default(),
3860 receive_meta,
3861 )
3862 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3863 }
3864 }
3865 ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
3866 trace!("receive_ipv6_packet: delivering locally");
3867
3868 let action = if let Some(action) = delivery_extension_header_action {
3869 action
3870 } else {
3871 ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
3872 };
3873 match action {
3874 Ipv6PacketAction::_Discard => {
3875 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3876 trace!(
3877 "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
3878 );
3879 packet_metadata.acknowledge_drop();
3880 }
3881 Ipv6PacketAction::Continue => {
3882 trace!(
3883 "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
3884 );
3885
3886 match internal_forwarding {
3889 InternalForwarding::Used(outbound_device) => {
3890 core_ctx.increment_both(device, |c| &c.forward);
3891 match core_ctx.filter_handler().forwarding_hook(
3892 &mut packet,
3893 device,
3894 &outbound_device,
3895 &mut packet_metadata,
3896 ) {
3897 filter::Verdict::Drop => {
3898 packet_metadata.acknowledge_drop();
3899 return;
3900 }
3901 filter::Verdict::Accept(()) => {}
3902 }
3903 }
3904 InternalForwarding::NotUsed => {}
3905 }
3906
3907 let meta = ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
3908
3909 dispatch_receive_ipv6_packet(
3914 core_ctx,
3915 bindings_ctx,
3916 device,
3917 frame_dst,
3918 packet,
3919 packet_metadata,
3920 meta,
3921 )
3922 .unwrap_or_else(|err| {
3923 err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer)
3924 });
3925 }
3926 Ipv6PacketAction::ProcessFragment => {
3927 debug!("receive_ipv6_packet: found fragment header after reassembly; dropping");
3928 packet_metadata.acknowledge_drop();
3929 }
3930 }
3931 }
3932 ReceivePacketAction::Forward {
3933 original_dst,
3934 dst: Destination { device: dst_device, next_hop },
3935 } => {
3936 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
3937 core_ctx,
3938 packet,
3939 packet_metadata,
3940 None,
3941 device,
3942 &dst_device,
3943 IpPacketDestination::from_next_hop(next_hop, original_dst),
3944 frame_dst,
3945 src_ip,
3946 original_dst,
3947 )
3948 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3949 }
3950 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3951 core_ctx.increment_both(device, |c| &c.no_route_to_host);
3952 let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
3953 drop_packet_and_undo_parse!(packet, buffer);
3954 debug!("received IPv6 packet with no known route to destination {}", dst_ip);
3955 let marks = packet_metadata.marks;
3956 packet_metadata.acknowledge_drop();
3957
3958 let src_ip = match src_ip {
3959 Ipv6SourceAddr::Unspecified => {
3960 core_ctx.increment_both(device, |c| &c.unspecified_source);
3961 return;
3962 }
3963 Ipv6SourceAddr::Unicast(src_ip) => src_ip,
3964 };
3965 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3966 core_ctx,
3967 bindings_ctx,
3968 device,
3969 frame_dst,
3970 *src_ip,
3971 dst_ip,
3972 buffer,
3973 Icmpv6ErrorKind::NetUnreachable { proto, header_len: meta.header_len() },
3974 &marks,
3975 );
3976 }
3977 ReceivePacketAction::Drop { reason } => {
3978 core_ctx.increment_both(device, |c| &c.dropped);
3979 let src_ip = packet.src_ip();
3980 let dst_ip = packet.dst_ip();
3981 packet_metadata.acknowledge_drop();
3982 debug!(
3983 "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
3984 {device:?}: {reason:?}",
3985 );
3986 }
3987 }
3988}
3989
3990#[derive(Debug, PartialEq)]
3992pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
3993 Deliver {
3995 address_status: I::AddressStatus,
3997 internal_forwarding: InternalForwarding<DeviceId>,
4000 },
4001
4002 Forward {
4004 original_dst: SpecifiedAddr<I::Addr>,
4006 dst: Destination<I::Addr, DeviceId>,
4008 },
4009
4010 MulticastForward {
4018 targets: MulticastRouteTargets<DeviceId>,
4020 address_status: Option<I::AddressStatus>,
4023 dst_ip: SpecifiedAddr<I::Addr>,
4025 },
4026
4027 SendNoRouteToDest {
4033 dst: SpecifiedAddr<I::Addr>,
4035 },
4036
4037 #[allow(missing_docs)]
4041 Drop { reason: DropReason },
4042}
4043
4044fn choose_highest_priority_address_status<I: IpLayerIpExt>(
4047 address_statuses: impl Iterator<Item = I::AddressStatus>,
4048) -> Option<I::AddressStatus> {
4049 address_statuses.max_by_key(|status| {
4050 #[derive(GenericOverIp)]
4051 #[generic_over_ip(I, Ip)]
4052 struct Wrap<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
4053 I::map_ip_in(
4054 Wrap(status),
4055 |Wrap(v4_status)| match v4_status {
4056 Ipv4PresentAddressStatus::UnicastTentative => 0,
4057 _ => 1,
4058 },
4059 |Wrap(v6_status)| match v6_status {
4060 Ipv6PresentAddressStatus::UnicastTentative => 0,
4061 _ => 1,
4062 },
4063 )
4064 })
4065}
4066
4067#[derive(Debug, PartialEq)]
4069pub enum DropReason {
4070 Tentative,
4072 UnspecifiedDestination,
4074 ForwardUnspecifiedSource,
4076 ForwardLinkLocal,
4078 ForwardingDisabledInboundIface,
4081 MulticastNoInterest,
4087}
4088
4089pub fn receive_ipv4_packet_action<BC, CC, B>(
4091 core_ctx: &mut CC,
4092 bindings_ctx: &mut BC,
4093 device: &CC::DeviceId,
4094 packet: &Ipv4Packet<B>,
4095 frame_dst: Option<FrameDestination>,
4096 marks: &Marks,
4097) -> ReceivePacketAction<Ipv4, CC::DeviceId>
4098where
4099 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
4100 CC: IpLayerContext<Ipv4, BC>,
4101 B: SplitByteSlice,
4102{
4103 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4104 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4105 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4106 };
4107
4108 let highest_priority = if device.is_loopback() {
4121 core_ctx.with_address_statuses(dst_ip, |it| {
4122 let it = it.map(|(_device, status)| status);
4123 choose_highest_priority_address_status::<Ipv4>(it)
4124 })
4125 } else {
4126 core_ctx.address_status_for_device(dst_ip, device).into_present()
4127 };
4128 match highest_priority {
4129 Some(
4130 address_status @ (Ipv4PresentAddressStatus::UnicastAssigned
4131 | Ipv4PresentAddressStatus::LoopbackSubnet),
4132 ) => {
4133 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4134 ReceivePacketAction::Deliver {
4135 address_status,
4136 internal_forwarding: InternalForwarding::NotUsed,
4137 }
4138 }
4139 Some(Ipv4PresentAddressStatus::UnicastTentative) => {
4140 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4146 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4147 }
4148
4149 Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4150 receive_ip_multicast_packet_action(
4151 core_ctx,
4152 bindings_ctx,
4153 device,
4154 packet,
4155 Some(address_status),
4156 dst_ip,
4157 frame_dst,
4158 )
4159 }
4160 Some(
4161 address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4162 | Ipv4PresentAddressStatus::SubnetBroadcast),
4163 ) => {
4164 core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
4165 ReceivePacketAction::Deliver {
4166 address_status,
4167 internal_forwarding: InternalForwarding::NotUsed,
4168 }
4169 }
4170 None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4171 core_ctx,
4172 bindings_ctx,
4173 dst_ip,
4174 device,
4175 packet,
4176 frame_dst,
4177 marks,
4178 ),
4179 }
4180}
4181
4182pub fn receive_ipv6_packet_action<BC, CC, B>(
4184 core_ctx: &mut CC,
4185 bindings_ctx: &mut BC,
4186 device: &CC::DeviceId,
4187 packet: &Ipv6Packet<B>,
4188 frame_dst: Option<FrameDestination>,
4189 marks: &Marks,
4190) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4191where
4192 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4193 CC: IpLayerContext<Ipv6, BC>,
4194 B: SplitByteSlice,
4195{
4196 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4197 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4198 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4199 };
4200
4201 let highest_priority = if device.is_loopback() {
4214 core_ctx.with_address_statuses(dst_ip, |it| {
4215 let it = it.map(|(_device, status)| status);
4216 choose_highest_priority_address_status::<Ipv6>(it)
4217 })
4218 } else {
4219 core_ctx.address_status_for_device(dst_ip, device).into_present()
4220 };
4221 match highest_priority {
4222 Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
4223 receive_ip_multicast_packet_action(
4224 core_ctx,
4225 bindings_ctx,
4226 device,
4227 packet,
4228 Some(address_status),
4229 dst_ip,
4230 frame_dst,
4231 )
4232 }
4233 Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
4234 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4235 ReceivePacketAction::Deliver {
4236 address_status,
4237 internal_forwarding: InternalForwarding::NotUsed,
4238 }
4239 }
4240 Some(Ipv6PresentAddressStatus::UnicastTentative) => {
4241 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4272 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4273 }
4274 None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
4275 core_ctx,
4276 bindings_ctx,
4277 dst_ip,
4278 device,
4279 packet,
4280 frame_dst,
4281 marks,
4282 ),
4283 }
4284}
4285
4286fn receive_ip_multicast_packet_action<
4289 I: IpLayerIpExt,
4290 B: SplitByteSlice,
4291 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4292 CC: IpLayerContext<I, BC>,
4293>(
4294 core_ctx: &mut CC,
4295 bindings_ctx: &mut BC,
4296 device: &CC::DeviceId,
4297 packet: &I::Packet<B>,
4298 address_status: Option<I::AddressStatus>,
4299 dst_ip: SpecifiedAddr<I::Addr>,
4300 frame_dst: Option<FrameDestination>,
4301) -> ReceivePacketAction<I, CC::DeviceId> {
4302 let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
4303 core_ctx,
4304 bindings_ctx,
4305 packet,
4306 device,
4307 frame_dst,
4308 );
4309 match (targets, address_status) {
4310 (Some(targets), address_status) => {
4311 if address_status.is_some() {
4312 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4313 }
4314 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
4315 }
4316 (None, Some(address_status)) => {
4317 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4320 ReceivePacketAction::Deliver {
4321 address_status,
4322 internal_forwarding: InternalForwarding::NotUsed,
4323 }
4324 }
4325 (None, None) => {
4326 core_ctx.increment_both(device, |c| &c.multicast_no_interest);
4335 ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
4336 }
4337 }
4338}
4339
4340fn receive_ip_packet_action_common<
4343 I: IpLayerIpExt,
4344 B: SplitByteSlice,
4345 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4346 CC: IpLayerContext<I, BC>,
4347>(
4348 core_ctx: &mut CC,
4349 bindings_ctx: &mut BC,
4350 dst_ip: SpecifiedAddr<I::Addr>,
4351 device_id: &CC::DeviceId,
4352 packet: &I::Packet<B>,
4353 frame_dst: Option<FrameDestination>,
4354 marks: &Marks,
4355) -> ReceivePacketAction<I, CC::DeviceId> {
4356 if dst_ip.is_multicast() {
4357 return receive_ip_multicast_packet_action(
4358 core_ctx,
4359 bindings_ctx,
4360 device_id,
4361 packet,
4362 None,
4363 dst_ip,
4364 frame_dst,
4365 );
4366 }
4367
4368 if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
4370 core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
4383 return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
4384 }
4385 let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
4392 return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
4393 };
4394
4395 if let Some(dst_ip) = NonMappedAddr::new(dst_ip).and_then(NonMulticastAddr::new) {
4402 if let Some((outbound_device, address_status)) =
4403 get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
4404 {
4405 return ReceivePacketAction::Deliver {
4406 address_status,
4407 internal_forwarding: InternalForwarding::Used(outbound_device),
4408 };
4409 }
4410 }
4411
4412 if I::map_ip_in(
4427 &packet,
4428 |_| false,
4429 |packet| packet.src_ip().is_link_local() || packet.dst_ip().is_link_local(),
4430 ) {
4431 return ReceivePacketAction::Drop { reason: DropReason::ForwardLinkLocal };
4432 }
4433
4434 match lookup_route_table(
4435 core_ctx,
4436 *dst_ip,
4437 RuleInput {
4438 packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
4439 marks,
4440 },
4441 ) {
4442 Some(dst) => {
4443 core_ctx.increment_both(device_id, |c| &c.forward);
4444 ReceivePacketAction::Forward { original_dst: dst_ip, dst }
4445 }
4446 None => {
4447 core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
4448 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
4449 }
4450 }
4451}
4452
4453fn lookup_route_table<
4455 I: IpLayerIpExt,
4456 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4457 CC: IpStateContext<I, BC>,
4458>(
4459 core_ctx: &mut CC,
4460 dst_ip: I::Addr,
4461 rule_input: RuleInput<'_, I, CC::DeviceId>,
4462) -> Option<Destination<I::Addr, CC::DeviceId>> {
4463 let bound_device = match rule_input.packet_origin {
4464 PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
4465 PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
4466 };
4467 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
4468 match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
4469 match table.lookup(core_ctx, bound_device, dst_ip) {
4470 Some(dst) => ControlFlow::Break(Some(dst)),
4471 None => ControlFlow::Continue(()),
4472 }
4473 }) {
4474 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
4475 inner: dst,
4476 observed_source_address_matcher: _,
4477 })) => dst,
4478 ControlFlow::Break(RuleAction::Unreachable) => None,
4479 ControlFlow::Continue(RuleWalkInfo {
4480 inner: (),
4481 observed_source_address_matcher: _,
4482 }) => None,
4483 }
4484 })
4485}
4486
4487#[derive(Debug, Derivative, Clone)]
4489#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
4490pub enum IpPacketDestination<I: BroadcastIpExt, D> {
4491 Broadcast(I::BroadcastMarker),
4493
4494 Multicast(MulticastAddr<I::Addr>),
4496
4497 Neighbor(SpecifiedAddr<I::Addr>),
4500
4501 Loopback(D),
4504}
4505
4506impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
4507 pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
4509 match MulticastAddr::new(addr.into_addr()) {
4510 Some(mc_addr) => Self::Multicast(mc_addr),
4511 None => Self::Neighbor(addr),
4512 }
4513 }
4514
4515 pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
4517 match next_hop {
4518 NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
4519 NextHop::Gateway(gateway) => Self::Neighbor(gateway),
4520 NextHop::Broadcast(marker) => Self::Broadcast(marker),
4521 }
4522 }
4523}
4524
4525#[derive(Debug, Clone)]
4527pub struct SendIpPacketMeta<I: IpExt, D, Src> {
4528 pub device: D,
4530
4531 pub src_ip: Src,
4533
4534 pub dst_ip: SpecifiedAddr<I::Addr>,
4536
4537 pub destination: IpPacketDestination<I, D>,
4539
4540 pub proto: I::Proto,
4542
4543 pub ttl: Option<NonZeroU8>,
4547
4548 pub mtu: Mtu,
4553
4554 pub dscp_and_ecn: DscpAndEcn,
4556}
4557
4558impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4559 for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
4560{
4561 fn from(
4562 SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
4563 I,
4564 D,
4565 SpecifiedAddr<I::Addr>,
4566 >,
4567 ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
4568 SendIpPacketMeta {
4569 device,
4570 src_ip: Some(src_ip),
4571 dst_ip,
4572 destination,
4573 proto,
4574 ttl,
4575 mtu,
4576 dscp_and_ecn,
4577 }
4578 }
4579}
4580
4581pub trait IpLayerHandler<I: IpExt + FragmentationIpExt + FilterIpExt, BC>:
4587 DeviceIdContext<AnyDevice>
4588{
4589 fn send_ip_packet_from_device<S>(
4592 &mut self,
4593 bindings_ctx: &mut BC,
4594 meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4595 body: S,
4596 ) -> Result<(), IpSendFrameError<S>>
4597 where
4598 S: TransportPacketSerializer<I>,
4599 S::Buffer: BufferMut;
4600
4601 fn send_ip_frame<S>(
4608 &mut self,
4609 bindings_ctx: &mut BC,
4610 device: &Self::DeviceId,
4611 destination: IpPacketDestination<I, &Self::DeviceId>,
4612 body: S,
4613 ) -> Result<(), IpSendFrameError<S>>
4614 where
4615 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>;
4616}
4617
4618impl<
4619 I: IpLayerIpExt,
4620 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
4621 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4622> IpLayerHandler<I, BC> for CC
4623{
4624 fn send_ip_packet_from_device<S>(
4625 &mut self,
4626 bindings_ctx: &mut BC,
4627 meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4628 body: S,
4629 ) -> Result<(), IpSendFrameError<S>>
4630 where
4631 S: TransportPacketSerializer<I>,
4632 S::Buffer: BufferMut,
4633 {
4634 send_ip_packet_from_device(self, bindings_ctx, meta, body, IpLayerPacketMetadata::default())
4635 }
4636
4637 fn send_ip_frame<S>(
4638 &mut self,
4639 bindings_ctx: &mut BC,
4640 device: &Self::DeviceId,
4641 destination: IpPacketDestination<I, &Self::DeviceId>,
4642 body: S,
4643 ) -> Result<(), IpSendFrameError<S>>
4644 where
4645 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>,
4646 {
4647 send_ip_frame(
4648 self,
4649 bindings_ctx,
4650 device,
4651 destination,
4652 body,
4653 IpLayerPacketMetadata::default(),
4654 Mtu::no_limit(),
4655 )
4656 }
4657}
4658
4659pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
4666 core_ctx: &mut CC,
4667 bindings_ctx: &mut BC,
4668 meta: SendIpPacketMeta<
4669 I,
4670 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
4671 Option<SpecifiedAddr<I::Addr>>,
4672 >,
4673 body: S,
4674 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
4675) -> Result<(), IpSendFrameError<S>>
4676where
4677 I: IpLayerIpExt,
4678 BC: FilterBindingsContext + TxMetadataBindingsTypes,
4679 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4680 S: TransportPacketSerializer<I>,
4681 S::Buffer: BufferMut,
4682{
4683 let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
4684 meta;
4685 core_ctx.increment_both(device, |c| &c.send_ip_packet);
4686 let next_packet_id = gen_ip_packet_id(core_ctx);
4687 let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
4688 let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
4689 let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
4690
4691 #[derive(GenericOverIp)]
4692 #[generic_over_ip(I, Ip)]
4693 struct Wrap<'a, I: IpLayerIpExt> {
4694 builder: &'a mut I::PacketBuilder,
4695 next_packet_id: I::PacketId,
4696 }
4697
4698 I::map_ip::<_, ()>(
4699 Wrap { builder: &mut builder, next_packet_id },
4700 |Wrap { builder, next_packet_id }| {
4701 builder.id(next_packet_id);
4702 },
4703 |Wrap { builder: _, next_packet_id: () }| {
4704 },
4706 );
4707
4708 builder.set_dscp_and_ecn(dscp_and_ecn);
4709
4710 let ip_frame = builder.wrap_body(body);
4711 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
4712 .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
4713}
4714
4715pub trait FilterHandlerProvider<I: FilterIpExt, BT: FilterBindingsTypes>:
4717 IpDeviceAddressIdContext<I, DeviceId: netstack3_base::InterfaceProperties<BT::DeviceClass>>
4718{
4719 type Handler<'a>: filter::FilterHandler<I, BT, DeviceId = Self::DeviceId, WeakAddressId = Self::WeakAddressId>
4721 where
4722 Self: 'a;
4723
4724 fn filter_handler(&mut self) -> Self::Handler<'_>;
4726}
4727
4728#[cfg(any(test, feature = "testutils"))]
4729pub(crate) mod testutil {
4730 use super::*;
4731
4732 use netstack3_base::testutil::{FakeCoreCtx, FakeStrongDeviceId};
4733 use netstack3_base::{AssignedAddrIpExt, SendFrameContext, SendFrameError, SendableFrameMeta};
4734 use packet::Serializer;
4735
4736 #[derive(Debug, GenericOverIp)]
4738 #[generic_over_ip()]
4739 #[allow(missing_docs)]
4740 pub enum DualStackSendIpPacketMeta<D> {
4741 V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
4742 V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
4743 }
4744
4745 impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4746 for DualStackSendIpPacketMeta<D>
4747 {
4748 fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
4749 #[derive(GenericOverIp)]
4750 #[generic_over_ip(I, Ip)]
4751 struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
4752 use DualStackSendIpPacketMeta::*;
4753 I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
4754 }
4755 }
4756
4757 impl<I: IpExt, S, DeviceId, BC>
4758 SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
4759 for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
4760 {
4761 fn send_meta<SS>(
4762 self,
4763 core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
4764 bindings_ctx: &mut BC,
4765 frame: SS,
4766 ) -> Result<(), SendFrameError<SS>>
4767 where
4768 SS: Serializer,
4769 SS::Buffer: BufferMut,
4770 {
4771 SendFrameContext::send_frame(
4772 &mut core_ctx.frames,
4773 bindings_ctx,
4774 DualStackSendIpPacketMeta::from(self),
4775 frame,
4776 )
4777 }
4778 }
4779
4780 #[derive(Debug)]
4782 pub struct WrongIpVersion;
4783
4784 impl<D> DualStackSendIpPacketMeta<D> {
4785 pub fn try_as<I: IpExt>(
4788 &self,
4789 ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
4790 #[derive(GenericOverIp)]
4791 #[generic_over_ip(I, Ip)]
4792 struct Wrap<'a, I: IpExt, D>(
4793 Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
4794 );
4795 use DualStackSendIpPacketMeta::*;
4796 let Wrap(dual_stack) = I::map_ip(
4797 self,
4798 |value| {
4799 Wrap(match value {
4800 V4(meta) => Some(meta),
4801 V6(_) => None,
4802 })
4803 },
4804 |value| {
4805 Wrap(match value {
4806 V4(_) => None,
4807 V6(meta) => Some(meta),
4808 })
4809 },
4810 );
4811 dual_stack.ok_or(WrongIpVersion)
4812 }
4813 }
4814
4815 impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
4816 where
4817 I: AssignedAddrIpExt + FilterIpExt,
4818 BC: FilterBindingsContext,
4819 DeviceId: FakeStrongDeviceId + netstack3_base::InterfaceProperties<BC::DeviceClass>,
4820 {
4821 type Handler<'a>
4822 = filter::testutil::NoopImpl<DeviceId>
4823 where
4824 Self: 'a;
4825
4826 fn filter_handler(&mut self) -> Self::Handler<'_> {
4827 filter::testutil::NoopImpl::default()
4828 }
4829 }
4830}
4831
4832#[cfg(test)]
4833mod test {
4834 use super::*;
4835
4836 #[test]
4837 fn highest_priority_address_status_v4() {
4838 assert_eq!(
4840 choose_highest_priority_address_status::<Ipv4>(
4841 [
4842 Ipv4PresentAddressStatus::UnicastAssigned,
4843 Ipv4PresentAddressStatus::UnicastTentative
4844 ]
4845 .into_iter()
4846 ),
4847 Some(Ipv4PresentAddressStatus::UnicastAssigned)
4848 )
4849 }
4850
4851 #[test]
4852 fn highest_priority_address_status_v6() {
4853 assert_eq!(
4855 choose_highest_priority_address_status::<Ipv6>(
4856 [
4857 Ipv6PresentAddressStatus::UnicastAssigned,
4858 Ipv6PresentAddressStatus::UnicastTentative
4859 ]
4860 .into_iter()
4861 ),
4862 Some(Ipv6PresentAddressStatus::UnicastAssigned)
4863 )
4864 }
4865}