1use alloc::boxed::Box;
6use alloc::collections::HashMap;
7use alloc::vec::Vec;
8use core::cmp::Ordering;
9use core::convert::Infallible as Never;
10use core::fmt::Debug;
11use core::hash::Hash;
12use core::marker::PhantomData;
13use core::num::NonZeroU8;
14use core::ops::ControlFlow;
15#[cfg(test)]
16use core::ops::DerefMut;
17use core::sync::atomic::{self, AtomicU16};
18
19use derivative::Derivative;
20use explicit::ResultExt as _;
21use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
22use log::{debug, error, trace};
23use net_types::ip::{
24 GenericOverIp, Ip, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu, Subnet,
25};
26use net_types::{
27 MulticastAddr, MulticastAddress, NonMappedAddr, NonMulticastAddr, SpecifiedAddr,
28 SpecifiedAddress as _, UnicastAddr, Witness,
29};
30use netstack3_base::socket::SocketIpAddrExt as _;
31use netstack3_base::sync::{Mutex, PrimaryRc, RwLock, StrongRc, WeakRc};
32use netstack3_base::{
33 AnyDevice, BroadcastIpExt, CoreTimerContext, Counter, CounterContext, DeviceIdContext,
34 DeviceIdentifier as _, DeviceWithName, ErrorAndSerializer, EventContext, FrameDestination,
35 HandleableTimer, Inspectable, Inspector, InspectorExt as _, InstantContext, IpAddressId,
36 IpDeviceAddr, IpDeviceAddressIdContext, IpExt, MarkDomain, Marks, Matcher as _,
37 NestedIntoCoreTimerCtx, NotFoundError, RngContext, SendFrameErrorReason,
38 StrongDeviceIdentifier, TimerBindingsTypes, TimerContext, TimerHandler,
39 TxMetadataBindingsTypes, WeakIpAddressId, WrapBroadcastMarker,
40};
41use netstack3_filter::{
42 self as filter, ConnectionDirection, ConntrackConnection, FilterBindingsContext,
43 FilterBindingsTypes, FilterHandler as _, FilterIpContext, FilterIpExt, FilterIpMetadata,
44 FilterMarkMetadata, FilterTimerId, ForwardedPacket, IngressVerdict, IpPacket, MarkAction,
45 TransportPacketSerializer, Tuple, WeakConnectionError, WeakConntrackConnection,
46};
47use packet::{
48 Buf, BufferAlloc, BufferMut, GrowBuffer, PacketConstraints, ParseBufferMut, ParseMetadata,
49 SerializeError, Serializer as _,
50};
51use packet_formats::error::IpParseError;
52use packet_formats::ip::{DscpAndEcn, IpPacket as _, IpPacketBuilder as _};
53use packet_formats::ipv4::{Ipv4FragmentType, Ipv4Packet};
54use packet_formats::ipv6::Ipv6Packet;
55use thiserror::Error;
56use zerocopy::SplitByteSlice;
57
58use crate::internal::device::opaque_iid::IidSecret;
59use crate::internal::device::slaac::SlaacCounters;
60use crate::internal::device::state::{
61 IpDeviceStateBindingsTypes, IpDeviceStateIpExt, Ipv6AddressFlags, Ipv6AddressState,
62};
63use crate::internal::device::{
64 self, IpAddressIdExt, IpDeviceBindingsContext, IpDeviceIpExt, IpDeviceSendContext,
65};
66use crate::internal::fragmentation::{
67 FragmentableIpSerializer, FragmentationCounters, FragmentationIpExt, IpFragmenter,
68};
69use crate::internal::gmp::igmp::IgmpCounters;
70use crate::internal::gmp::mld::MldCounters;
71use crate::internal::gmp::GmpQueryHandler;
72use crate::internal::icmp::{
73 IcmpBindingsTypes, IcmpErrorHandler, IcmpHandlerIpExt, Icmpv4Error, Icmpv4ErrorKind,
74 Icmpv4State, Icmpv4StateBuilder, Icmpv6ErrorKind, Icmpv6State, Icmpv6StateBuilder,
75};
76use crate::internal::ipv6::Ipv6PacketAction;
77use crate::internal::local_delivery::{
78 IpHeaderInfo, Ipv4HeaderInfo, Ipv6HeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta,
79 TransparentLocalDelivery,
80};
81use crate::internal::multicast_forwarding::counters::MulticastForwardingCounters;
82use crate::internal::multicast_forwarding::route::{
83 MulticastRouteIpExt, MulticastRouteTarget, MulticastRouteTargets,
84};
85use crate::internal::multicast_forwarding::state::{
86 MulticastForwardingState, MulticastForwardingStateContext,
87};
88use crate::internal::multicast_forwarding::{
89 MulticastForwardingBindingsTypes, MulticastForwardingDeviceContext, MulticastForwardingEvent,
90 MulticastForwardingTimerId,
91};
92use crate::internal::path_mtu::{PmtuBindingsTypes, PmtuCache, PmtuTimerId};
93use crate::internal::raw::counters::RawIpSocketCounters;
94use crate::internal::raw::{RawIpSocketHandler, RawIpSocketMap, RawIpSocketsBindingsTypes};
95use crate::internal::reassembly::{
96 FragmentBindingsTypes, FragmentHandler, FragmentProcessingState, FragmentTimerId,
97 FragmentablePacket, IpPacketFragmentCache,
98};
99use crate::internal::routing::rules::{Rule, RuleAction, RuleInput, RulesTable};
100use crate::internal::routing::{
101 IpRoutingDeviceContext, NonLocalSrcAddrPolicy, PacketOrigin, RoutingTable,
102};
103use crate::internal::socket::{IpSocketBindingsContext, IpSocketContext, IpSocketHandler};
104use crate::internal::types::{
105 self, Destination, InternalForwarding, NextHop, ResolvedRoute, RoutableIpAddr,
106};
107use crate::internal::{ipv6, multicast_forwarding};
108
109#[cfg(test)]
110mod tests;
111
112pub const DEFAULT_TTL: NonZeroU8 = NonZeroU8::new(64).unwrap();
114
115#[derive(Copy, Clone, Debug, Eq, PartialEq)]
117#[allow(missing_docs)]
118pub struct HopLimits {
119 pub unicast: NonZeroU8,
120 pub multicast: NonZeroU8,
121}
122
123pub const DEFAULT_HOP_LIMITS: HopLimits =
125 HopLimits { unicast: DEFAULT_TTL, multicast: NonZeroU8::new(1).unwrap() };
126
127pub const IPV6_DEFAULT_SUBNET: Subnet<Ipv6Addr> =
130 unsafe { Subnet::new_unchecked(Ipv6::UNSPECIFIED_ADDRESS, 0) };
131
132#[derive(Debug)]
134#[allow(missing_docs)]
135pub enum TransportReceiveError {
136 ProtocolUnsupported,
137 PortUnreachable,
138}
139
140impl TransportReceiveError {
141 fn into_icmpv4_error(self, header_len: usize) -> Icmpv4Error {
142 let kind = match self {
143 TransportReceiveError::ProtocolUnsupported => Icmpv4ErrorKind::ProtocolUnreachable,
144 TransportReceiveError::PortUnreachable => Icmpv4ErrorKind::PortUnreachable,
145 };
146 Icmpv4Error { kind, header_len }
147 }
148
149 fn into_icmpv6_error(self, header_len: usize) -> Icmpv6ErrorKind {
150 match self {
151 TransportReceiveError::ProtocolUnsupported => {
152 Icmpv6ErrorKind::ProtocolUnreachable { header_len }
153 }
154 TransportReceiveError::PortUnreachable => Icmpv6ErrorKind::PortUnreachable,
155 }
156 }
157}
158
159#[derive(Derivative)]
165#[derivative(Default(bound = ""))]
166pub struct IpLayerPacketMetadata<
167 I: packet_formats::ip::IpExt,
168 A,
169 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
170> {
171 conntrack_connection_and_direction:
172 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
173 tx_metadata: BT::TxMetadata,
178 marks: Marks,
180 #[cfg(debug_assertions)]
181 drop_check: IpLayerPacketMetadataDropCheck,
182}
183
184#[cfg(debug_assertions)]
191#[derive(Default)]
192struct IpLayerPacketMetadataDropCheck {
193 okay_to_drop: bool,
194}
195
196#[derive(Derivative)]
199#[derivative(Debug(bound = ""), Default(bound = ""))]
200pub struct DeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
201 conntrack_entry: Option<(WeakConntrackConnection, ConnectionDirection)>,
209 tx_metadata: BT::TxMetadata,
214 marks: Marks,
221}
222
223impl<BT: TxMetadataBindingsTypes> DeviceIpLayerMetadata<BT> {
224 pub fn into_tx_metadata(self) -> BT::TxMetadata {
227 self.tx_metadata
228 }
229 #[cfg(any(test, feature = "testutils"))]
231 pub fn with_marks(marks: Marks) -> Self {
232 Self { conntrack_entry: None, tx_metadata: Default::default(), marks }
233 }
234}
235
236impl<
237 I: IpLayerIpExt,
238 A: WeakIpAddressId<I::Addr>,
239 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
240 > IpLayerPacketMetadata<I, A, BT>
241{
242 fn from_device_ip_layer_metadata<CC>(
243 core_ctx: &mut CC,
244 DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks }: DeviceIpLayerMetadata<BT>,
245 ) -> Self
246 where
247 CC: CounterContext<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.counters().invalid_cached_conntrack_entry.increment();
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
319#[cfg(debug_assertions)]
320impl Drop for IpLayerPacketMetadataDropCheck {
321 fn drop(&mut self) {
322 if !self.okay_to_drop {
323 panic!(
324 "IpLayerPacketMetadata dropped without acknowledgement. https://fxbug.dev/334127474"
325 );
326 }
327 }
328}
329
330impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
331 FilterIpMetadata<I, A, BT> for IpLayerPacketMetadata<I, A, BT>
332{
333 fn take_connection_and_direction(
334 &mut self,
335 ) -> Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)> {
336 self.conntrack_connection_and_direction.take()
337 }
338
339 fn replace_connection_and_direction(
340 &mut self,
341 conn: ConntrackConnection<I, A, BT>,
342 direction: ConnectionDirection,
343 ) -> Option<ConntrackConnection<I, A, BT>> {
344 self.conntrack_connection_and_direction.replace((conn, direction)).map(|(conn, _dir)| conn)
345 }
346}
347
348impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
349 FilterMarkMetadata for IpLayerPacketMetadata<I, A, BT>
350{
351 fn apply_mark_action(&mut self, domain: MarkDomain, action: MarkAction) {
352 action.apply(self.marks.get_mut(domain))
353 }
354}
355
356pub type IpSendFrameError<S> = ErrorAndSerializer<IpSendFrameErrorReason, S>;
358
359#[derive(Debug, PartialEq)]
361pub enum IpSendFrameErrorReason {
362 Device(SendFrameErrorReason),
364 IllegalLoopbackAddress,
367}
368
369impl From<SendFrameErrorReason> for IpSendFrameErrorReason {
370 fn from(value: SendFrameErrorReason) -> Self {
371 Self::Device(value)
372 }
373}
374
375pub trait IpTransportContext<I: IpExt, BC, CC: DeviceIdContext<AnyDevice> + ?Sized> {
381 fn receive_icmp_error(
395 core_ctx: &mut CC,
396 bindings_ctx: &mut BC,
397 device: &CC::DeviceId,
398 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
399 original_dst_ip: SpecifiedAddr<I::Addr>,
400 original_body: &[u8],
401 err: I::ErrorCode,
402 );
403
404 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
410 core_ctx: &mut CC,
411 bindings_ctx: &mut BC,
412 device: &CC::DeviceId,
413 src_ip: I::RecvSrcAddr,
414 dst_ip: SpecifiedAddr<I::Addr>,
415 buffer: B,
416 info: &LocalDeliveryPacketInfo<I, H>,
417 ) -> Result<(), (B, TransportReceiveError)>;
418}
419
420impl<I: IpExt, BC, CC: DeviceIdContext<AnyDevice> + ?Sized> IpTransportContext<I, BC, CC> for () {
421 fn receive_icmp_error(
422 _core_ctx: &mut CC,
423 _bindings_ctx: &mut BC,
424 _device: &CC::DeviceId,
425 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
426 _original_dst_ip: SpecifiedAddr<I::Addr>,
427 _original_body: &[u8],
428 err: I::ErrorCode,
429 ) {
430 trace!("IpTransportContext::receive_icmp_error: Received ICMP error message ({:?}) for unsupported IP protocol", err);
431 }
432
433 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
434 _core_ctx: &mut CC,
435 _bindings_ctx: &mut BC,
436 _device: &CC::DeviceId,
437 _src_ip: I::RecvSrcAddr,
438 _dst_ip: SpecifiedAddr<I::Addr>,
439 buffer: B,
440 _info: &LocalDeliveryPacketInfo<I, H>,
441 ) -> Result<(), (B, TransportReceiveError)> {
442 Err((buffer, TransportReceiveError::ProtocolUnsupported))
443 }
444}
445
446pub trait BaseTransportIpContext<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
449 type DevicesWithAddrIter<'s>: Iterator<Item = Self::DeviceId>;
452
453 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
459 &mut self,
460 addr: SpecifiedAddr<I::Addr>,
461 cb: F,
462 ) -> O;
463
464 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits;
469
470 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)>;
474}
475
476pub trait TransportIpContext<I: IpExt, BC: TxMetadataBindingsTypes>:
479 BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>
480{
481}
482
483impl<I, CC, BC> TransportIpContext<I, BC> for CC
484where
485 I: IpExt,
486 CC: BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>,
487 BC: TxMetadataBindingsTypes,
488{
489}
490
491pub trait MulticastMembershipHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
493 fn join_multicast_group(
500 &mut self,
501 bindings_ctx: &mut BC,
502 device: &Self::DeviceId,
503 addr: MulticastAddr<I::Addr>,
504 );
505
506 fn leave_multicast_group(
514 &mut self,
515 bindings_ctx: &mut BC,
516 device: &Self::DeviceId,
517 addr: MulticastAddr<I::Addr>,
518 );
519
520 fn select_device_for_multicast_group(
525 &mut self,
526 addr: MulticastAddr<I::Addr>,
527 marks: &Marks,
528 ) -> Result<Self::DeviceId, ResolveRouteError>;
529}
530
531pub trait UseTransportIpContextBlanket {}
543
544pub struct AssignedAddressDeviceIterator<Iter, I, D>(Iter, PhantomData<(I, D)>);
547
548impl<Iter, I, D> Iterator for AssignedAddressDeviceIterator<Iter, I, D>
549where
550 Iter: Iterator<Item = (D, I::AddressStatus)>,
551 I: IpLayerIpExt,
552{
553 type Item = D;
554 fn next(&mut self) -> Option<D> {
555 let Self(iter, PhantomData) = self;
556 iter.by_ref().find_map(|(device, state)| is_unicast_assigned::<I>(&state).then_some(device))
557 }
558}
559
560impl<
561 I: IpLayerIpExt,
562 BC: FilterBindingsContext + TxMetadataBindingsTypes,
563 CC: IpDeviceContext<I>
564 + IpSocketHandler<I, BC>
565 + IpStateContext<I>
566 + FilterIpContext<I, BC>
567 + UseTransportIpContextBlanket,
568 > BaseTransportIpContext<I, BC> for CC
569{
570 type DevicesWithAddrIter<'s> =
571 AssignedAddressDeviceIterator<CC::DeviceAndAddressStatusIter<'s>, I, CC::DeviceId>;
572
573 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
574 &mut self,
575 addr: SpecifiedAddr<I::Addr>,
576 cb: F,
577 ) -> O {
578 self.with_address_statuses(addr, |it| cb(AssignedAddressDeviceIterator(it, PhantomData)))
579 }
580
581 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
582 match device {
583 Some(device) => HopLimits {
584 unicast: IpDeviceEgressStateContext::<I>::get_hop_limit(self, device),
585 ..DEFAULT_HOP_LIMITS
586 },
587 None => DEFAULT_HOP_LIMITS,
588 }
589 }
590
591 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)> {
592 self.with_filter_state(|state| {
593 let conn = state.conntrack.get_connection(&tuple)?;
594
595 if !conn.destination_nat() {
596 return None;
597 }
598
599 let original = conn.original_tuple();
603 Some((original.dst_addr, original.dst_port_or_id))
604 })
605 }
606}
607
608#[derive(Debug, PartialEq)]
610#[allow(missing_docs)]
611pub enum AddressStatus<S> {
612 Present(S),
613 Unassigned,
614}
615
616impl<S> AddressStatus<S> {
617 fn into_present(self) -> Option<S> {
618 match self {
619 Self::Present(s) => Some(s),
620 Self::Unassigned => None,
621 }
622 }
623}
624
625impl AddressStatus<Ipv4PresentAddressStatus> {
626 pub fn from_context_addr_v4<
628 BC: IpDeviceStateBindingsTypes,
629 CC: device::IpDeviceStateContext<Ipv4, BC> + GmpQueryHandler<Ipv4, BC>,
630 >(
631 core_ctx: &mut CC,
632 device: &CC::DeviceId,
633 addr: SpecifiedAddr<Ipv4Addr>,
634 ) -> AddressStatus<Ipv4PresentAddressStatus> {
635 if addr.is_limited_broadcast() {
636 return AddressStatus::Present(Ipv4PresentAddressStatus::LimitedBroadcast);
637 }
638
639 if MulticastAddr::new(addr.get())
640 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
641 {
642 return AddressStatus::Present(Ipv4PresentAddressStatus::Multicast);
643 }
644
645 core_ctx.with_address_ids(device, |mut addrs, _core_ctx| {
646 addrs
647 .find_map(|addr_id| {
648 let dev_addr = addr_id.addr_sub();
649 let (dev_addr, subnet) = dev_addr.addr_subnet();
650
651 if **dev_addr == addr {
652 Some(AddressStatus::Present(Ipv4PresentAddressStatus::Unicast))
653 } else if addr.get() == subnet.broadcast() {
654 Some(AddressStatus::Present(Ipv4PresentAddressStatus::SubnetBroadcast))
655 } else if device.is_loopback() && subnet.contains(addr.as_ref()) {
656 Some(AddressStatus::Present(Ipv4PresentAddressStatus::LoopbackSubnet))
657 } else {
658 None
659 }
660 })
661 .unwrap_or(AddressStatus::Unassigned)
662 })
663 }
664}
665
666impl AddressStatus<Ipv6PresentAddressStatus> {
667 pub fn from_context_addr_v6<
669 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
670 CC: device::Ipv6DeviceContext<BC> + GmpQueryHandler<Ipv6, BC>,
671 >(
672 core_ctx: &mut CC,
673 device: &CC::DeviceId,
674 addr: SpecifiedAddr<Ipv6Addr>,
675 ) -> AddressStatus<Ipv6PresentAddressStatus> {
676 if MulticastAddr::new(addr.get())
677 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
678 {
679 return AddressStatus::Present(Ipv6PresentAddressStatus::Multicast);
680 }
681
682 let addr_id = match core_ctx.get_address_id(device, addr) {
683 Ok(o) => o,
684 Err(NotFoundError) => return AddressStatus::Unassigned,
685 };
686
687 let assigned = core_ctx.with_ip_address_state(
688 device,
689 &addr_id,
690 |Ipv6AddressState { flags: Ipv6AddressFlags { assigned }, config: _ }| *assigned,
691 );
692
693 if assigned {
694 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned)
695 } else {
696 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastTentative)
697 }
698 }
699}
700
701impl<S: GenericOverIp<I>, I: Ip> GenericOverIp<I> for AddressStatus<S> {
702 type Type = AddressStatus<S::Type>;
703}
704
705#[derive(Debug, PartialEq)]
707#[allow(missing_docs)]
708pub enum Ipv4PresentAddressStatus {
709 LimitedBroadcast,
710 SubnetBroadcast,
711 Multicast,
712 Unicast,
713 LoopbackSubnet,
724}
725
726impl Ipv4PresentAddressStatus {
727 fn to_broadcast_marker(&self) -> Option<<Ipv4 as BroadcastIpExt>::BroadcastMarker> {
728 match self {
729 Self::LimitedBroadcast | Self::SubnetBroadcast => Some(()),
730 Self::Multicast | Self::Unicast | Self::LoopbackSubnet => None,
731 }
732 }
733}
734
735#[derive(Debug, PartialEq)]
737#[allow(missing_docs)]
738pub enum Ipv6PresentAddressStatus {
739 Multicast,
740 UnicastAssigned,
741 UnicastTentative,
742}
743
744pub trait IpLayerIpExt:
746 IpExt
747 + MulticastRouteIpExt
748 + IcmpHandlerIpExt
749 + FilterIpExt
750 + FragmentationIpExt
751 + IpDeviceIpExt
752 + IpAddressIdExt
753{
754 type AddressStatus: Debug;
756 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>: AsRef<
758 IpStateInner<Self, StrongDeviceId, BT>,
759 >;
760 type PacketIdState;
762 type PacketId;
764 type RxCounters: Default + Inspectable;
766 fn next_packet_id_from_state(state: &Self::PacketIdState) -> Self::PacketId;
768}
769
770impl IpLayerIpExt for Ipv4 {
771 type AddressStatus = Ipv4PresentAddressStatus;
772 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
773 Ipv4State<StrongDeviceId, BT>;
774 type PacketIdState = AtomicU16;
775 type PacketId = u16;
776 type RxCounters = Ipv4RxCounters;
777 fn next_packet_id_from_state(next_packet_id: &Self::PacketIdState) -> Self::PacketId {
778 next_packet_id.fetch_add(1, atomic::Ordering::Relaxed)
782 }
783}
784
785impl IpLayerIpExt for Ipv6 {
786 type AddressStatus = Ipv6PresentAddressStatus;
787 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
788 Ipv6State<StrongDeviceId, BT>;
789 type PacketIdState = ();
790 type PacketId = ();
791 type RxCounters = Ipv6RxCounters;
792 fn next_packet_id_from_state((): &Self::PacketIdState) -> Self::PacketId {
793 ()
794 }
795}
796
797pub trait IpStateContext<I: IpLayerIpExt>:
799 IpRouteTablesContext<I, DeviceId: DeviceWithName>
800{
801 type IpRouteTablesCtx<'a>: IpRouteTablesContext<I, DeviceId = Self::DeviceId>;
803
804 fn with_rules_table<
806 O,
807 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId>) -> O,
808 >(
809 &mut self,
810 cb: F,
811 ) -> O;
812
813 fn with_rules_table_mut<
815 O,
816 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId>) -> O,
817 >(
818 &mut self,
819 cb: F,
820 ) -> O;
821}
822
823pub trait IpRouteTablesContext<I: IpLayerIpExt>:
825 IpRouteTableContext<I> + IpDeviceContext<I>
826{
827 type Ctx<'a>: IpRouteTableContext<
829 I,
830 DeviceId = Self::DeviceId,
831 WeakDeviceId = Self::WeakDeviceId,
832 >;
833
834 fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId>;
836
837 fn with_ip_routing_tables<
839 O,
840 F: FnOnce(
841 &mut Self::Ctx<'_>,
842 &HashMap<
843 RoutingTableId<I, Self::DeviceId>,
844 PrimaryRc<RwLock<RoutingTable<I, Self::DeviceId>>>,
845 >,
846 ) -> O,
847 >(
848 &mut self,
849 cb: F,
850 ) -> O;
851
852 fn with_ip_routing_tables_mut<
854 O,
855 F: FnOnce(
856 &mut HashMap<
857 RoutingTableId<I, Self::DeviceId>,
858 PrimaryRc<RwLock<RoutingTable<I, Self::DeviceId>>>,
859 >,
860 ) -> O,
861 >(
862 &mut self,
863 cb: F,
864 ) -> O;
865
866 fn with_main_ip_routing_table<
870 O,
871 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
872 >(
873 &mut self,
874 cb: F,
875 ) -> O {
876 let main_table_id = self.main_table_id();
877 self.with_ip_routing_table(&main_table_id, cb)
878 }
879
880 fn with_main_ip_routing_table_mut<
884 O,
885 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
886 >(
887 &mut self,
888 cb: F,
889 ) -> O {
890 let main_table_id = self.main_table_id();
891 self.with_ip_routing_table_mut(&main_table_id, cb)
892 }
893}
894
895pub trait IpRouteTableContext<I: IpLayerIpExt>: IpDeviceContext<I> {
897 type IpDeviceIdCtx<'a>: DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
899 + IpRoutingDeviceContext<I>
900 + IpDeviceContext<I>;
901
902 fn with_ip_routing_table<
904 O,
905 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
906 >(
907 &mut self,
908 table_id: &RoutingTableId<I, Self::DeviceId>,
909 cb: F,
910 ) -> O;
911
912 fn with_ip_routing_table_mut<
914 O,
915 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
916 >(
917 &mut self,
918 table_id: &RoutingTableId<I, Self::DeviceId>,
919 cb: F,
920 ) -> O;
921}
922
923pub trait IpDeviceEgressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
925 fn with_next_packet_id<O, F: FnOnce(&I::PacketIdState) -> O>(&self, cb: F) -> O;
927
928 fn get_local_addr_for_remote(
930 &mut self,
931 device_id: &Self::DeviceId,
932 remote: Option<SpecifiedAddr<I::Addr>>,
933 ) -> Option<IpDeviceAddr<I::Addr>>;
934
935 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8;
937}
938
939pub trait IpDeviceIngressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
941 fn address_status_for_device(
947 &mut self,
948 addr: SpecifiedAddr<I::Addr>,
949 device_id: &Self::DeviceId,
950 ) -> AddressStatus<I::AddressStatus>;
951}
952
953pub trait IpDeviceContext<I: IpLayerIpExt>:
955 IpDeviceEgressStateContext<I> + IpDeviceIngressStateContext<I>
956{
957 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
959
960 type DeviceAndAddressStatusIter<'a>: Iterator<Item = (Self::DeviceId, I::AddressStatus)>;
962
963 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
969 &mut self,
970 addr: SpecifiedAddr<I::Addr>,
971 cb: F,
972 ) -> R;
973
974 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
976}
977
978pub trait IpDeviceConfirmReachableContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
980 fn confirm_reachable(
983 &mut self,
984 bindings_ctx: &mut BC,
985 device: &Self::DeviceId,
986 neighbor: SpecifiedAddr<I::Addr>,
987 );
988}
989
990pub trait IpDeviceMtuContext<I: Ip>: DeviceIdContext<AnyDevice> {
992 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu;
996}
997
998#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
1000#[generic_over_ip(I, Ip)]
1001pub enum IpLayerEvent<DeviceId, I: IpLayerIpExt> {
1002 AddRoute(types::AddableEntry<I::Addr, DeviceId>),
1004 RemoveRoutes {
1006 subnet: Subnet<I::Addr>,
1008 device: DeviceId,
1010 gateway: Option<SpecifiedAddr<I::Addr>>,
1012 },
1013 MulticastForwarding(MulticastForwardingEvent<I, DeviceId>),
1015}
1016
1017impl<DeviceId, I: IpLayerIpExt> From<MulticastForwardingEvent<I, DeviceId>>
1018 for IpLayerEvent<DeviceId, I>
1019{
1020 fn from(event: MulticastForwardingEvent<I, DeviceId>) -> IpLayerEvent<DeviceId, I> {
1021 IpLayerEvent::MulticastForwarding(event)
1022 }
1023}
1024
1025impl<DeviceId, I: IpLayerIpExt> IpLayerEvent<DeviceId, I> {
1026 pub fn map_device<N, F: Fn(DeviceId) -> N>(self, map: F) -> IpLayerEvent<N, I> {
1028 match self {
1029 IpLayerEvent::AddRoute(types::AddableEntry { subnet, device, gateway, metric }) => {
1030 IpLayerEvent::AddRoute(types::AddableEntry {
1031 subnet,
1032 device: map(device),
1033 gateway,
1034 metric,
1035 })
1036 }
1037 IpLayerEvent::RemoveRoutes { subnet, device, gateway } => {
1038 IpLayerEvent::RemoveRoutes { subnet, device: map(device), gateway }
1039 }
1040 IpLayerEvent::MulticastForwarding(e) => {
1041 IpLayerEvent::MulticastForwarding(e.map_device(map))
1042 }
1043 }
1044 }
1045}
1046
1047#[derive(Derivative, PartialEq, Eq, Clone, Hash)]
1049#[derivative(Debug)]
1050pub struct RouterAdvertisementEvent<D> {
1051 #[derivative(Debug = "ignore")]
1054 pub options_bytes: Box<[u8]>,
1055 pub source: net_types::ip::Ipv6Addr,
1057 pub device: D,
1059}
1060
1061impl<D> RouterAdvertisementEvent<D> {
1062 pub fn map_device<N, F: Fn(D) -> N>(self, map: F) -> RouterAdvertisementEvent<N> {
1064 let Self { options_bytes, source, device } = self;
1065 RouterAdvertisementEvent { options_bytes, source, device: map(device) }
1066 }
1067}
1068
1069pub trait NdpBindingsContext<DeviceId>: EventContext<RouterAdvertisementEvent<DeviceId>> {}
1071impl<DeviceId, BC: EventContext<RouterAdvertisementEvent<DeviceId>>> NdpBindingsContext<DeviceId>
1072 for BC
1073{
1074}
1075
1076pub trait IpLayerBindingsContext<I: IpLayerIpExt, DeviceId>:
1078 InstantContext
1079 + EventContext<IpLayerEvent<DeviceId, I>>
1080 + FilterBindingsContext
1081 + TxMetadataBindingsTypes
1082{
1083}
1084impl<
1085 I: IpLayerIpExt,
1086 DeviceId,
1087 BC: InstantContext
1088 + EventContext<IpLayerEvent<DeviceId, I>>
1089 + FilterBindingsContext
1090 + TxMetadataBindingsTypes,
1091 > IpLayerBindingsContext<I, DeviceId> for BC
1092{
1093}
1094
1095pub trait IpLayerBindingsTypes: IcmpBindingsTypes + IpStateBindingsTypes {}
1097impl<BT: IcmpBindingsTypes + IpStateBindingsTypes> IpLayerBindingsTypes for BT {}
1098
1099pub trait IpLayerContext<
1101 I: IpLayerIpExt,
1102 BC: IpLayerBindingsContext<I, <Self as DeviceIdContext<AnyDevice>>::DeviceId>,
1103>:
1104 IpStateContext<I>
1105 + IpDeviceContext<I>
1106 + IpDeviceMtuContext<I>
1107 + IpDeviceSendContext<I, BC>
1108 + IcmpErrorHandler<I, BC>
1109 + MulticastForwardingStateContext<I, BC>
1110 + MulticastForwardingDeviceContext<I>
1111 + CounterContext<MulticastForwardingCounters<I>>
1112{
1113}
1114
1115impl<
1116 I: IpLayerIpExt,
1117 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
1118 CC: IpStateContext<I>
1119 + IpDeviceContext<I>
1120 + IpDeviceMtuContext<I>
1121 + IpDeviceSendContext<I, BC>
1122 + IcmpErrorHandler<I, BC>
1123 + MulticastForwardingStateContext<I, BC>
1124 + MulticastForwardingDeviceContext<I>
1125 + CounterContext<MulticastForwardingCounters<I>>,
1126 > IpLayerContext<I, BC> for CC
1127{
1128}
1129
1130fn is_unicast_assigned<I: IpLayerIpExt>(status: &I::AddressStatus) -> bool {
1131 #[derive(GenericOverIp)]
1132 #[generic_over_ip(I, Ip)]
1133 struct WrapAddressStatus<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
1134
1135 I::map_ip(
1136 WrapAddressStatus(status),
1137 |WrapAddressStatus(status)| match status {
1138 Ipv4PresentAddressStatus::Unicast | Ipv4PresentAddressStatus::LoopbackSubnet => true,
1139 Ipv4PresentAddressStatus::LimitedBroadcast
1140 | Ipv4PresentAddressStatus::SubnetBroadcast
1141 | Ipv4PresentAddressStatus::Multicast => false,
1142 },
1143 |WrapAddressStatus(status)| match status {
1144 Ipv6PresentAddressStatus::UnicastAssigned => true,
1145 Ipv6PresentAddressStatus::Multicast | Ipv6PresentAddressStatus::UnicastTentative => {
1146 false
1147 }
1148 },
1149 )
1150}
1151
1152fn is_local_assigned_address<I: Ip + IpLayerIpExt, CC: IpDeviceIngressStateContext<I>>(
1153 core_ctx: &mut CC,
1154 device: &CC::DeviceId,
1155 addr: IpDeviceAddr<I::Addr>,
1156) -> bool {
1157 match core_ctx.address_status_for_device(addr.into(), device) {
1158 AddressStatus::Present(status) => is_unicast_assigned::<I>(&status),
1159 AddressStatus::Unassigned => false,
1160 }
1161}
1162
1163fn get_device_with_assigned_address<I, CC>(
1164 core_ctx: &mut CC,
1165 addr: IpDeviceAddr<I::Addr>,
1166) -> Option<(CC::DeviceId, I::AddressStatus)>
1167where
1168 I: IpLayerIpExt,
1169 CC: IpDeviceContext<I>,
1170{
1171 core_ctx.with_address_statuses(addr.into(), |mut it| {
1172 it.find_map(|(device, status)| {
1173 is_unicast_assigned::<I>(&status).then_some((device, status))
1174 })
1175 })
1176}
1177
1178fn get_local_addr<I: Ip + IpLayerIpExt, CC: IpDeviceContext<I>>(
1182 core_ctx: &mut CC,
1183 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1184 device: &CC::DeviceId,
1185 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1186) -> Result<IpDeviceAddr<I::Addr>, ResolveRouteError> {
1187 match local_ip_and_policy {
1188 Some((local_ip, NonLocalSrcAddrPolicy::Allow)) => Ok(local_ip),
1189 Some((local_ip, NonLocalSrcAddrPolicy::Deny)) => {
1190 is_local_assigned_address(core_ctx, device, local_ip)
1191 .then_some(local_ip)
1192 .ok_or(ResolveRouteError::NoSrcAddr)
1193 }
1194 None => core_ctx
1195 .get_local_addr_for_remote(device, remote_addr.map(Into::into))
1196 .ok_or(ResolveRouteError::NoSrcAddr),
1197 }
1198}
1199
1200#[derive(Error, Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
1202#[generic_over_ip()]
1203pub enum ResolveRouteError {
1204 #[error("a source address could not be selected")]
1206 NoSrcAddr,
1207 #[error("no route exists to the destination IP address")]
1209 Unreachable,
1210}
1211
1212fn get_local_addr_with_internal_forwarding<I, CC>(
1214 core_ctx: &mut CC,
1215 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1216 device: &CC::DeviceId,
1217 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1218) -> Result<(IpDeviceAddr<I::Addr>, InternalForwarding<CC::DeviceId>), ResolveRouteError>
1219where
1220 I: IpLayerIpExt,
1221 CC: IpDeviceContext<I>,
1222{
1223 match get_local_addr(core_ctx, local_ip_and_policy, device, remote_addr) {
1224 Ok(src_addr) => Ok((src_addr, InternalForwarding::NotUsed)),
1225 Err(e) => {
1226 if let Some((local_ip, _policy)) = local_ip_and_policy {
1234 if let Some((device, _addr_status)) =
1235 get_device_with_assigned_address(core_ctx, local_ip)
1236 {
1237 if core_ctx.is_device_unicast_forwarding_enabled(&device) {
1238 return Ok((local_ip, InternalForwarding::Used(device)));
1239 }
1240 }
1241 }
1242 Err(e)
1243 }
1244 }
1245}
1246
1247#[derive(Debug, PartialEq, Eq)]
1250struct RuleWalkInfo<O> {
1251 observed_source_address_matcher: bool,
1253 inner: O,
1256}
1257
1258fn walk_rules<
1272 I: IpLayerIpExt,
1273 CC: IpRouteTablesContext<I, DeviceId: DeviceWithName>,
1274 O,
1275 State,
1276 F: FnMut(
1277 State,
1278 &mut CC::IpDeviceIdCtx<'_>,
1279 &RoutingTable<I, CC::DeviceId>,
1280 ) -> ControlFlow<O, State>,
1281>(
1282 core_ctx: &mut CC,
1283 rules: &RulesTable<I, CC::DeviceId>,
1284 init: State,
1285 rule_input: &RuleInput<'_, I, CC::DeviceId>,
1286 mut lookup_table: F,
1287) -> ControlFlow<RuleAction<RuleWalkInfo<O>>, RuleWalkInfo<State>> {
1288 rules.iter().try_fold(
1289 RuleWalkInfo { inner: init, observed_source_address_matcher: false },
1290 |RuleWalkInfo { inner: state, observed_source_address_matcher },
1291 Rule { action, matcher }| {
1292 let observed_source_address_matcher =
1293 observed_source_address_matcher || matcher.source_address_matcher.is_some();
1294 if !matcher.matches(rule_input) {
1295 return ControlFlow::Continue(RuleWalkInfo {
1296 inner: state,
1297 observed_source_address_matcher,
1298 });
1299 }
1300 match action {
1301 RuleAction::Unreachable => return ControlFlow::Break(RuleAction::Unreachable),
1302 RuleAction::Lookup(table_id) => core_ctx.with_ip_routing_table(
1303 &table_id,
1304 |core_ctx, table| match lookup_table(state, core_ctx, table) {
1305 ControlFlow::Break(out) => {
1306 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1307 inner: out,
1308 observed_source_address_matcher,
1309 }))
1310 }
1311 ControlFlow::Continue(state) => ControlFlow::Continue(RuleWalkInfo {
1312 inner: state,
1313 observed_source_address_matcher,
1314 }),
1315 },
1316 ),
1317 }
1318 },
1319 )
1320}
1321
1322pub fn resolve_output_route_to_destination<
1333 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1334 BC: IpDeviceBindingsContext<I, CC::DeviceId> + IpLayerBindingsContext<I, CC::DeviceId>,
1335 CC: IpStateContext<I> + IpDeviceContext<I> + device::IpDeviceConfigurationContext<I, BC>,
1336>(
1337 core_ctx: &mut CC,
1338 device: Option<&CC::DeviceId>,
1339 src_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1340 dst_ip: Option<RoutableIpAddr<I::Addr>>,
1341 marks: &Marks,
1342) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1343 enum LocalDelivery<A, D> {
1344 WeakLoopback { dst_ip: A, device: D },
1345 StrongForDevice(D),
1346 }
1347
1348 let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1366 let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1367 match (device, dst_ip) {
1368 (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1369 .then_some(LocalDelivery::StrongForDevice(device.clone())),
1370 (None, Some(dst_ip)) => {
1371 get_device_with_assigned_address(core_ctx, dst_ip).map(
1372 |(dst_device, _addr_status)| {
1373 if src_ip_and_policy
1378 .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1379 || dst_ip.as_ref().must_have_zone()
1380 {
1381 LocalDelivery::StrongForDevice(dst_device)
1382 } else {
1383 LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1384 }
1385 },
1386 )
1387 }
1388 (_, None) => None,
1389 }
1390 };
1391
1392 if let Some(local_delivery) = local_delivery_instructions {
1393 let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1394
1395 let (src_addr, dest_device) = match local_delivery {
1396 LocalDelivery::WeakLoopback { dst_ip, device } => {
1397 let src_ip = match src_ip_and_policy {
1398 Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1399 let _device = get_device_with_assigned_address(core_ctx, src_ip)
1400 .ok_or(ResolveRouteError::NoSrcAddr)?;
1401 src_ip
1402 }
1403 Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1404 None => dst_ip,
1405 };
1406 (src_ip, device)
1407 }
1408 LocalDelivery::StrongForDevice(device) => {
1409 (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1410 }
1411 };
1412 return Ok(ResolvedRoute {
1413 src_addr,
1414 local_delivery_device: Some(dest_device),
1415 device: loopback,
1416 next_hop: NextHop::RemoteAsNeighbor,
1417 internal_forwarding: InternalForwarding::NotUsed,
1418 });
1419 }
1420 let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1421 let rule_input = RuleInput {
1422 packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1423 marks,
1424 };
1425 core_ctx.with_rules_table(|core_ctx, rules| {
1426 let mut walk_rules = |rule_input, src_ip_and_policy| {
1427 walk_rules(
1428 core_ctx,
1429 rules,
1430 None, rule_input,
1432 |first_error, core_ctx, table| {
1433 let mut matching_with_addr = table.lookup_filter_map(
1434 core_ctx,
1435 device,
1436 dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1437 |core_ctx, d| {
1438 Some(get_local_addr_with_internal_forwarding(
1439 core_ctx,
1440 src_ip_and_policy,
1441 d,
1442 dst_ip,
1443 ))
1444 },
1445 );
1446
1447 let first_error_in_this_table = match matching_with_addr.next() {
1448 Some((
1449 Destination { device, next_hop },
1450 Ok((local_addr, internal_forwarding)),
1451 )) => {
1452 return ControlFlow::Break(Ok((
1453 Destination { device: device.clone(), next_hop },
1454 local_addr,
1455 internal_forwarding,
1456 )));
1457 }
1458 Some((_, Err(e))) => e,
1459 None => return ControlFlow::Continue(first_error),
1463 };
1464
1465 matching_with_addr
1466 .filter_map(|(destination, local_addr)| {
1467 local_addr.ok_checked::<ResolveRouteError>().map(
1470 |(local_addr, internal_forwarding)| {
1471 (destination, local_addr, internal_forwarding)
1472 },
1473 )
1474 })
1475 .next()
1476 .map_or(
1477 ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1478 |(
1479 Destination { device, next_hop },
1480 local_addr,
1481 internal_forwarding,
1482 )| {
1483 ControlFlow::Break(Ok((
1484 Destination { device: device.clone(), next_hop },
1485 local_addr,
1486 internal_forwarding,
1487 )))
1488 },
1489 )
1490 },
1491 )
1492 };
1493
1494 let result = match walk_rules(&rule_input, src_ip_and_policy) {
1495 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1502 inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1503 observed_source_address_matcher: true,
1504 })) if src_ip_and_policy.is_none() => walk_rules(
1505 &RuleInput {
1506 packet_origin: PacketOrigin::Local {
1507 bound_address: Some(selected_src_addr.into()),
1508 bound_device: device,
1509 },
1510 marks,
1511 },
1512 Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1513 ),
1514 result => result,
1515 };
1516
1517 match result {
1518 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1519 inner: result,
1520 observed_source_address_matcher: _,
1521 })) => {
1522 result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1523 ResolvedRoute {
1524 src_addr,
1525 device,
1526 local_delivery_device: None,
1527 next_hop,
1528 internal_forwarding,
1529 }
1530 })
1531 }
1532 ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1533 ControlFlow::Continue(RuleWalkInfo {
1534 inner: first_error,
1535 observed_source_address_matcher: _,
1536 }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1537 }
1538 })
1539}
1540
1541pub trait UseIpSocketContextBlanket {}
1546
1547impl<
1548 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1549 BC: IpDeviceBindingsContext<I, CC::DeviceId>
1550 + IpLayerBindingsContext<I, CC::DeviceId>
1551 + IpSocketBindingsContext,
1552 CC: IpLayerEgressContext<I, BC>
1553 + IpStateContext<I>
1554 + IpDeviceContext<I>
1555 + IpDeviceConfirmReachableContext<I, BC>
1556 + IpDeviceMtuContext<I>
1557 + device::IpDeviceConfigurationContext<I, BC>
1558 + UseIpSocketContextBlanket,
1559 > IpSocketContext<I, BC> for CC
1560{
1561 fn lookup_route(
1562 &mut self,
1563 _bindings_ctx: &mut BC,
1564 device: Option<&CC::DeviceId>,
1565 local_ip: Option<IpDeviceAddr<I::Addr>>,
1566 addr: RoutableIpAddr<I::Addr>,
1567 transparent: bool,
1568 marks: &Marks,
1569 ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1570 let src_ip_and_policy = local_ip.map(|local_ip| {
1571 (
1572 local_ip,
1573 if transparent {
1574 NonLocalSrcAddrPolicy::Allow
1575 } else {
1576 NonLocalSrcAddrPolicy::Deny
1577 },
1578 )
1579 });
1580 let res =
1581 resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1582 trace!(
1583 "lookup_route(\
1584 device={device:?}, \
1585 local_ip={local_ip:?}, \
1586 addr={addr:?}, \
1587 transparent={transparent:?}, \
1588 marks={marks:?}) => {res:?}"
1589 );
1590 res
1591 }
1592
1593 fn send_ip_packet<S>(
1594 &mut self,
1595 bindings_ctx: &mut BC,
1596 meta: SendIpPacketMeta<
1597 I,
1598 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1599 SpecifiedAddr<I::Addr>,
1600 >,
1601 body: S,
1602 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1603 ) -> Result<(), IpSendFrameError<S>>
1604 where
1605 S: TransportPacketSerializer<I>,
1606 S::Buffer: BufferMut,
1607 {
1608 send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1609 }
1610
1611 fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1612 device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1613 }
1614
1615 fn confirm_reachable(
1616 &mut self,
1617 bindings_ctx: &mut BC,
1618 dst: SpecifiedAddr<I::Addr>,
1619 input: RuleInput<'_, I, Self::DeviceId>,
1620 ) {
1621 match lookup_route_table(self, dst.get(), input) {
1622 Some(Destination { next_hop, device }) => {
1623 let neighbor = match next_hop {
1624 NextHop::RemoteAsNeighbor => dst,
1625 NextHop::Gateway(gateway) => gateway,
1626 NextHop::Broadcast(marker) => {
1627 I::map_ip::<_, ()>(
1628 WrapBroadcastMarker(marker),
1629 |WrapBroadcastMarker(())| {
1630 debug!(
1631 "can't confirm {dst:?}@{device:?} as reachable: \
1632 dst is a broadcast address"
1633 );
1634 },
1635 |WrapBroadcastMarker(never)| match never {},
1636 );
1637 return;
1638 }
1639 };
1640 IpDeviceConfirmReachableContext::confirm_reachable(
1641 self,
1642 bindings_ctx,
1643 &device,
1644 neighbor,
1645 );
1646 }
1647 None => {
1648 debug!("can't confirm {dst:?} as reachable: no route");
1649 }
1650 }
1651 }
1652}
1653
1654pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1659 fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1661 &mut self,
1662 bindings_ctx: &mut BC,
1663 device: &Self::DeviceId,
1664 src_ip: I::RecvSrcAddr,
1665 dst_ip: SpecifiedAddr<I::Addr>,
1666 proto: I::Proto,
1667 body: B,
1668 info: &LocalDeliveryPacketInfo<I, H>,
1669 ) -> Result<(), TransportReceiveError>;
1670}
1671
1672pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1674 IpTransportDispatchContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1675 + IpDeviceIngressStateContext<I>
1676 + IpDeviceMtuContext<I>
1677 + IpDeviceSendContext<I, BC>
1678 + IcmpErrorHandler<I, BC>
1679 + IpLayerContext<I, BC>
1680 + FragmentHandler<I, BC>
1681 + FilterHandlerProvider<I, BC>
1682 + RawIpSocketHandler<I, BC>
1683{
1684}
1685
1686impl<
1687 I: IpLayerIpExt,
1688 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1689 CC: IpTransportDispatchContext<
1690 I,
1691 BC,
1692 DeviceId: filter::InterfaceProperties<BC::DeviceClass>,
1693 > + IpDeviceIngressStateContext<I>
1694 + IpDeviceMtuContext<I>
1695 + IpDeviceSendContext<I, BC>
1696 + IcmpErrorHandler<I, BC>
1697 + IpLayerContext<I, BC>
1698 + FragmentHandler<I, BC>
1699 + FilterHandlerProvider<I, BC>
1700 + RawIpSocketHandler<I, BC>,
1701 > IpLayerIngressContext<I, BC> for CC
1702{
1703}
1704
1705pub trait IpLayerEgressContext<I, BC>:
1707 IpDeviceSendContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1708 + FilterHandlerProvider<I, BC>
1709 + CounterContext<IpCounters<I>>
1710where
1711 I: IpLayerIpExt,
1712 BC: FilterBindingsContext + TxMetadataBindingsTypes,
1713{
1714}
1715
1716impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1717where
1718 I: IpLayerIpExt,
1719 BC: FilterBindingsContext + TxMetadataBindingsTypes,
1720 CC: IpDeviceSendContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1721 + FilterHandlerProvider<I, BC>
1722 + CounterContext<IpCounters<I>>,
1723{
1724}
1725
1726pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1728 IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
1729{
1730}
1731
1732impl<
1733 I: IpLayerIpExt,
1734 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1735 CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
1736 > IpLayerForwardingContext<I, BC> for CC
1737{
1738}
1739
1740#[derive(Copy, Clone, Default)]
1742pub struct Ipv4StateBuilder {
1743 icmp: Icmpv4StateBuilder,
1744}
1745
1746impl Ipv4StateBuilder {
1747 #[cfg(any(test, feature = "testutils"))]
1749 pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
1750 &mut self.icmp
1751 }
1752
1753 pub fn build<
1755 CC: CoreTimerContext<IpLayerTimerId, BC>,
1756 StrongDeviceId: StrongDeviceIdentifier,
1757 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1758 >(
1759 self,
1760 bindings_ctx: &mut BC,
1761 ) -> Ipv4State<StrongDeviceId, BC> {
1762 let Ipv4StateBuilder { icmp } = self;
1763
1764 Ipv4State {
1765 inner: IpStateInner::new::<CC>(bindings_ctx),
1766 icmp: icmp.build(),
1767 next_packet_id: Default::default(),
1768 }
1769 }
1770}
1771
1772#[derive(Copy, Clone)]
1776pub struct Ipv6StateBuilder {
1777 icmp: Icmpv6StateBuilder,
1778 slaac_stable_secret_key: Option<IidSecret>,
1779}
1780
1781impl Ipv6StateBuilder {
1782 pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
1787 self.slaac_stable_secret_key = Some(secret_key);
1788 self
1789 }
1790
1791 pub fn build<
1797 CC: CoreTimerContext<IpLayerTimerId, BC>,
1798 StrongDeviceId: StrongDeviceIdentifier,
1799 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1800 >(
1801 self,
1802 bindings_ctx: &mut BC,
1803 ) -> Ipv6State<StrongDeviceId, BC> {
1804 let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
1805
1806 let slaac_stable_secret_key = slaac_stable_secret_key
1807 .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
1808
1809 Ipv6State {
1810 inner: IpStateInner::new::<CC>(bindings_ctx),
1811 icmp: icmp.build(),
1812 slaac_counters: Default::default(),
1813 slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
1814 slaac_stable_secret_key,
1815 }
1816 }
1817}
1818
1819impl Default for Ipv6StateBuilder {
1820 fn default() -> Self {
1821 #[cfg(any(test, feature = "testutils"))]
1822 let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
1823
1824 #[cfg(not(any(test, feature = "testutils")))]
1825 let slaac_stable_secret_key = None;
1826
1827 Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
1828 }
1829}
1830
1831pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1833 pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
1835 pub icmp: Icmpv4State<BT>,
1837 pub next_packet_id: AtomicU16,
1839}
1840
1841impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1842 AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
1843{
1844 fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
1845 &self.inner
1846 }
1847}
1848
1849pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
1853 core_ctx: &mut CC,
1854) -> I::PacketId {
1855 core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
1856}
1857
1858pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1860 pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
1862 pub icmp: Icmpv6State<BT>,
1864 pub slaac_counters: SlaacCounters,
1866 pub slaac_temp_secret_key: IidSecret,
1868 pub slaac_stable_secret_key: IidSecret,
1873}
1874
1875impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1876 AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
1877{
1878 fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
1879 &self.inner
1880 }
1881}
1882
1883impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1884 OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
1885{
1886 type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
1887 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1888 OrderedLockRef::new(&self.fragment_cache)
1889 }
1890}
1891
1892impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1893 OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
1894{
1895 type Lock = Mutex<PmtuCache<I, BT>>;
1896 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1897 OrderedLockRef::new(&self.pmtu_cache)
1898 }
1899}
1900
1901impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1902 OrderedLockAccess<RulesTable<I, D>> for IpStateInner<I, D, BT>
1903{
1904 type Lock = RwLock<RulesTable<I, D>>;
1905 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1906 OrderedLockRef::new(&self.rules_table)
1907 }
1908}
1909
1910impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1911 OrderedLockAccess<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>
1912 for IpStateInner<I, D, BT>
1913{
1914 type Lock = Mutex<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>;
1915 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1916 OrderedLockRef::new(&self.tables)
1917 }
1918}
1919
1920impl<I: IpLayerIpExt, D: StrongDeviceIdentifier> OrderedLockAccess<RoutingTable<I, D>>
1921 for RoutingTableId<I, D>
1922{
1923 type Lock = RwLock<RoutingTable<I, D>>;
1924 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1925 let Self(inner) = self;
1926 OrderedLockRef::new(&*inner)
1927 }
1928}
1929
1930impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1931 OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
1932{
1933 type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
1934 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1935 OrderedLockRef::new(&self.multicast_forwarding)
1936 }
1937}
1938
1939impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1940 OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
1941{
1942 type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
1943 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1944 OrderedLockRef::new(&self.raw_sockets)
1945 }
1946}
1947
1948impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1949 OrderedLockAccess<filter::State<I, I::Weak<BT>, BT>> for IpStateInner<I, D, BT>
1950{
1951 type Lock = RwLock<filter::State<I, I::Weak<BT>, BT>>;
1952 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1953 OrderedLockRef::new(&self.filter)
1954 }
1955}
1956
1957#[derive(Default, GenericOverIp)]
1959#[generic_over_ip(I, Ip)]
1960pub struct IpCounters<I: IpLayerIpExt> {
1961 pub deliver_unicast: Counter,
1963 pub deliver_multicast: Counter,
1965 pub dispatch_receive_ip_packet: Counter,
1967 pub dispatch_receive_ip_packet_other_host: Counter,
1969 pub receive_ip_packet: Counter,
1971 pub send_ip_packet: Counter,
1973 pub forwarding_disabled: Counter,
1976 pub forward: Counter,
1978 pub no_route_to_host: Counter,
1981 pub mtu_exceeded: Counter,
1984 pub ttl_expired: Counter,
1987 pub receive_icmp_error: Counter,
1989 pub fragment_reassembly_error: Counter,
1991 pub need_more_fragments: Counter,
1994 pub invalid_fragment: Counter,
1997 pub fragment_cache_full: Counter,
2000 pub parameter_problem: Counter,
2002 pub unspecified_destination: Counter,
2004 pub unspecified_source: Counter,
2006 pub dropped: Counter,
2008 pub tx_illegal_loopback_address: Counter,
2011 pub version_rx: I::RxCounters,
2013 pub multicast_no_interest: Counter,
2017 pub invalid_cached_conntrack_entry: Counter,
2021 pub fragmentation: FragmentationCounters,
2023}
2024
2025#[derive(Default)]
2027pub struct Ipv4RxCounters {
2028 pub deliver_broadcast: Counter,
2030}
2031
2032impl Inspectable for Ipv4RxCounters {
2033 fn record<I: Inspector>(&self, inspector: &mut I) {
2034 let Self { deliver_broadcast } = self;
2035 inspector.record_counter("DeliveredBroadcast", deliver_broadcast);
2036 }
2037}
2038
2039#[derive(Default)]
2041pub struct Ipv6RxCounters {
2042 pub drop_for_tentative: Counter,
2045 pub non_unicast_source: Counter,
2047 pub extension_header_discard: Counter,
2050 pub drop_looped_back_dad_probe: Counter,
2053}
2054
2055impl Inspectable for Ipv6RxCounters {
2056 fn record<I: Inspector>(&self, inspector: &mut I) {
2057 let Self {
2058 drop_for_tentative,
2059 non_unicast_source,
2060 extension_header_discard,
2061 drop_looped_back_dad_probe,
2062 } = self;
2063 inspector.record_counter("DroppedTentativeDst", drop_for_tentative);
2064 inspector.record_counter("DroppedNonUnicastSrc", non_unicast_source);
2065 inspector.record_counter("DroppedExtensionHeader", extension_header_discard);
2066 inspector.record_counter("DroppedLoopedBackDadProbe", drop_looped_back_dad_probe);
2067 }
2068}
2069
2070pub trait IpStateBindingsTypes:
2072 PmtuBindingsTypes
2073 + FragmentBindingsTypes
2074 + RawIpSocketsBindingsTypes
2075 + FilterBindingsTypes
2076 + MulticastForwardingBindingsTypes
2077 + IpDeviceStateBindingsTypes
2078{
2079}
2080impl<BT> IpStateBindingsTypes for BT where
2081 BT: PmtuBindingsTypes
2082 + FragmentBindingsTypes
2083 + RawIpSocketsBindingsTypes
2084 + FilterBindingsTypes
2085 + MulticastForwardingBindingsTypes
2086 + IpDeviceStateBindingsTypes
2087{
2088}
2089
2090#[derive(Clone, PartialEq, Eq, Hash)]
2092pub struct RoutingTableId<I: Ip, D>(StrongRc<RwLock<RoutingTable<I, D>>>);
2093
2094impl<I: Ip, D> Debug for RoutingTableId<I, D> {
2095 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2096 let Self(rc) = self;
2097 f.debug_tuple("RoutingTableId").field(&StrongRc::debug_id(rc)).finish()
2098 }
2099}
2100
2101impl<I: Ip, D> RoutingTableId<I, D> {
2102 pub(crate) fn new(rc: StrongRc<RwLock<RoutingTable<I, D>>>) -> Self {
2104 Self(rc)
2105 }
2106
2107 #[cfg(any(test, feature = "testutils"))]
2109 pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
2110 let Self(inner) = self;
2111 &*inner
2112 }
2113
2114 pub fn downgrade(&self) -> WeakRoutingTableId<I, D> {
2116 let Self(rc) = self;
2117 WeakRoutingTableId(StrongRc::downgrade(rc))
2118 }
2119
2120 #[cfg(test)]
2121 fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2122 let Self(rc) = self;
2123 rc.write()
2124 }
2125}
2126
2127#[derive(Clone, PartialEq, Eq, Hash)]
2129pub struct WeakRoutingTableId<I: Ip, D>(WeakRc<RwLock<RoutingTable<I, D>>>);
2130
2131impl<I: Ip, D> Debug for WeakRoutingTableId<I, D> {
2132 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2133 let Self(rc) = self;
2134 f.debug_tuple("WeakRoutingTableId").field(&WeakRc::debug_id(rc)).finish()
2135 }
2136}
2137
2138#[derive(GenericOverIp)]
2140#[generic_over_ip(I, Ip)]
2141pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2142 rules_table: RwLock<RulesTable<I, D>>,
2143 main_table_id: RoutingTableId<I, D>,
2145 multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2146 multicast_forwarding_counters: MulticastForwardingCounters<I>,
2147 fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2148 pmtu_cache: Mutex<PmtuCache<I, BT>>,
2149 counters: IpCounters<I>,
2150 raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2151 raw_socket_counters: RawIpSocketCounters<I>,
2152 filter: RwLock<filter::State<I, I::Weak<BT>, BT>>,
2153 tables: Mutex<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>,
2159 igmp_counters: IgmpCounters,
2160 mld_counters: MldCounters,
2161}
2162
2163impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2164 pub fn counters(&self) -> &IpCounters<I> {
2166 &self.counters
2167 }
2168
2169 pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2171 &self.multicast_forwarding_counters
2172 }
2173
2174 pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2176 &self.raw_socket_counters
2177 }
2178
2179 pub fn main_table_id(&self) -> &RoutingTableId<I, D> {
2181 &self.main_table_id
2182 }
2183
2184 #[cfg(any(test, feature = "testutils"))]
2186 pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2187 &self.pmtu_cache
2188 }
2189
2190 #[cfg(any(test, feature = "testutils"))]
2192 pub fn filter(&self) -> &RwLock<filter::State<I, I::Weak<BT>, BT>> {
2193 &self.filter
2194 }
2195
2196 pub fn igmp_counters(&self) -> &IgmpCounters {
2198 &self.igmp_counters
2199 }
2200
2201 pub fn mld_counters(&self) -> &MldCounters {
2203 &self.mld_counters
2204 }
2205}
2206
2207impl<
2208 I: IpLayerIpExt,
2209 D: StrongDeviceIdentifier,
2210 BC: TimerContext + RngContext + IpStateBindingsTypes,
2211 > IpStateInner<I, D, BC>
2212{
2213 fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2215 let main_table: PrimaryRc<RwLock<RoutingTable<I, D>>> = PrimaryRc::new(Default::default());
2216 let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2217 Self {
2218 rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2219 tables: Mutex::new(HashMap::from_iter(core::iter::once((
2220 main_table_id.clone(),
2221 main_table,
2222 )))),
2223 main_table_id,
2224 multicast_forwarding: Default::default(),
2225 multicast_forwarding_counters: Default::default(),
2226 fragment_cache: Mutex::new(
2227 IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2228 ),
2229 pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2230 counters: Default::default(),
2231 raw_sockets: Default::default(),
2232 raw_socket_counters: Default::default(),
2233 filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2234 igmp_counters: Default::default(),
2235 mld_counters: Default::default(),
2236 }
2237 }
2238}
2239
2240#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2242#[generic_over_ip()]
2243pub enum IpLayerTimerId {
2244 ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2246 ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2248 PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2250 PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2252 FilterTimerv4(FilterTimerId<Ipv4>),
2254 FilterTimerv6(FilterTimerId<Ipv6>),
2256 MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2258 MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2260}
2261
2262impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2263 fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2264 I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2265 }
2266}
2267
2268impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2269 fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2270 I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2271 }
2272}
2273
2274impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2275 fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2276 I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2277 }
2278}
2279
2280impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2281 fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2282 I::map_ip(
2283 timer,
2284 IpLayerTimerId::MulticastForwardingTimerv4,
2285 IpLayerTimerId::MulticastForwardingTimerv6,
2286 )
2287 }
2288}
2289
2290impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2291where
2292 CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2293 + TimerHandler<BC, FragmentTimerId<Ipv6>>
2294 + TimerHandler<BC, PmtuTimerId<Ipv4>>
2295 + TimerHandler<BC, PmtuTimerId<Ipv6>>
2296 + TimerHandler<BC, FilterTimerId<Ipv4>>
2297 + TimerHandler<BC, FilterTimerId<Ipv6>>
2298 + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2299 + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2300 BC: TimerBindingsTypes,
2301{
2302 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2303 match self {
2304 IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2305 core_ctx.handle_timer(bindings_ctx, id, timer)
2306 }
2307 IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2308 core_ctx.handle_timer(bindings_ctx, id, timer)
2309 }
2310 IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2311 IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2312 IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2313 IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2314 IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2315 core_ctx.handle_timer(bindings_ctx, id, timer)
2316 }
2317 IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2318 core_ctx.handle_timer(bindings_ctx, id, timer)
2319 }
2320 }
2321 }
2322}
2323
2324pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2331 err: I::IcmpError,
2333 src_ip: I::SourceAddress,
2336 dst_ip: SpecifiedAddr<I::Addr>,
2339 frame_dst: Option<FrameDestination>,
2341 device: &'a D,
2343 meta: ParseMetadata,
2346 marks: Marks,
2348}
2349
2350impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2351 fn respond_with_icmp_error<B, BC, CC>(
2358 self,
2359 core_ctx: &mut CC,
2360 bindings_ctx: &mut BC,
2361 mut body: B,
2362 ) where
2363 B: BufferMut,
2364 CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2365 {
2366 let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks } = self;
2367 body.undo_parse(meta);
2371
2372 core_ctx.send_icmp_error_message(
2373 bindings_ctx,
2374 device,
2375 frame_dst,
2376 src_ip,
2377 dst_ip,
2378 body,
2379 err,
2380 &marks,
2381 );
2382 }
2383}
2384
2385fn dispatch_receive_ipv4_packet<
2406 'a,
2407 'b,
2408 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2409 CC: IpLayerIngressContext<Ipv4, BC> + CounterContext<IpCounters<Ipv4>>,
2410>(
2411 core_ctx: &'a mut CC,
2412 bindings_ctx: &'a mut BC,
2413 device: &'b CC::DeviceId,
2414 frame_dst: Option<FrameDestination>,
2415 mut packet: Ipv4Packet<&'a mut [u8]>,
2416 mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2417 receive_meta: ReceiveIpPacketMeta<Ipv4>,
2418) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2419 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx).dispatch_receive_ip_packet.increment();
2420
2421 match frame_dst {
2422 Some(FrameDestination::Individual { local: false }) => {
2423 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx)
2424 .dispatch_receive_ip_packet_other_host
2425 .increment();
2426 }
2427 Some(FrameDestination::Individual { local: true })
2428 | Some(FrameDestination::Multicast)
2429 | Some(FrameDestination::Broadcast)
2430 | None => (),
2431 }
2432
2433 let proto = packet.proto();
2434
2435 match core_ctx.filter_handler().local_ingress_hook(
2436 bindings_ctx,
2437 &mut packet,
2438 device,
2439 &mut packet_metadata,
2440 ) {
2441 filter::Verdict::Drop => {
2442 packet_metadata.acknowledge_drop();
2443 return Ok(());
2444 }
2445 filter::Verdict::Accept(()) => {}
2446 }
2447 let marks = packet_metadata.marks;
2448 packet_metadata.acknowledge_drop();
2449
2450 let src_ip = packet.src_ip();
2451 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2455 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx).unspecified_destination.increment();
2456 debug!(
2457 "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2458 after the LOCAL_INGRESS hook; dropping"
2459 );
2460 return Ok(());
2461 };
2462
2463 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2464
2465 let (prefix, options, body) = packet.parts_with_body_mut();
2466 let buffer = Buf::new(body, ..);
2467 let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2468 let receive_info = LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks };
2469
2470 core_ctx
2471 .dispatch_receive_ip_packet(
2472 bindings_ctx,
2473 device,
2474 src_ip,
2475 dst_ip,
2476 proto,
2477 buffer,
2478 &receive_info,
2479 )
2480 .or_else(|err| {
2481 if let Some(src_ip) = SpecifiedAddr::new(src_ip) {
2482 let (_, _, _, meta) = packet.into_metadata();
2483 Err(IcmpErrorSender {
2484 err: err.into_icmpv4_error(meta.header_len()),
2485 src_ip,
2486 dst_ip,
2487 frame_dst,
2488 device,
2489 meta,
2490 marks,
2491 })
2492 } else {
2493 Ok(())
2494 }
2495 })
2496}
2497
2498fn dispatch_receive_ipv6_packet<
2503 'a,
2504 'b,
2505 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2506 CC: IpLayerIngressContext<Ipv6, BC> + CounterContext<IpCounters<Ipv6>>,
2507>(
2508 core_ctx: &'a mut CC,
2509 bindings_ctx: &'a mut BC,
2510 device: &'b CC::DeviceId,
2511 frame_dst: Option<FrameDestination>,
2512 mut packet: Ipv6Packet<&'a mut [u8]>,
2513 mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2514 meta: ReceiveIpPacketMeta<Ipv6>,
2515) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2516 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx).dispatch_receive_ip_packet.increment();
2523
2524 match frame_dst {
2525 Some(FrameDestination::Individual { local: false }) => {
2526 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
2527 .dispatch_receive_ip_packet_other_host
2528 .increment();
2529 }
2530 Some(FrameDestination::Individual { local: true })
2531 | Some(FrameDestination::Multicast)
2532 | Some(FrameDestination::Broadcast)
2533 | None => (),
2534 }
2535
2536 let proto = packet.proto();
2537
2538 match core_ctx.filter_handler().local_ingress_hook(
2539 bindings_ctx,
2540 &mut packet,
2541 device,
2542 &mut packet_metadata,
2543 ) {
2544 filter::Verdict::Drop => {
2545 packet_metadata.acknowledge_drop();
2546 return Ok(());
2547 }
2548 filter::Verdict::Accept(()) => {}
2549 }
2550
2551 let Some(src_ip) = packet.src_ipv6() else {
2555 debug!(
2556 "dispatch_receive_ipv6_packet: received packet from non-unicast source {} after the \
2557 LOCAL_INGRESS hook; dropping",
2558 packet.src_ip()
2559 );
2560 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
2561 .version_rx
2562 .non_unicast_source
2563 .increment();
2564 return Ok(());
2565 };
2566 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2567 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx).unspecified_destination.increment();
2568 debug!(
2569 "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2570 after the LOCAL_INGRESS hook; dropping"
2571 );
2572 return Ok(());
2573 };
2574
2575 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2576
2577 let (fixed, extension, body) = packet.parts_with_body_mut();
2578 let buffer = Buf::new(body, ..);
2579 let header_info = Ipv6HeaderInfo { fixed, extension };
2580 let receive_info = LocalDeliveryPacketInfo { meta, header_info, marks: packet_metadata.marks };
2581
2582 let result = core_ctx
2583 .dispatch_receive_ip_packet(
2584 bindings_ctx,
2585 device,
2586 src_ip,
2587 dst_ip,
2588 proto,
2589 buffer,
2590 &receive_info,
2591 )
2592 .or_else(|err| {
2593 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
2594 let (_, _, _, meta) = packet.into_metadata();
2595 Err(IcmpErrorSender {
2596 err: err.into_icmpv6_error(meta.header_len()),
2597 src_ip: *src_ip,
2598 dst_ip,
2599 frame_dst,
2600 device,
2601 meta,
2602 marks: receive_info.marks,
2603 })
2604 } else {
2605 Ok(())
2606 }
2607 });
2608 packet_metadata.acknowledge_drop();
2609 result
2610}
2611
2612pub(crate) struct IpPacketForwarder<
2619 'a,
2620 I: IpLayerIpExt,
2621 D,
2622 A,
2623 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2624> {
2625 inbound_device: &'a D,
2626 outbound_device: &'a D,
2627 packet_meta: IpLayerPacketMetadata<I, A, BT>,
2628 src_ip: I::RecvSrcAddr,
2629 dst_ip: SpecifiedAddr<I::Addr>,
2630 destination: IpPacketDestination<I, &'a D>,
2631 proto: I::Proto,
2632 parse_meta: ParseMetadata,
2633 frame_dst: Option<FrameDestination>,
2634}
2635
2636impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
2637where
2638 I: IpLayerIpExt,
2639 BC: IpLayerBindingsContext<I, D>,
2640{
2641 fn forward_with_buffer<CC, B>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B)
2643 where
2644 B: BufferMut,
2645 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2646 {
2647 let Self {
2648 inbound_device,
2649 outbound_device,
2650 packet_meta,
2651 src_ip,
2652 dst_ip,
2653 destination,
2654 proto,
2655 parse_meta,
2656 frame_dst,
2657 } = self;
2658
2659 let packet = ForwardedPacket::new(src_ip.into(), dst_ip.get(), proto, parse_meta, buffer);
2660
2661 trace!("forward_with_buffer: forwarding {} packet", I::NAME);
2662
2663 let marks = packet_meta.marks;
2664 match send_ip_frame(
2665 core_ctx,
2666 bindings_ctx,
2667 outbound_device,
2668 destination,
2669 packet,
2670 packet_meta,
2671 Mtu::no_limit(),
2672 ) {
2673 Ok(()) => (),
2674 Err(IpSendFrameError { serializer, error }) => {
2675 match error {
2676 IpSendFrameErrorReason::Device(
2677 SendFrameErrorReason::SizeConstraintsViolation,
2678 ) => {
2679 debug!("failed to forward {} packet: MTU exceeded", I::NAME);
2680 CounterContext::<IpCounters<I>>::counters(core_ctx)
2681 .mtu_exceeded
2682 .increment();
2683 let mtu = core_ctx.get_mtu(inbound_device);
2684 let Some(err) = I::new_mtu_exceeded(proto, parse_meta.header_len(), mtu)
2686 else {
2687 return;
2688 };
2689 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2692 return;
2693 };
2694 core_ctx.send_icmp_error_message(
2704 bindings_ctx,
2705 inbound_device,
2706 frame_dst,
2707 src_ip,
2708 dst_ip,
2709 serializer.into_buffer(),
2710 err,
2711 &marks,
2712 );
2713 }
2714 IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
2715 | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
2716 | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
2717 }
2718 debug!("failed to forward {} packet: {error:?}", I::NAME);
2719 }
2720 }
2721 }
2722}
2723
2724pub(crate) enum ForwardingAction<
2726 'a,
2727 I: IpLayerIpExt,
2728 D,
2729 A,
2730 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2731> {
2732 SilentlyDrop,
2734 Forward(IpPacketForwarder<'a, I, D, A, BT>),
2736 DropWithIcmpError(IcmpErrorSender<'a, I, D>),
2739}
2740
2741impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
2742where
2743 I: IpLayerIpExt,
2744 BC: IpLayerBindingsContext<I, D>,
2745{
2746 pub(crate) fn perform_action_with_buffer<CC, B>(
2748 self,
2749 core_ctx: &mut CC,
2750 bindings_ctx: &mut BC,
2751 buffer: B,
2752 ) where
2753 B: BufferMut,
2754 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2755 {
2756 match self {
2757 ForwardingAction::SilentlyDrop => {}
2758 ForwardingAction::Forward(forwarder) => {
2759 forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer)
2760 }
2761 ForwardingAction::DropWithIcmpError(icmp_sender) => {
2762 icmp_sender.respond_with_icmp_error(core_ctx, bindings_ctx, buffer)
2763 }
2764 }
2765 }
2766}
2767
2768pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
2770 core_ctx: &'a mut CC,
2771 mut packet: I::Packet<&'a mut [u8]>,
2772 mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2773 minimum_ttl: Option<u8>,
2774 inbound_device: &'b CC::DeviceId,
2775 outbound_device: &'b CC::DeviceId,
2776 destination: IpPacketDestination<I, &'b CC::DeviceId>,
2777 frame_dst: Option<FrameDestination>,
2778 src_ip: I::RecvSrcAddr,
2779 dst_ip: SpecifiedAddr<I::Addr>,
2780) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
2781where
2782 I: IpLayerIpExt,
2783 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2784 CC: IpLayerForwardingContext<I, BC>,
2785{
2786 const DEFAULT_MINIMUM_FORWARDING_TTL: u8 = 2;
2791 let minimum_ttl = minimum_ttl.unwrap_or(DEFAULT_MINIMUM_FORWARDING_TTL);
2792
2793 let ttl = packet.ttl();
2794 if ttl < minimum_ttl {
2795 debug!(
2796 "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
2797 I::NAME
2798 );
2799 if ttl > 1 {
2811 packet_meta.acknowledge_drop();
2812 return ForwardingAction::SilentlyDrop;
2813 }
2814
2815 CounterContext::<IpCounters<I>>::counters(core_ctx).ttl_expired.increment();
2816
2817 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2819 CounterContext::<IpCounters<I>>::counters(core_ctx).unspecified_source.increment();
2820 packet_meta.acknowledge_drop();
2821 return ForwardingAction::SilentlyDrop;
2822 };
2823
2824 let version_specific_meta = packet.version_specific_meta();
2826 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
2827 let err = I::new_ttl_expired(proto, parse_meta.header_len(), version_specific_meta);
2828 let action = ForwardingAction::DropWithIcmpError(IcmpErrorSender {
2829 err,
2830 src_ip,
2831 dst_ip,
2832 frame_dst,
2833 device: inbound_device,
2834 meta: parse_meta,
2835 marks: packet_meta.marks,
2836 });
2837 packet_meta.acknowledge_drop();
2838 return action;
2839 }
2840
2841 trace!("determine_ip_packet_forwarding_action: adequate TTL");
2842
2843 let maybe_ipv6_packet_action = I::map_ip_in(
2849 &packet,
2850 |_packet| None,
2851 |packet| {
2852 Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
2853 },
2854 );
2855 match maybe_ipv6_packet_action {
2856 None => {} Some(Ipv6PacketAction::_Discard) => {
2858 let counters = CounterContext::<IpCounters<I>>::counters(core_ctx);
2859 #[derive(GenericOverIp)]
2860 #[generic_over_ip(I, Ip)]
2861 struct InCounters<'a, I: IpLayerIpExt>(&'a I::RxCounters);
2862 I::map_ip::<_, ()>(
2863 InCounters(&counters.version_rx),
2864 |_counters| {
2865 unreachable!("`I` must be `Ipv6` because we're handling IPv6 extension headers")
2866 },
2867 |InCounters(counters)| counters.extension_header_discard.increment(),
2868 );
2869 trace!(
2870 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
2871 discarding packet"
2872 );
2873 packet_meta.acknowledge_drop();
2874 return ForwardingAction::SilentlyDrop;
2875 }
2876 Some(Ipv6PacketAction::Continue) => {
2877 trace!(
2878 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
2879 forwarding packet"
2880 );
2881 }
2882 Some(Ipv6PacketAction::ProcessFragment) => {
2883 unreachable!(
2884 "When forwarding packets, we should only ever look at the hop by hop \
2885 options extension header (if present)"
2886 )
2887 }
2888 };
2889
2890 match core_ctx.filter_handler().forwarding_hook(
2891 I::as_filter_packet(&mut packet),
2892 inbound_device,
2893 outbound_device,
2894 &mut packet_meta,
2895 ) {
2896 filter::Verdict::Drop => {
2897 packet_meta.acknowledge_drop();
2898 trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
2899 return ForwardingAction::SilentlyDrop;
2900 }
2901 filter::Verdict::Accept(()) => {}
2902 }
2903
2904 packet.set_ttl(ttl - 1);
2905 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
2906 ForwardingAction::Forward(IpPacketForwarder {
2907 inbound_device,
2908 outbound_device,
2909 packet_meta,
2910 src_ip,
2911 dst_ip,
2912 destination,
2913 proto,
2914 parse_meta,
2915 frame_dst,
2916 })
2917}
2918
2919pub(crate) fn send_ip_frame<I, CC, BC, S>(
2920 core_ctx: &mut CC,
2921 bindings_ctx: &mut BC,
2922 device: &CC::DeviceId,
2923 destination: IpPacketDestination<I, &CC::DeviceId>,
2924 mut body: S,
2925 mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2926 limit_mtu: Mtu,
2927) -> Result<(), IpSendFrameError<S>>
2928where
2929 I: IpLayerIpExt,
2930 BC: FilterBindingsContext + TxMetadataBindingsTypes,
2931 CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
2932 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>,
2933{
2934 let (verdict, proof) = core_ctx.filter_handler().egress_hook(
2935 bindings_ctx,
2936 &mut body,
2937 device,
2938 &mut packet_metadata,
2939 );
2940 match verdict {
2941 filter::Verdict::Drop => {
2942 packet_metadata.acknowledge_drop();
2943 return Ok(());
2944 }
2945 filter::Verdict::Accept(()) => {}
2946 }
2947
2948 let (conntrack_connection_and_direction, tx_metadata, marks) = packet_metadata.into_parts();
2952 let conntrack_entry = if device.is_loopback() {
2953 conntrack_connection_and_direction
2954 .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
2955 } else {
2956 None
2957 };
2958 let device_ip_layer_metadata = DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks };
2959
2960 if !device.is_loopback()
2964 && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
2965 || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
2966 {
2967 CounterContext::<IpCounters<I>>::counters(core_ctx).tx_illegal_loopback_address.increment();
2968 return Err(IpSendFrameError {
2969 serializer: body,
2970 error: IpSendFrameErrorReason::IllegalLoopbackAddress,
2971 });
2972 }
2973
2974 let mtu = limit_mtu.min(core_ctx.get_mtu(device));
2976
2977 let body = body.with_size_limit(mtu.into());
2978
2979 let fits_mtu =
2980 match body.serialize_new_buf(PacketConstraints::UNCONSTRAINED, AlwaysFailBufferAlloc) {
2981 Err(SerializeError::Alloc(())) => true,
2984 Err(SerializeError::SizeLimitExceeded) => false,
2986 };
2987
2988 if fits_mtu {
2989 return core_ctx
2990 .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
2991 .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
2992 serializer: serializer.into_inner(),
2993 error: error.into(),
2994 });
2995 }
2996
2997 CounterContext::<IpCounters<I>>::counters(core_ctx)
3000 .fragmentation
3001 .fragmentation_required
3002 .increment();
3003
3004 let mut device_ip_layer_metadata = Some(device_ip_layer_metadata);
3006 let body = body.into_inner();
3007 let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
3008 Ok(mut fragmenter) => loop {
3009 let (fragment, has_more) = match fragmenter.next() {
3010 None => break Ok(()),
3011 Some(f) => f,
3012 };
3013
3014 let device_ip_layer_metadata = if has_more {
3019 let device_ip_layer_metadata = device_ip_layer_metadata.as_ref().unwrap();
3021 DeviceIpLayerMetadata {
3022 conntrack_entry: device_ip_layer_metadata.conntrack_entry.clone(),
3023 tx_metadata: Default::default(),
3024 marks: device_ip_layer_metadata.marks,
3025 }
3026 } else {
3027 device_ip_layer_metadata.take().unwrap()
3029 };
3030
3031 match core_ctx.send_ip_frame(
3032 bindings_ctx,
3033 device,
3034 destination.clone(),
3035 device_ip_layer_metadata,
3036 fragment,
3037 proof.clone_for_fragmentation(),
3038 ) {
3039 Ok(()) => {
3040 CounterContext::<IpCounters<I>>::counters(core_ctx)
3041 .fragmentation
3042 .fragments
3043 .increment();
3044 }
3045 Err(ErrorAndSerializer { serializer: _, error }) => {
3046 CounterContext::<IpCounters<I>>::counters(core_ctx)
3047 .fragmentation
3048 .error_fragmented_serializer
3049 .increment();
3050 break Err(error);
3051 }
3052 }
3053 },
3054 Err(e) => {
3055 CounterContext::<IpCounters<I>>::counters(core_ctx)
3056 .fragmentation
3057 .error_counter(e)
3058 .increment();
3059 Err(SendFrameErrorReason::SizeConstraintsViolation)
3060 }
3061 };
3062 result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
3063}
3064
3065struct AlwaysFailBufferAlloc;
3070
3071impl BufferAlloc<Never> for AlwaysFailBufferAlloc {
3072 type Error = ();
3073 fn alloc(self, _len: usize) -> Result<Never, Self::Error> {
3074 Err(())
3075 }
3076}
3077
3078macro_rules! drop_packet_and_undo_parse {
3087 ($packet:expr, $buffer:expr) => {{
3088 let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
3089 $buffer.undo_parse(meta);
3090 (src_ip, dst_ip, proto, meta)
3091 }};
3092}
3093
3094enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
3097 Done,
3100
3101 NotNeeded(I::Packet<&'a mut [u8]>),
3104
3105 Reassembled(Vec<u8>),
3108}
3109
3110fn process_fragment<'a, I, CC, BC>(
3116 core_ctx: &mut CC,
3117 bindings_ctx: &mut BC,
3118 packet: I::Packet<&'a mut [u8]>,
3119) -> ProcessFragmentResult<'a, I>
3120where
3121 I: IpLayerIpExt,
3122 for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3123 CC: IpLayerIngressContext<I, BC> + CounterContext<IpCounters<I>>,
3124 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3125{
3126 match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3127 FragmentProcessingState::NotNeeded(packet) => {
3129 trace!("receive_ip_packet: not fragmented");
3130 ProcessFragmentResult::NotNeeded(packet)
3131 }
3132 FragmentProcessingState::Ready { key, packet_len } => {
3134 trace!("receive_ip_packet: fragmented, ready for reassembly");
3135 let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3137
3138 let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3140 core_ctx,
3141 bindings_ctx,
3142 &key,
3143 buffer.buffer_view_mut(),
3144 ) {
3145 Ok(()) => ProcessFragmentResult::Reassembled(buffer.into_inner()),
3147 Err(e) => {
3148 CounterContext::<IpCounters<I>>::counters(core_ctx)
3149 .fragment_reassembly_error
3150 .increment();
3151 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3152 ProcessFragmentResult::Done
3153 }
3154 };
3155 reassemble_result
3156 }
3157 FragmentProcessingState::NeedMoreFragments => {
3160 CounterContext::<IpCounters<I>>::counters(core_ctx).need_more_fragments.increment();
3161 trace!("receive_ip_packet: fragmented, need more before reassembly");
3162 ProcessFragmentResult::Done
3163 }
3164 FragmentProcessingState::InvalidFragment => {
3166 CounterContext::<IpCounters<I>>::counters(core_ctx).invalid_fragment.increment();
3167 trace!("receive_ip_packet: fragmented, invalid");
3168 ProcessFragmentResult::Done
3169 }
3170 FragmentProcessingState::OutOfMemory => {
3171 CounterContext::<IpCounters<I>>::counters(core_ctx).fragment_cache_full.increment();
3172 trace!("receive_ip_packet: fragmented, dropped because OOM");
3173 ProcessFragmentResult::Done
3174 }
3175 }
3176}
3177
3178macro_rules! try_parse_ip_packet {
3188 ($buffer:expr) => {{
3189 let p_len = $buffer.prefix_len();
3190 let s_len = $buffer.suffix_len();
3191
3192 let result = $buffer.parse_mut();
3193
3194 if let Err(err) = result {
3195 let n_p_len = $buffer.prefix_len();
3197 let n_s_len = $buffer.suffix_len();
3198
3199 if p_len > n_p_len {
3200 $buffer.grow_front(p_len - n_p_len);
3201 }
3202
3203 if s_len > n_s_len {
3204 $buffer.grow_back(s_len - n_s_len);
3205 }
3206
3207 Err(err)
3208 } else {
3209 result
3210 }
3211 }};
3212}
3213
3214macro_rules! clone_packet_for_mcast_forwarding {
3232 {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3233 let mut $new_data = $packet.to_vec();
3234 let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3235 let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3236 };
3237}
3238
3239pub fn receive_ipv4_packet<
3244 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3245 B: BufferMut,
3246 CC: IpLayerIngressContext<Ipv4, BC> + CounterContext<IpCounters<Ipv4>>,
3247>(
3248 core_ctx: &mut CC,
3249 bindings_ctx: &mut BC,
3250 device: &CC::DeviceId,
3251 frame_dst: Option<FrameDestination>,
3252 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3253 buffer: B,
3254) {
3255 if !core_ctx.is_ip_device_enabled(&device) {
3256 return;
3257 }
3258
3259 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3262
3263 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx).receive_ip_packet.increment();
3264 trace!("receive_ip_packet({device:?})");
3265
3266 let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3267 Ok(packet) => packet,
3268 Err(IpParseError::ParameterProblem {
3277 src_ip,
3278 dst_ip,
3279 code,
3280 pointer,
3281 must_send_icmp,
3282 header_len,
3283 action,
3284 }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
3285 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx).parameter_problem.increment();
3286 assert!(!action.should_send_icmp_to_multicast());
3288 let dst_ip = match SpecifiedAddr::new(dst_ip) {
3289 Some(ip) => ip,
3290 None => {
3291 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx)
3292 .unspecified_destination
3293 .increment();
3294 debug!("receive_ipv4_packet: Received packet with unspecified destination IP address; dropping");
3295 return;
3296 }
3297 };
3298 let src_ip = match SpecifiedAddr::new(src_ip) {
3299 Some(ip) => ip,
3300 None => {
3301 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx)
3302 .unspecified_source
3303 .increment();
3304 trace!("receive_ipv4_packet: Cannot send ICMP error in response to packet with unspecified source IP address");
3305 return;
3306 }
3307 };
3308 IcmpErrorHandler::<Ipv4, _>::send_icmp_error_message(
3309 core_ctx,
3310 bindings_ctx,
3311 device,
3312 frame_dst,
3313 src_ip,
3314 dst_ip,
3315 buffer,
3316 Icmpv4Error {
3317 kind: Icmpv4ErrorKind::ParameterProblem {
3318 code,
3319 pointer,
3320 fragment_type: Ipv4FragmentType::InitialFragment,
3323 },
3324 header_len,
3325 },
3326 &device_ip_layer_metadata.marks,
3327 );
3328 return;
3329 }
3330 _ => return, };
3332
3333 if !packet.dst_ip().is_specified() {
3338 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx).unspecified_destination.increment();
3339 debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3340 return;
3341 };
3342
3343 let mut packet = match process_fragment(core_ctx, bindings_ctx, packet) {
3356 ProcessFragmentResult::Done => return,
3357 ProcessFragmentResult::NotNeeded(packet) => packet,
3358 ProcessFragmentResult::Reassembled(buf) => {
3359 let buf = Buf::new(buf, ..);
3360 buffer = packet::Either::B(buf);
3361
3362 match buffer.parse_mut() {
3363 Ok(packet) => packet,
3364 Err(err) => {
3365 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx)
3366 .fragment_reassembly_error
3367 .increment();
3368 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3369 return;
3370 }
3371 }
3372 }
3373 };
3374
3375 let mut packet_metadata =
3378 IpLayerPacketMetadata::from_device_ip_layer_metadata(core_ctx, device_ip_layer_metadata);
3379 let mut filter = core_ctx.filter_handler();
3380 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3381 IngressVerdict::Verdict(filter::Verdict::Accept(())) => {}
3382 IngressVerdict::Verdict(filter::Verdict::Drop) => {
3383 packet_metadata.acknowledge_drop();
3384 return;
3385 }
3386 IngressVerdict::TransparentLocalDelivery { addr, port } => {
3387 drop(filter);
3390
3391 let Some(addr) = SpecifiedAddr::new(addr) else {
3392 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx)
3393 .unspecified_destination
3394 .increment();
3395 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3396 return;
3397 };
3398
3399 let receive_meta = ReceiveIpPacketMeta {
3400 broadcast: None,
3404 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3405 };
3406
3407 dispatch_receive_ipv4_packet(
3411 core_ctx,
3412 bindings_ctx,
3413 device,
3414 frame_dst,
3415 packet,
3416 packet_metadata,
3417 receive_meta,
3418 )
3419 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3420 return;
3421 }
3422 }
3423 drop(filter);
3426
3427 let action = receive_ipv4_packet_action(
3428 core_ctx,
3429 bindings_ctx,
3430 device,
3431 &packet,
3432 frame_dst,
3433 &packet_metadata.marks,
3434 );
3435 match action {
3436 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3437 let src_ip = packet.src_ip();
3438 let mut packet_metadata = Some(packet_metadata);
3445 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3446 clone_packet_for_mcast_forwarding! {
3447 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3448 };
3449 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3450 core_ctx,
3451 copy_of_packet,
3452 packet_metadata.take().unwrap_or_default(),
3453 Some(*min_ttl),
3454 device,
3455 &output_interface,
3456 IpPacketDestination::from_addr(dst_ip),
3457 frame_dst,
3458 src_ip,
3459 dst_ip,
3460 )
3461 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3462 }
3463
3464 if let Some(address_status) = address_status {
3466 let receive_meta = ReceiveIpPacketMeta {
3467 broadcast: address_status.to_broadcast_marker(),
3468 transparent_override: None,
3469 };
3470 dispatch_receive_ipv4_packet(
3471 core_ctx,
3472 bindings_ctx,
3473 device,
3474 frame_dst,
3475 packet,
3476 packet_metadata.take().unwrap_or_default(),
3477 receive_meta,
3478 )
3479 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3480 }
3481 }
3482 ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
3483 match internal_forwarding {
3486 InternalForwarding::Used(outbound_device) => {
3487 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx).forward.increment();
3488 match core_ctx.filter_handler().forwarding_hook(
3489 &mut packet,
3490 device,
3491 &outbound_device,
3492 &mut packet_metadata,
3493 ) {
3494 filter::Verdict::Drop => {
3495 packet_metadata.acknowledge_drop();
3496 return;
3497 }
3498 filter::Verdict::Accept(()) => {}
3499 }
3500 }
3501 InternalForwarding::NotUsed => {}
3502 }
3503
3504 let receive_meta = ReceiveIpPacketMeta {
3505 broadcast: address_status.to_broadcast_marker(),
3506 transparent_override: None,
3507 };
3508 dispatch_receive_ipv4_packet(
3509 core_ctx,
3510 bindings_ctx,
3511 device,
3512 frame_dst,
3513 packet,
3514 packet_metadata,
3515 receive_meta,
3516 )
3517 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3518 }
3519 ReceivePacketAction::Forward {
3520 original_dst,
3521 dst: Destination { device: dst_device, next_hop },
3522 } => {
3523 let src_ip = packet.src_ip();
3524 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3525 core_ctx,
3526 packet,
3527 packet_metadata,
3528 None,
3529 device,
3530 &dst_device,
3531 IpPacketDestination::from_next_hop(next_hop, original_dst),
3532 frame_dst,
3533 src_ip,
3534 original_dst,
3535 )
3536 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3537 }
3538 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3539 use packet_formats::ipv4::Ipv4Header as _;
3540 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx).no_route_to_host.increment();
3541 debug!("received IPv4 packet with no known route to destination {}", dst_ip);
3542 let fragment_type = packet.fragment_type();
3543 let (src_ip, _, proto, meta): (_, Ipv4Addr, _, _) =
3544 drop_packet_and_undo_parse!(packet, buffer);
3545 let marks = packet_metadata.marks;
3546 packet_metadata.acknowledge_drop();
3547 let src_ip = match SpecifiedAddr::new(src_ip) {
3548 Some(ip) => ip,
3549 None => {
3550 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx)
3551 .unspecified_source
3552 .increment();
3553 trace!("receive_ipv4_packet: Cannot send ICMP error in response to packet with unspecified source IP address");
3554 return;
3555 }
3556 };
3557 IcmpErrorHandler::<Ipv4, _>::send_icmp_error_message(
3558 core_ctx,
3559 bindings_ctx,
3560 device,
3561 frame_dst,
3562 src_ip,
3563 dst_ip,
3564 buffer,
3565 Icmpv4Error {
3566 kind: Icmpv4ErrorKind::NetUnreachable { proto, fragment_type },
3567 header_len: meta.header_len(),
3568 },
3569 &marks,
3570 );
3571 }
3572 ReceivePacketAction::Drop { reason } => {
3573 let src_ip = packet.src_ip();
3574 let dst_ip = packet.dst_ip();
3575 packet_metadata.acknowledge_drop();
3576 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx).dropped.increment();
3577 debug!(
3578 "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
3579 {device:?}: {reason:?}",
3580 );
3581 }
3582 }
3583}
3584
3585pub fn receive_ipv6_packet<
3590 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3591 B: BufferMut,
3592 CC: IpLayerIngressContext<Ipv6, BC> + CounterContext<IpCounters<Ipv6>>,
3593>(
3594 core_ctx: &mut CC,
3595 bindings_ctx: &mut BC,
3596 device: &CC::DeviceId,
3597 frame_dst: Option<FrameDestination>,
3598 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3599 buffer: B,
3600) {
3601 if !core_ctx.is_ip_device_enabled(&device) {
3602 return;
3603 }
3604
3605 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3608
3609 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx).receive_ip_packet.increment();
3610 trace!("receive_ipv6_packet({:?})", device);
3611
3612 let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
3613 Ok(packet) => packet,
3614 Err(IpParseError::ParameterProblem {
3620 src_ip,
3621 dst_ip,
3622 code,
3623 pointer,
3624 must_send_icmp,
3625 header_len: _,
3626 action,
3627 }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
3628 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx).parameter_problem.increment();
3629 let dst_ip = match SpecifiedAddr::new(dst_ip) {
3630 Some(ip) => ip,
3631 None => {
3632 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
3633 .unspecified_destination
3634 .increment();
3635 debug!("receive_ipv6_packet: Received packet with unspecified destination IP address; dropping");
3636 return;
3637 }
3638 };
3639 let src_ip = match UnicastAddr::new(src_ip) {
3640 Some(ip) => ip,
3641 None => {
3642 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
3643 .version_rx
3644 .non_unicast_source
3645 .increment();
3646 trace!("receive_ipv6_packet: Cannot send ICMP error in response to packet with non unicast source IP address");
3647 return;
3648 }
3649 };
3650 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3651 core_ctx,
3652 bindings_ctx,
3653 device,
3654 frame_dst,
3655 src_ip,
3656 dst_ip,
3657 buffer,
3658 Icmpv6ErrorKind::ParameterProblem {
3659 code,
3660 pointer,
3661 allow_dst_multicast: action.should_send_icmp_to_multicast(),
3662 },
3663 &device_ip_layer_metadata.marks,
3664 );
3665 return;
3666 }
3667 _ => return, };
3669
3670 trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
3671
3672 if packet.src_ipv6().is_none() {
3678 debug!(
3679 "receive_ipv6_packet: received packet from non-unicast source {}; dropping",
3680 packet.src_ip()
3681 );
3682 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
3683 .version_rx
3684 .non_unicast_source
3685 .increment();
3686 return;
3687 };
3688 if !packet.dst_ip().is_specified() {
3689 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx).unspecified_destination.increment();
3690 debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
3691 return;
3692 };
3693
3694 let (mut packet, delivery_extension_header_action) =
3705 match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
3706 Ipv6PacketAction::_Discard => {
3707 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
3708 .version_rx
3709 .extension_header_discard
3710 .increment();
3711 trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
3712 return;
3713 }
3714 Ipv6PacketAction::Continue => {
3715 trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
3716 (packet, Some(Ipv6PacketAction::Continue))
3717 }
3718 Ipv6PacketAction::ProcessFragment => {
3719 trace!(
3720 "receive_ipv6_packet: handled IPv6 extension headers: handling \
3721 fragmented packet"
3722 );
3723
3724 match process_fragment(core_ctx, bindings_ctx, packet) {
3736 ProcessFragmentResult::Done => return,
3737 ProcessFragmentResult::NotNeeded(packet) => {
3738 (packet, Some(Ipv6PacketAction::Continue))
3753 }
3754 ProcessFragmentResult::Reassembled(buf) => {
3755 let buf = Buf::new(buf, ..);
3756 buffer = packet::Either::B(buf);
3757
3758 match buffer.parse_mut() {
3759 Ok(packet) => (packet, None),
3760 Err(err) => {
3761 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
3762 .fragment_reassembly_error
3763 .increment();
3764 debug!(
3765 "receive_ip_packet: fragmented, failed to reassemble: {:?}",
3766 err
3767 );
3768 return;
3769 }
3770 }
3771 }
3772 }
3773 }
3774 };
3775
3776 let mut packet_metadata =
3777 IpLayerPacketMetadata::from_device_ip_layer_metadata(core_ctx, device_ip_layer_metadata);
3778 let mut filter = core_ctx.filter_handler();
3779
3780 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3781 IngressVerdict::Verdict(filter::Verdict::Accept(())) => {}
3782 IngressVerdict::Verdict(filter::Verdict::Drop) => {
3783 packet_metadata.acknowledge_drop();
3784 return;
3785 }
3786 IngressVerdict::TransparentLocalDelivery { addr, port } => {
3787 drop(filter);
3790
3791 let Some(addr) = SpecifiedAddr::new(addr) else {
3792 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
3793 .unspecified_destination
3794 .increment();
3795 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3796 return;
3797 };
3798
3799 let receive_meta = ReceiveIpPacketMeta {
3800 broadcast: None,
3801 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3802 };
3803
3804 dispatch_receive_ipv6_packet(
3808 core_ctx,
3809 bindings_ctx,
3810 device,
3811 frame_dst,
3812 packet,
3813 packet_metadata,
3814 receive_meta,
3815 )
3816 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3817 return;
3818 }
3819 }
3820 drop(filter);
3823
3824 let Some(src_ip) = packet.src_ipv6() else {
3825 debug!(
3826 "receive_ipv6_packet: received packet from non-unicast source {}; dropping",
3827 packet.src_ip()
3828 );
3829 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
3830 .version_rx
3831 .non_unicast_source
3832 .increment();
3833 return;
3834 };
3835
3836 match receive_ipv6_packet_action(
3837 core_ctx,
3838 bindings_ctx,
3839 device,
3840 &packet,
3841 frame_dst,
3842 &packet_metadata.marks,
3843 ) {
3844 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3845 let mut packet_metadata = Some(packet_metadata);
3852 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3853 clone_packet_for_mcast_forwarding! {
3854 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3855 };
3856 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
3857 core_ctx,
3858 copy_of_packet,
3859 packet_metadata.take().unwrap_or_default(),
3860 Some(*min_ttl),
3861 device,
3862 &output_interface,
3863 IpPacketDestination::from_addr(dst_ip),
3864 frame_dst,
3865 src_ip,
3866 dst_ip,
3867 )
3868 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3869 }
3870
3871 if let Some(_) = address_status {
3873 let receive_meta =
3874 ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
3875
3876 dispatch_receive_ipv6_packet(
3877 core_ctx,
3878 bindings_ctx,
3879 device,
3880 frame_dst,
3881 packet,
3882 packet_metadata.take().unwrap_or_default(),
3883 receive_meta,
3884 )
3885 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3886 }
3887 }
3888 ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
3889 trace!("receive_ipv6_packet: delivering locally");
3890
3891 let action = if let Some(action) = delivery_extension_header_action {
3892 action
3893 } else {
3894 ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
3895 };
3896 match action {
3897 Ipv6PacketAction::_Discard => {
3898 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
3899 .version_rx
3900 .extension_header_discard
3901 .increment();
3902 trace!(
3903 "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
3904 );
3905 packet_metadata.acknowledge_drop();
3906 }
3907 Ipv6PacketAction::Continue => {
3908 trace!(
3909 "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
3910 );
3911
3912 match internal_forwarding {
3915 InternalForwarding::Used(outbound_device) => {
3916 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
3917 .forward
3918 .increment();
3919 match core_ctx.filter_handler().forwarding_hook(
3920 &mut packet,
3921 device,
3922 &outbound_device,
3923 &mut packet_metadata,
3924 ) {
3925 filter::Verdict::Drop => {
3926 packet_metadata.acknowledge_drop();
3927 return;
3928 }
3929 filter::Verdict::Accept(()) => {}
3930 }
3931 }
3932 InternalForwarding::NotUsed => {}
3933 }
3934
3935 let meta = ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
3936
3937 dispatch_receive_ipv6_packet(
3942 core_ctx,
3943 bindings_ctx,
3944 device,
3945 frame_dst,
3946 packet,
3947 packet_metadata,
3948 meta,
3949 )
3950 .unwrap_or_else(|err| {
3951 err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer)
3952 });
3953 }
3954 Ipv6PacketAction::ProcessFragment => {
3955 debug!("receive_ipv6_packet: found fragment header after reassembly; dropping");
3956 packet_metadata.acknowledge_drop();
3957 }
3958 }
3959 }
3960 ReceivePacketAction::Forward {
3961 original_dst,
3962 dst: Destination { device: dst_device, next_hop },
3963 } => {
3964 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
3965 core_ctx,
3966 packet,
3967 packet_metadata,
3968 None,
3969 device,
3970 &dst_device,
3971 IpPacketDestination::from_next_hop(next_hop, original_dst),
3972 frame_dst,
3973 src_ip,
3974 original_dst,
3975 )
3976 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3977 }
3978 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3979 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx).no_route_to_host.increment();
3980 let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
3981 drop_packet_and_undo_parse!(packet, buffer);
3982 debug!("received IPv6 packet with no known route to destination {}", dst_ip);
3983 let marks = packet_metadata.marks;
3984 packet_metadata.acknowledge_drop();
3985
3986 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
3987 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3988 core_ctx,
3989 bindings_ctx,
3990 device,
3991 frame_dst,
3992 *src_ip,
3993 dst_ip,
3994 buffer,
3995 Icmpv6ErrorKind::NetUnreachable { proto, header_len: meta.header_len() },
3996 &marks,
3997 );
3998 }
3999 }
4000 ReceivePacketAction::Drop { reason } => {
4001 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx).dropped.increment();
4002 let src_ip = packet.src_ip();
4003 let dst_ip = packet.dst_ip();
4004 packet_metadata.acknowledge_drop();
4005 debug!(
4006 "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
4007 {device:?}: {reason:?}",
4008 );
4009 }
4010 }
4011}
4012
4013#[derive(Debug, PartialEq)]
4015pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
4016 Deliver {
4018 address_status: I::AddressStatus,
4020 internal_forwarding: InternalForwarding<DeviceId>,
4023 },
4024
4025 Forward {
4027 original_dst: SpecifiedAddr<I::Addr>,
4029 dst: Destination<I::Addr, DeviceId>,
4031 },
4032
4033 MulticastForward {
4041 targets: MulticastRouteTargets<DeviceId>,
4043 address_status: Option<I::AddressStatus>,
4046 dst_ip: SpecifiedAddr<I::Addr>,
4048 },
4049
4050 SendNoRouteToDest {
4056 dst: SpecifiedAddr<I::Addr>,
4058 },
4059
4060 #[allow(missing_docs)]
4064 Drop { reason: DropReason },
4065}
4066
4067#[derive(Debug, PartialEq)]
4069pub enum DropReason {
4070 Tentative,
4072 UnspecifiedDestination,
4074 ForwardUnspecifiedSource,
4076 ForwardingDisabledInboundIface,
4079 MulticastNoInterest,
4085}
4086
4087pub fn receive_ipv4_packet_action<BC, CC, B>(
4089 core_ctx: &mut CC,
4090 bindings_ctx: &mut BC,
4091 device: &CC::DeviceId,
4092 packet: &Ipv4Packet<B>,
4093 frame_dst: Option<FrameDestination>,
4094 marks: &Marks,
4095) -> ReceivePacketAction<Ipv4, CC::DeviceId>
4096where
4097 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
4098 CC: IpLayerContext<Ipv4, BC> + CounterContext<IpCounters<Ipv4>>,
4099 B: SplitByteSlice,
4100{
4101 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4102 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx).unspecified_destination.increment();
4103 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4104 };
4105
4106 let first_status = if device.is_loopback() {
4122 core_ctx.with_address_statuses(dst_ip, |it| it.map(|(_device, status)| status).next())
4123 } else {
4124 core_ctx.address_status_for_device(dst_ip, device).into_present()
4125 };
4126 match first_status {
4127 Some(
4128 address_status @ (Ipv4PresentAddressStatus::Unicast
4129 | Ipv4PresentAddressStatus::LoopbackSubnet),
4130 ) => {
4131 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx).deliver_unicast.increment();
4132 ReceivePacketAction::Deliver {
4133 address_status,
4134 internal_forwarding: InternalForwarding::NotUsed,
4135 }
4136 }
4137 Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4138 receive_ip_multicast_packet_action(
4139 core_ctx,
4140 bindings_ctx,
4141 device,
4142 packet,
4143 Some(address_status),
4144 dst_ip,
4145 frame_dst,
4146 )
4147 }
4148 Some(
4149 address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4150 | Ipv4PresentAddressStatus::SubnetBroadcast),
4151 ) => {
4152 CounterContext::<IpCounters<Ipv4>>::counters(core_ctx)
4153 .version_rx
4154 .deliver_broadcast
4155 .increment();
4156 ReceivePacketAction::Deliver {
4157 address_status,
4158 internal_forwarding: InternalForwarding::NotUsed,
4159 }
4160 }
4161 None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4162 core_ctx,
4163 bindings_ctx,
4164 dst_ip,
4165 device,
4166 packet,
4167 frame_dst,
4168 marks,
4169 ),
4170 }
4171}
4172
4173pub fn receive_ipv6_packet_action<BC, CC, B>(
4175 core_ctx: &mut CC,
4176 bindings_ctx: &mut BC,
4177 device: &CC::DeviceId,
4178 packet: &Ipv6Packet<B>,
4179 frame_dst: Option<FrameDestination>,
4180 marks: &Marks,
4181) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4182where
4183 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4184 CC: IpLayerContext<Ipv6, BC> + CounterContext<IpCounters<Ipv6>>,
4185 B: SplitByteSlice,
4186{
4187 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4188 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx).unspecified_destination.increment();
4189 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4190 };
4191
4192 fn choose_highest_priority(
4211 address_statuses: impl Iterator<Item = Ipv6PresentAddressStatus>,
4212 dst_ip: SpecifiedAddr<Ipv6Addr>,
4213 ) -> Option<Ipv6PresentAddressStatus> {
4214 address_statuses.max_by(|lhs, rhs| {
4215 use Ipv6PresentAddressStatus::*;
4216 match (lhs, rhs) {
4217 (UnicastAssigned | UnicastTentative, Multicast)
4218 | (Multicast, UnicastAssigned | UnicastTentative) => {
4219 unreachable!("the IPv6 address {:?} is not both unicast and multicast", dst_ip)
4220 }
4221 (UnicastAssigned, UnicastTentative) => Ordering::Greater,
4222 (UnicastTentative, UnicastAssigned) => Ordering::Less,
4223 (UnicastTentative, UnicastTentative)
4224 | (UnicastAssigned, UnicastAssigned)
4225 | (Multicast, Multicast) => Ordering::Equal,
4226 }
4227 })
4228 }
4229
4230 let highest_priority = if device.is_loopback() {
4231 core_ctx.with_address_statuses(dst_ip, |it| {
4232 let it = it.map(|(_device, status)| status);
4233 choose_highest_priority(it, dst_ip)
4234 })
4235 } else {
4236 core_ctx.address_status_for_device(dst_ip, device).into_present()
4237 };
4238 match highest_priority {
4239 Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
4240 receive_ip_multicast_packet_action(
4241 core_ctx,
4242 bindings_ctx,
4243 device,
4244 packet,
4245 Some(address_status),
4246 dst_ip,
4247 frame_dst,
4248 )
4249 }
4250 Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
4251 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx).deliver_unicast.increment();
4252 ReceivePacketAction::Deliver {
4253 address_status,
4254 internal_forwarding: InternalForwarding::NotUsed,
4255 }
4256 }
4257 Some(Ipv6PresentAddressStatus::UnicastTentative) => {
4258 CounterContext::<IpCounters<Ipv6>>::counters(core_ctx)
4289 .version_rx
4290 .drop_for_tentative
4291 .increment();
4292 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4293 }
4294 None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
4295 core_ctx,
4296 bindings_ctx,
4297 dst_ip,
4298 device,
4299 packet,
4300 frame_dst,
4301 marks,
4302 ),
4303 }
4304}
4305
4306fn receive_ip_multicast_packet_action<
4309 I: IpLayerIpExt,
4310 B: SplitByteSlice,
4311 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4312 CC: IpLayerContext<I, BC> + CounterContext<IpCounters<I>>,
4313>(
4314 core_ctx: &mut CC,
4315 bindings_ctx: &mut BC,
4316 device: &CC::DeviceId,
4317 packet: &I::Packet<B>,
4318 address_status: Option<I::AddressStatus>,
4319 dst_ip: SpecifiedAddr<I::Addr>,
4320 frame_dst: Option<FrameDestination>,
4321) -> ReceivePacketAction<I, CC::DeviceId> {
4322 let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
4323 core_ctx,
4324 bindings_ctx,
4325 packet,
4326 device,
4327 frame_dst,
4328 );
4329 match (targets, address_status) {
4330 (Some(targets), address_status) => {
4331 if address_status.is_some() {
4332 CounterContext::<IpCounters<I>>::counters(core_ctx).deliver_multicast.increment();
4333 }
4334 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
4335 }
4336 (None, Some(address_status)) => {
4337 CounterContext::<IpCounters<I>>::counters(core_ctx).deliver_multicast.increment();
4340 ReceivePacketAction::Deliver {
4341 address_status,
4342 internal_forwarding: InternalForwarding::NotUsed,
4343 }
4344 }
4345 (None, None) => {
4346 CounterContext::<IpCounters<I>>::counters(core_ctx).multicast_no_interest.increment();
4355 ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
4356 }
4357 }
4358}
4359
4360fn receive_ip_packet_action_common<
4363 I: IpLayerIpExt,
4364 B: SplitByteSlice,
4365 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4366 CC: IpLayerContext<I, BC> + CounterContext<IpCounters<I>>,
4367>(
4368 core_ctx: &mut CC,
4369 bindings_ctx: &mut BC,
4370 dst_ip: SpecifiedAddr<I::Addr>,
4371 device_id: &CC::DeviceId,
4372 packet: &I::Packet<B>,
4373 frame_dst: Option<FrameDestination>,
4374 marks: &Marks,
4375) -> ReceivePacketAction<I, CC::DeviceId> {
4376 if dst_ip.is_multicast() {
4377 return receive_ip_multicast_packet_action(
4378 core_ctx,
4379 bindings_ctx,
4380 device_id,
4381 packet,
4382 None,
4383 dst_ip,
4384 frame_dst,
4385 );
4386 }
4387
4388 if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
4390 CounterContext::<IpCounters<I>>::counters(core_ctx).forwarding_disabled.increment();
4403 return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
4404 }
4405 let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
4412 return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
4413 };
4414
4415 if let Some(dst_ip) = NonMappedAddr::new(dst_ip).and_then(NonMulticastAddr::new) {
4422 if let Some((outbound_device, address_status)) =
4423 get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
4424 {
4425 return ReceivePacketAction::Deliver {
4426 address_status,
4427 internal_forwarding: InternalForwarding::Used(outbound_device),
4428 };
4429 }
4430 }
4431
4432 match lookup_route_table(
4433 core_ctx,
4434 *dst_ip,
4435 RuleInput {
4436 packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
4437 marks,
4438 },
4439 ) {
4440 Some(dst) => {
4441 CounterContext::<IpCounters<I>>::counters(core_ctx).forward.increment();
4442 ReceivePacketAction::Forward { original_dst: dst_ip, dst }
4443 }
4444 None => {
4445 CounterContext::<IpCounters<I>>::counters(core_ctx).no_route_to_host.increment();
4446 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
4447 }
4448 }
4449}
4450
4451fn lookup_route_table<I: IpLayerIpExt, CC: IpStateContext<I>>(
4453 core_ctx: &mut CC,
4454 dst_ip: I::Addr,
4455 rule_input: RuleInput<'_, I, CC::DeviceId>,
4456) -> Option<Destination<I::Addr, CC::DeviceId>> {
4457 let bound_device = match rule_input.packet_origin {
4458 PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
4459 PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
4460 };
4461 core_ctx.with_rules_table(|core_ctx, rules| {
4462 match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
4463 match table.lookup(core_ctx, bound_device, dst_ip) {
4464 Some(dst) => ControlFlow::Break(Some(dst)),
4465 None => ControlFlow::Continue(()),
4466 }
4467 }) {
4468 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
4469 inner: dst,
4470 observed_source_address_matcher: _,
4471 })) => dst,
4472 ControlFlow::Break(RuleAction::Unreachable) => None,
4473 ControlFlow::Continue(RuleWalkInfo {
4474 inner: (),
4475 observed_source_address_matcher: _,
4476 }) => None,
4477 }
4478 })
4479}
4480
4481#[derive(Debug, Derivative, Clone)]
4483#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
4484pub enum IpPacketDestination<I: BroadcastIpExt, D> {
4485 Broadcast(I::BroadcastMarker),
4487
4488 Multicast(MulticastAddr<I::Addr>),
4490
4491 Neighbor(SpecifiedAddr<I::Addr>),
4494
4495 Loopback(D),
4498}
4499
4500impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
4501 pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
4503 match MulticastAddr::new(addr.into_addr()) {
4504 Some(mc_addr) => Self::Multicast(mc_addr),
4505 None => Self::Neighbor(addr),
4506 }
4507 }
4508
4509 pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
4511 match next_hop {
4512 NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
4513 NextHop::Gateway(gateway) => Self::Neighbor(gateway),
4514 NextHop::Broadcast(marker) => Self::Broadcast(marker),
4515 }
4516 }
4517}
4518
4519#[derive(Debug, Clone)]
4521pub struct SendIpPacketMeta<I: IpExt, D, Src> {
4522 pub device: D,
4524
4525 pub src_ip: Src,
4527
4528 pub dst_ip: SpecifiedAddr<I::Addr>,
4530
4531 pub destination: IpPacketDestination<I, D>,
4533
4534 pub proto: I::Proto,
4536
4537 pub ttl: Option<NonZeroU8>,
4541
4542 pub mtu: Mtu,
4547
4548 pub dscp_and_ecn: DscpAndEcn,
4550}
4551
4552impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4553 for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
4554{
4555 fn from(
4556 SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
4557 I,
4558 D,
4559 SpecifiedAddr<I::Addr>,
4560 >,
4561 ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
4562 SendIpPacketMeta {
4563 device,
4564 src_ip: Some(src_ip),
4565 dst_ip,
4566 destination,
4567 proto,
4568 ttl,
4569 mtu,
4570 dscp_and_ecn,
4571 }
4572 }
4573}
4574
4575pub trait IpLayerHandler<I: IpExt + FragmentationIpExt, BC>: DeviceIdContext<AnyDevice> {
4581 fn send_ip_packet_from_device<S>(
4584 &mut self,
4585 bindings_ctx: &mut BC,
4586 meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4587 body: S,
4588 ) -> Result<(), IpSendFrameError<S>>
4589 where
4590 S: TransportPacketSerializer<I>,
4591 S::Buffer: BufferMut;
4592
4593 fn send_ip_frame<S>(
4600 &mut self,
4601 bindings_ctx: &mut BC,
4602 device: &Self::DeviceId,
4603 destination: IpPacketDestination<I, &Self::DeviceId>,
4604 body: S,
4605 ) -> Result<(), IpSendFrameError<S>>
4606 where
4607 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>;
4608}
4609
4610impl<
4611 I: IpLayerIpExt,
4612 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
4613 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4614 > IpLayerHandler<I, BC> for CC
4615{
4616 fn send_ip_packet_from_device<S>(
4617 &mut self,
4618 bindings_ctx: &mut BC,
4619 meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4620 body: S,
4621 ) -> Result<(), IpSendFrameError<S>>
4622 where
4623 S: TransportPacketSerializer<I>,
4624 S::Buffer: BufferMut,
4625 {
4626 send_ip_packet_from_device(self, bindings_ctx, meta, body, IpLayerPacketMetadata::default())
4627 }
4628
4629 fn send_ip_frame<S>(
4630 &mut self,
4631 bindings_ctx: &mut BC,
4632 device: &Self::DeviceId,
4633 destination: IpPacketDestination<I, &Self::DeviceId>,
4634 body: S,
4635 ) -> Result<(), IpSendFrameError<S>>
4636 where
4637 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>,
4638 {
4639 send_ip_frame(
4640 self,
4641 bindings_ctx,
4642 device,
4643 destination,
4644 body,
4645 IpLayerPacketMetadata::default(),
4646 Mtu::no_limit(),
4647 )
4648 }
4649}
4650
4651pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
4658 core_ctx: &mut CC,
4659 bindings_ctx: &mut BC,
4660 meta: SendIpPacketMeta<
4661 I,
4662 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
4663 Option<SpecifiedAddr<I::Addr>>,
4664 >,
4665 body: S,
4666 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
4667) -> Result<(), IpSendFrameError<S>>
4668where
4669 I: IpLayerIpExt,
4670 BC: FilterBindingsContext + TxMetadataBindingsTypes,
4671 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4672 S: TransportPacketSerializer<I>,
4673 S::Buffer: BufferMut,
4674{
4675 let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
4676 meta;
4677 let next_packet_id = gen_ip_packet_id(core_ctx);
4678 let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
4679 let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
4680 let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
4681
4682 #[derive(GenericOverIp)]
4683 #[generic_over_ip(I, Ip)]
4684 struct Wrap<'a, I: IpLayerIpExt> {
4685 builder: &'a mut I::PacketBuilder,
4686 next_packet_id: I::PacketId,
4687 }
4688
4689 I::map_ip::<_, ()>(
4690 Wrap { builder: &mut builder, next_packet_id },
4691 |Wrap { builder, next_packet_id }| {
4692 builder.id(next_packet_id);
4693 },
4694 |Wrap { builder: _, next_packet_id: () }| {
4695 },
4697 );
4698
4699 builder.set_dscp_and_ecn(dscp_and_ecn);
4700
4701 let ip_frame = body.encapsulate(builder);
4702 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
4703 .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
4704}
4705
4706pub trait FilterHandlerProvider<I: packet_formats::ip::IpExt, BT: FilterBindingsTypes>:
4708 IpDeviceAddressIdContext<I, DeviceId: filter::InterfaceProperties<BT::DeviceClass>>
4709{
4710 type Handler<'a>: filter::FilterHandler<
4712 I,
4713 BT,
4714 DeviceId = Self::DeviceId,
4715 WeakAddressId = Self::WeakAddressId,
4716 >
4717 where
4718 Self: 'a;
4719
4720 fn filter_handler(&mut self) -> Self::Handler<'_>;
4722}
4723
4724#[cfg(any(test, feature = "testutils"))]
4725pub(crate) mod testutil {
4726 use super::*;
4727
4728 use netstack3_base::testutil::{FakeCoreCtx, FakeStrongDeviceId};
4729 use netstack3_base::{AssignedAddrIpExt, SendFrameContext, SendFrameError, SendableFrameMeta};
4730 use packet::Serializer;
4731
4732 #[derive(Debug, GenericOverIp)]
4734 #[generic_over_ip()]
4735 #[allow(missing_docs)]
4736 pub enum DualStackSendIpPacketMeta<D> {
4737 V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
4738 V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
4739 }
4740
4741 impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4742 for DualStackSendIpPacketMeta<D>
4743 {
4744 fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
4745 #[derive(GenericOverIp)]
4746 #[generic_over_ip(I, Ip)]
4747 struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
4748 use DualStackSendIpPacketMeta::*;
4749 I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
4750 }
4751 }
4752
4753 impl<I: IpExt, S, DeviceId, BC>
4754 SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
4755 for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
4756 {
4757 fn send_meta<SS>(
4758 self,
4759 core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
4760 bindings_ctx: &mut BC,
4761 frame: SS,
4762 ) -> Result<(), SendFrameError<SS>>
4763 where
4764 SS: Serializer,
4765 SS::Buffer: BufferMut,
4766 {
4767 SendFrameContext::send_frame(
4768 &mut core_ctx.frames,
4769 bindings_ctx,
4770 DualStackSendIpPacketMeta::from(self),
4771 frame,
4772 )
4773 }
4774 }
4775
4776 #[derive(Debug)]
4778 pub struct WrongIpVersion;
4779
4780 impl<D> DualStackSendIpPacketMeta<D> {
4781 pub fn try_as<I: IpExt>(
4784 &self,
4785 ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
4786 #[derive(GenericOverIp)]
4787 #[generic_over_ip(I, Ip)]
4788 struct Wrap<'a, I: IpExt, D>(
4789 Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
4790 );
4791 use DualStackSendIpPacketMeta::*;
4792 let Wrap(dual_stack) = I::map_ip(
4793 self,
4794 |value| {
4795 Wrap(match value {
4796 V4(meta) => Some(meta),
4797 V6(_) => None,
4798 })
4799 },
4800 |value| {
4801 Wrap(match value {
4802 V4(_) => None,
4803 V6(meta) => Some(meta),
4804 })
4805 },
4806 );
4807 dual_stack.ok_or(WrongIpVersion)
4808 }
4809 }
4810
4811 impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
4812 where
4813 I: packet_formats::ip::IpExt + AssignedAddrIpExt,
4814 BC: FilterBindingsContext,
4815 DeviceId: FakeStrongDeviceId + filter::InterfaceProperties<BC::DeviceClass>,
4816 {
4817 type Handler<'a>
4818 = filter::testutil::NoopImpl<DeviceId>
4819 where
4820 Self: 'a;
4821
4822 fn filter_handler(&mut self) -> Self::Handler<'_> {
4823 filter::testutil::NoopImpl::default()
4824 }
4825 }
4826}