1use alloc::boxed::Box;
6use alloc::vec::Vec;
7use core::convert::Infallible as Never;
8use core::fmt::Debug;
9use core::hash::Hash;
10use core::marker::PhantomData;
11use core::num::NonZeroU8;
12use core::ops::ControlFlow;
13#[cfg(test)]
14use core::ops::DerefMut;
15use core::sync::atomic::{self, AtomicU16};
16
17use derivative::Derivative;
18use explicit::ResultExt as _;
19use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
20use log::{debug, error, trace};
21use net_types::ip::{
22 GenericOverIp, Ip, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu, Subnet,
23};
24use net_types::{
25 LinkLocalAddress, MulticastAddr, MulticastAddress, NonMappedAddr, NonMulticastAddr,
26 SpecifiedAddr, SpecifiedAddress as _, Witness,
27};
28use netstack3_base::socket::SocketIpAddrExt as _;
29use netstack3_base::sync::{Mutex, PrimaryRc, RwLock, StrongRc, WeakRc};
30use netstack3_base::{
31 AnyDevice, BroadcastIpExt, CoreTimerContext, Counter, CounterCollectionSpec, CounterContext,
32 DeviceIdContext, DeviceIdentifier as _, DeviceWithName, ErrorAndSerializer, EventContext,
33 FrameDestination, HandleableTimer, InstantContext, IpAddressId, IpDeviceAddr,
34 IpDeviceAddressIdContext, IpExt, MarkDomain, Marks, Matcher as _, NestedIntoCoreTimerCtx,
35 NotFoundError, ResourceCounterContext, RngContext, SendFrameErrorReason,
36 StrongDeviceIdentifier, TimerBindingsTypes, TimerContext, TimerHandler,
37 TxMetadataBindingsTypes, WeakIpAddressId, WrapBroadcastMarker,
38};
39use netstack3_filter::{
40 self as filter, ConnectionDirection, ConntrackConnection, FilterBindingsContext,
41 FilterBindingsTypes, FilterHandler as _, FilterIpContext, FilterIpExt, FilterIpMetadata,
42 FilterMarkMetadata, FilterTimerId, ForwardedPacket, IngressVerdict, IpPacket, MarkAction,
43 TransportPacketSerializer, Tuple, WeakConnectionError, WeakConntrackConnection,
44};
45use netstack3_hashmap::HashMap;
46use packet::{
47 Buf, BufferMut, GrowBuffer, LayoutBufferAlloc, PacketBuilder as _, PacketConstraints,
48 ParseBufferMut, ParseMetadata, SerializeError, Serializer as _,
49};
50use packet_formats::error::IpParseError;
51use packet_formats::ip::{DscpAndEcn, IpPacket as _, IpPacketBuilder as _};
52use packet_formats::ipv4::{Ipv4FragmentType, Ipv4Packet};
53use packet_formats::ipv6::Ipv6Packet;
54use thiserror::Error;
55use zerocopy::SplitByteSlice;
56
57use crate::internal::counters::{IpCounters, IpCountersIpExt};
58use crate::internal::device::opaque_iid::IidSecret;
59use crate::internal::device::slaac::SlaacCounters;
60use crate::internal::device::state::{
61 IpAddressData, IpAddressFlags, IpDeviceStateBindingsTypes, IpDeviceStateIpExt, WeakAddressId,
62};
63use crate::internal::device::{
64 self, IpDeviceAddressContext, IpDeviceBindingsContext, IpDeviceIpExt, IpDeviceSendContext,
65};
66use crate::internal::fragmentation::{FragmentableIpSerializer, FragmentationIpExt, IpFragmenter};
67use crate::internal::gmp::GmpQueryHandler;
68use crate::internal::gmp::igmp::IgmpCounters;
69use crate::internal::gmp::mld::MldCounters;
70use crate::internal::icmp::{
71 IcmpBindingsTypes, IcmpErrorHandler, IcmpHandlerIpExt, Icmpv4Error, Icmpv4ErrorKind,
72 Icmpv4State, Icmpv4StateBuilder, Icmpv6ErrorKind, Icmpv6State, Icmpv6StateBuilder,
73};
74use crate::internal::ipv6::Ipv6PacketAction;
75use crate::internal::local_delivery::{
76 IpHeaderInfo, Ipv4HeaderInfo, Ipv6HeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta,
77 TransparentLocalDelivery,
78};
79use crate::internal::multicast_forwarding::counters::MulticastForwardingCounters;
80use crate::internal::multicast_forwarding::route::{
81 MulticastRouteIpExt, MulticastRouteTarget, MulticastRouteTargets,
82};
83use crate::internal::multicast_forwarding::state::{
84 MulticastForwardingState, MulticastForwardingStateContext,
85};
86use crate::internal::multicast_forwarding::{
87 MulticastForwardingBindingsTypes, MulticastForwardingDeviceContext, MulticastForwardingEvent,
88 MulticastForwardingTimerId,
89};
90use crate::internal::path_mtu::{PmtuBindingsTypes, PmtuCache, PmtuTimerId};
91use crate::internal::raw::counters::RawIpSocketCounters;
92use crate::internal::raw::{RawIpSocketHandler, RawIpSocketMap, RawIpSocketsBindingsTypes};
93use crate::internal::reassembly::{
94 FragmentBindingsTypes, FragmentHandler, FragmentProcessingState, FragmentTimerId,
95 FragmentablePacket, IpPacketFragmentCache, ReassemblyIpExt,
96};
97use crate::internal::routing::rules::{Rule, RuleAction, RuleInput, RulesTable};
98use crate::internal::routing::{
99 IpRoutingDeviceContext, NonLocalSrcAddrPolicy, PacketOrigin, RoutingTable,
100};
101use crate::internal::socket::{IpSocketBindingsContext, IpSocketContext, IpSocketHandler};
102use crate::internal::types::{
103 self, Destination, InternalForwarding, NextHop, ResolvedRoute, RoutableIpAddr,
104};
105use crate::internal::{ipv6, multicast_forwarding};
106
107#[cfg(test)]
108mod tests;
109
110pub const DEFAULT_TTL: NonZeroU8 = NonZeroU8::new(64).unwrap();
112
113#[derive(Copy, Clone, Debug, Eq, PartialEq)]
115#[allow(missing_docs)]
116pub struct HopLimits {
117 pub unicast: NonZeroU8,
118 pub multicast: NonZeroU8,
119}
120
121pub const DEFAULT_HOP_LIMITS: HopLimits =
123 HopLimits { unicast: DEFAULT_TTL, multicast: NonZeroU8::new(1).unwrap() };
124
125pub const IPV6_DEFAULT_SUBNET: Subnet<Ipv6Addr> =
128 unsafe { Subnet::new_unchecked(Ipv6::UNSPECIFIED_ADDRESS, 0) };
129
130#[derive(Debug)]
132#[allow(missing_docs)]
133pub enum TransportReceiveError {
134 ProtocolUnsupported,
135 PortUnreachable,
136}
137
138impl TransportReceiveError {
139 fn into_icmpv4_error(self, header_len: usize) -> Icmpv4Error {
140 let kind = match self {
141 TransportReceiveError::ProtocolUnsupported => Icmpv4ErrorKind::ProtocolUnreachable,
142 TransportReceiveError::PortUnreachable => Icmpv4ErrorKind::PortUnreachable,
143 };
144 Icmpv4Error { kind, header_len }
145 }
146
147 fn into_icmpv6_error(self, header_len: usize) -> Icmpv6ErrorKind {
148 match self {
149 TransportReceiveError::ProtocolUnsupported => {
150 Icmpv6ErrorKind::ProtocolUnreachable { header_len }
151 }
152 TransportReceiveError::PortUnreachable => Icmpv6ErrorKind::PortUnreachable,
153 }
154 }
155}
156
157#[derive(Derivative)]
163#[derivative(Default(bound = ""))]
164pub struct IpLayerPacketMetadata<
165 I: packet_formats::ip::IpExt,
166 A,
167 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
168> {
169 conntrack_connection_and_direction:
170 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
171 tx_metadata: BT::TxMetadata,
176 marks: Marks,
178 #[cfg(debug_assertions)]
179 drop_check: IpLayerPacketMetadataDropCheck,
180}
181
182#[cfg(debug_assertions)]
189#[derive(Default)]
190struct IpLayerPacketMetadataDropCheck {
191 okay_to_drop: bool,
192}
193
194#[derive(Derivative)]
197#[derivative(Debug(bound = ""), Default(bound = ""))]
198pub struct DeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
199 conntrack_entry: Option<(WeakConntrackConnection, ConnectionDirection)>,
207 tx_metadata: BT::TxMetadata,
212 marks: Marks,
219}
220
221impl<BT: TxMetadataBindingsTypes> DeviceIpLayerMetadata<BT> {
222 pub fn into_tx_metadata(self) -> BT::TxMetadata {
225 self.tx_metadata
226 }
227 #[cfg(any(test, feature = "testutils"))]
229 pub fn with_marks(marks: Marks) -> Self {
230 Self { conntrack_entry: None, tx_metadata: Default::default(), marks }
231 }
232}
233
234impl<
235 I: IpLayerIpExt,
236 A: WeakIpAddressId<I::Addr>,
237 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
238> IpLayerPacketMetadata<I, A, BT>
239{
240 fn from_device_ip_layer_metadata<CC, D>(
241 core_ctx: &mut CC,
242 device: &D,
243 DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks }: DeviceIpLayerMetadata<BT>,
244 ) -> Self
245 where
246 CC: ResourceCounterContext<D, IpCounters<I>>,
247 {
248 let conntrack_connection_and_direction = match conntrack_entry
249 .map(|(conn, dir)| conn.into_inner().map(|conn| (conn, dir)))
250 .transpose()
251 {
252 Ok(conn_and_dir) => conn_and_dir,
255 Err(WeakConnectionError::EntryRemoved) => None,
257 Err(WeakConnectionError::InvalidEntry) => {
261 core_ctx.increment_both(device, |c| &c.invalid_cached_conntrack_entry);
262 None
263 }
264 };
265 Self {
266 conntrack_connection_and_direction,
267 tx_metadata,
268 marks,
269 #[cfg(debug_assertions)]
270 drop_check: Default::default(),
271 }
272 }
273}
274
275impl<I: IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
276 IpLayerPacketMetadata<I, A, BT>
277{
278 pub(crate) fn from_tx_metadata_and_marks(tx_metadata: BT::TxMetadata, marks: Marks) -> Self {
279 Self {
280 conntrack_connection_and_direction: None,
281 tx_metadata,
282 marks,
283 #[cfg(debug_assertions)]
284 drop_check: Default::default(),
285 }
286 }
287
288 pub(crate) fn into_parts(
289 self,
290 ) -> (Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>, BT::TxMetadata, Marks) {
291 let Self {
292 tx_metadata,
293 marks,
294 conntrack_connection_and_direction,
295 #[cfg(debug_assertions)]
296 mut drop_check,
297 } = self;
298 #[cfg(debug_assertions)]
299 {
300 drop_check.okay_to_drop = true;
301 }
302 (conntrack_connection_and_direction, tx_metadata, marks)
303 }
304
305 pub(crate) fn acknowledge_drop(self) {
310 #[cfg(debug_assertions)]
311 {
312 let mut this = self;
313 this.drop_check.okay_to_drop = true;
314 }
315 }
316
317 pub(crate) fn tx_metadata(&self) -> &BT::TxMetadata {
319 &self.tx_metadata
320 }
321
322 pub(crate) fn marks(&self) -> &Marks {
324 &self.marks
325 }
326}
327
328#[cfg(debug_assertions)]
329impl Drop for IpLayerPacketMetadataDropCheck {
330 fn drop(&mut self) {
331 if !self.okay_to_drop {
332 panic!(
333 "IpLayerPacketMetadata dropped without acknowledgement. https://fxbug.dev/334127474"
334 );
335 }
336 }
337}
338
339impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
340 FilterIpMetadata<I, A, BT> for IpLayerPacketMetadata<I, A, BT>
341{
342 fn take_connection_and_direction(
343 &mut self,
344 ) -> Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)> {
345 self.conntrack_connection_and_direction.take()
346 }
347
348 fn replace_connection_and_direction(
349 &mut self,
350 conn: ConntrackConnection<I, A, BT>,
351 direction: ConnectionDirection,
352 ) -> Option<ConntrackConnection<I, A, BT>> {
353 self.conntrack_connection_and_direction.replace((conn, direction)).map(|(conn, _dir)| conn)
354 }
355}
356
357impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
358 FilterMarkMetadata for IpLayerPacketMetadata<I, A, BT>
359{
360 fn apply_mark_action(&mut self, domain: MarkDomain, action: MarkAction) {
361 action.apply(self.marks.get_mut(domain))
362 }
363}
364
365pub type IpSendFrameError<S> = ErrorAndSerializer<IpSendFrameErrorReason, S>;
367
368#[derive(Debug, PartialEq)]
370pub enum IpSendFrameErrorReason {
371 Device(SendFrameErrorReason),
373 IllegalLoopbackAddress,
376}
377
378impl From<SendFrameErrorReason> for IpSendFrameErrorReason {
379 fn from(value: SendFrameErrorReason) -> Self {
380 Self::Device(value)
381 }
382}
383
384pub trait IpTransportContext<I: IpExt, BC, CC: DeviceIdContext<AnyDevice> + ?Sized> {
390 fn receive_icmp_error(
404 core_ctx: &mut CC,
405 bindings_ctx: &mut BC,
406 device: &CC::DeviceId,
407 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
408 original_dst_ip: SpecifiedAddr<I::Addr>,
409 original_body: &[u8],
410 err: I::ErrorCode,
411 );
412
413 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
419 core_ctx: &mut CC,
420 bindings_ctx: &mut BC,
421 device: &CC::DeviceId,
422 src_ip: I::RecvSrcAddr,
423 dst_ip: SpecifiedAddr<I::Addr>,
424 buffer: B,
425 info: &LocalDeliveryPacketInfo<I, H>,
426 ) -> Result<(), (B, TransportReceiveError)>;
427}
428
429impl<I: IpExt, BC, CC: DeviceIdContext<AnyDevice> + ?Sized> IpTransportContext<I, BC, CC> for () {
430 fn receive_icmp_error(
431 _core_ctx: &mut CC,
432 _bindings_ctx: &mut BC,
433 _device: &CC::DeviceId,
434 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
435 _original_dst_ip: SpecifiedAddr<I::Addr>,
436 _original_body: &[u8],
437 err: I::ErrorCode,
438 ) {
439 trace!(
440 "IpTransportContext::receive_icmp_error: Received ICMP error message ({:?}) for unsupported IP protocol",
441 err
442 );
443 }
444
445 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
446 _core_ctx: &mut CC,
447 _bindings_ctx: &mut BC,
448 _device: &CC::DeviceId,
449 _src_ip: I::RecvSrcAddr,
450 _dst_ip: SpecifiedAddr<I::Addr>,
451 buffer: B,
452 _info: &LocalDeliveryPacketInfo<I, H>,
453 ) -> Result<(), (B, TransportReceiveError)> {
454 Err((buffer, TransportReceiveError::ProtocolUnsupported))
455 }
456}
457
458pub trait BaseTransportIpContext<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
461 type DevicesWithAddrIter<'s>: Iterator<Item = Self::DeviceId>;
464
465 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
471 &mut self,
472 addr: SpecifiedAddr<I::Addr>,
473 cb: F,
474 ) -> O;
475
476 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits;
481
482 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)>;
486}
487
488pub trait TransportIpContext<I: IpExt + FilterIpExt, BC: TxMetadataBindingsTypes>:
491 BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>
492{
493}
494
495impl<I, CC, BC> TransportIpContext<I, BC> for CC
496where
497 I: IpExt + FilterIpExt,
498 CC: BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>,
499 BC: TxMetadataBindingsTypes,
500{
501}
502
503pub trait MulticastMembershipHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
505 fn join_multicast_group(
512 &mut self,
513 bindings_ctx: &mut BC,
514 device: &Self::DeviceId,
515 addr: MulticastAddr<I::Addr>,
516 );
517
518 fn leave_multicast_group(
526 &mut self,
527 bindings_ctx: &mut BC,
528 device: &Self::DeviceId,
529 addr: MulticastAddr<I::Addr>,
530 );
531
532 fn select_device_for_multicast_group(
537 &mut self,
538 addr: MulticastAddr<I::Addr>,
539 marks: &Marks,
540 ) -> Result<Self::DeviceId, ResolveRouteError>;
541}
542
543pub trait UseTransportIpContextBlanket {}
555
556pub struct AssignedAddressDeviceIterator<Iter, I, D>(Iter, PhantomData<(I, D)>);
559
560impl<Iter, I, D> Iterator for AssignedAddressDeviceIterator<Iter, I, D>
561where
562 Iter: Iterator<Item = (D, I::AddressStatus)>,
563 I: IpLayerIpExt,
564{
565 type Item = D;
566 fn next(&mut self) -> Option<D> {
567 let Self(iter, PhantomData) = self;
568 iter.by_ref().find_map(|(device, state)| is_unicast_assigned::<I>(&state).then_some(device))
569 }
570}
571
572impl<
573 I: IpLayerIpExt,
574 BC: FilterBindingsContext + TxMetadataBindingsTypes,
575 CC: IpDeviceContext<I>
576 + IpSocketHandler<I, BC>
577 + IpStateContext<I>
578 + FilterIpContext<I, BC>
579 + UseTransportIpContextBlanket,
580> BaseTransportIpContext<I, BC> for CC
581{
582 type DevicesWithAddrIter<'s> =
583 AssignedAddressDeviceIterator<CC::DeviceAndAddressStatusIter<'s>, I, CC::DeviceId>;
584
585 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
586 &mut self,
587 addr: SpecifiedAddr<I::Addr>,
588 cb: F,
589 ) -> O {
590 self.with_address_statuses(addr, |it| cb(AssignedAddressDeviceIterator(it, PhantomData)))
591 }
592
593 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
594 match device {
595 Some(device) => HopLimits {
596 unicast: IpDeviceEgressStateContext::<I>::get_hop_limit(self, device),
597 ..DEFAULT_HOP_LIMITS
598 },
599 None => DEFAULT_HOP_LIMITS,
600 }
601 }
602
603 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)> {
604 self.with_filter_state(|state| {
605 let conn = state.conntrack.get_connection(&tuple)?;
606
607 if !conn.destination_nat() {
608 return None;
609 }
610
611 let original = conn.original_tuple();
615 Some((original.dst_addr, original.dst_port_or_id))
616 })
617 }
618}
619
620#[derive(Debug, PartialEq)]
622#[allow(missing_docs)]
623pub enum AddressStatus<S> {
624 Present(S),
625 Unassigned,
626}
627
628impl<S> AddressStatus<S> {
629 fn into_present(self) -> Option<S> {
630 match self {
631 Self::Present(s) => Some(s),
632 Self::Unassigned => None,
633 }
634 }
635}
636
637impl AddressStatus<Ipv4PresentAddressStatus> {
638 pub fn from_context_addr_v4<
640 BC: IpDeviceStateBindingsTypes,
641 CC: device::IpDeviceStateContext<Ipv4, BC> + GmpQueryHandler<Ipv4, BC>,
642 >(
643 core_ctx: &mut CC,
644 device: &CC::DeviceId,
645 addr: SpecifiedAddr<Ipv4Addr>,
646 ) -> AddressStatus<Ipv4PresentAddressStatus> {
647 if addr.is_limited_broadcast() {
648 return AddressStatus::Present(Ipv4PresentAddressStatus::LimitedBroadcast);
649 }
650
651 if MulticastAddr::new(addr.get())
652 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
653 {
654 return AddressStatus::Present(Ipv4PresentAddressStatus::Multicast);
655 }
656
657 core_ctx.with_address_ids(device, |mut addrs, core_ctx| {
658 addrs
659 .find_map(|addr_id| {
660 let dev_addr = addr_id.addr_sub();
661 let (dev_addr, subnet) = dev_addr.addr_subnet();
662
663 if **dev_addr == addr {
664 let assigned = core_ctx.with_ip_address_data(
665 device,
666 &addr_id,
667 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| {
668 *assigned
669 },
670 );
671
672 if assigned {
673 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastAssigned))
674 } else {
675 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastTentative))
676 }
677 } else if addr.get() == subnet.broadcast() {
678 Some(AddressStatus::Present(Ipv4PresentAddressStatus::SubnetBroadcast))
679 } else if device.is_loopback() && subnet.contains(addr.as_ref()) {
680 Some(AddressStatus::Present(Ipv4PresentAddressStatus::LoopbackSubnet))
681 } else {
682 None
683 }
684 })
685 .unwrap_or(AddressStatus::Unassigned)
686 })
687 }
688}
689
690impl AddressStatus<Ipv6PresentAddressStatus> {
691 pub fn from_context_addr_v6<
693 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
694 CC: device::Ipv6DeviceContext<BC> + GmpQueryHandler<Ipv6, BC>,
695 >(
696 core_ctx: &mut CC,
697 device: &CC::DeviceId,
698 addr: SpecifiedAddr<Ipv6Addr>,
699 ) -> AddressStatus<Ipv6PresentAddressStatus> {
700 if MulticastAddr::new(addr.get())
701 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
702 {
703 return AddressStatus::Present(Ipv6PresentAddressStatus::Multicast);
704 }
705
706 let addr_id = match core_ctx.get_address_id(device, addr) {
707 Ok(o) => o,
708 Err(NotFoundError) => return AddressStatus::Unassigned,
709 };
710
711 let assigned = core_ctx.with_ip_address_data(
712 device,
713 &addr_id,
714 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
715 );
716
717 if assigned {
718 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned)
719 } else {
720 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastTentative)
721 }
722 }
723}
724
725impl<S: GenericOverIp<I>, I: Ip> GenericOverIp<I> for AddressStatus<S> {
726 type Type = AddressStatus<S::Type>;
727}
728
729#[derive(Debug, PartialEq)]
731#[allow(missing_docs)]
732pub enum Ipv4PresentAddressStatus {
733 LimitedBroadcast,
734 SubnetBroadcast,
735 Multicast,
736 UnicastAssigned,
737 UnicastTentative,
738 LoopbackSubnet,
749}
750
751impl Ipv4PresentAddressStatus {
752 fn to_broadcast_marker(&self) -> Option<<Ipv4 as BroadcastIpExt>::BroadcastMarker> {
753 match self {
754 Self::LimitedBroadcast | Self::SubnetBroadcast => Some(()),
755 Self::Multicast
756 | Self::UnicastAssigned
757 | Self::UnicastTentative
758 | Self::LoopbackSubnet => None,
759 }
760 }
761}
762
763#[derive(Debug, PartialEq)]
765#[allow(missing_docs)]
766pub enum Ipv6PresentAddressStatus {
767 Multicast,
768 UnicastAssigned,
769 UnicastTentative,
770}
771
772pub trait IpLayerIpExt:
774 IpExt
775 + MulticastRouteIpExt
776 + IcmpHandlerIpExt
777 + FilterIpExt
778 + FragmentationIpExt
779 + IpDeviceIpExt
780 + IpCountersIpExt
781 + ReassemblyIpExt
782{
783 type AddressStatus: Debug;
785 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>: AsRef<
787 IpStateInner<Self, StrongDeviceId, BT>,
788 >;
789 type PacketIdState;
791 type PacketId;
793 fn next_packet_id_from_state(state: &Self::PacketIdState) -> Self::PacketId;
795}
796
797impl IpLayerIpExt for Ipv4 {
798 type AddressStatus = Ipv4PresentAddressStatus;
799 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
800 Ipv4State<StrongDeviceId, BT>;
801 type PacketIdState = AtomicU16;
802 type PacketId = u16;
803 fn next_packet_id_from_state(next_packet_id: &Self::PacketIdState) -> Self::PacketId {
804 next_packet_id.fetch_add(1, atomic::Ordering::Relaxed)
808 }
809}
810
811impl IpLayerIpExt for Ipv6 {
812 type AddressStatus = Ipv6PresentAddressStatus;
813 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
814 Ipv6State<StrongDeviceId, BT>;
815 type PacketIdState = ();
816 type PacketId = ();
817 fn next_packet_id_from_state((): &Self::PacketIdState) -> Self::PacketId {
818 ()
819 }
820}
821
822pub trait IpStateContext<I: IpLayerIpExt>:
824 IpRouteTablesContext<I, DeviceId: DeviceWithName>
825{
826 type IpRouteTablesCtx<'a>: IpRouteTablesContext<I, DeviceId = Self::DeviceId>;
828
829 fn with_rules_table<
831 O,
832 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId>) -> O,
833 >(
834 &mut self,
835 cb: F,
836 ) -> O;
837
838 fn with_rules_table_mut<
840 O,
841 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId>) -> O,
842 >(
843 &mut self,
844 cb: F,
845 ) -> O;
846}
847
848pub trait IpRouteTablesContext<I: IpLayerIpExt>:
850 IpRouteTableContext<I> + IpDeviceContext<I>
851{
852 type Ctx<'a>: IpRouteTableContext<I, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>;
854
855 fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId>;
857
858 fn with_ip_routing_tables<
860 O,
861 F: FnOnce(
862 &mut Self::Ctx<'_>,
863 &HashMap<
864 RoutingTableId<I, Self::DeviceId>,
865 PrimaryRc<RwLock<RoutingTable<I, Self::DeviceId>>>,
866 >,
867 ) -> O,
868 >(
869 &mut self,
870 cb: F,
871 ) -> O;
872
873 fn with_ip_routing_tables_mut<
875 O,
876 F: FnOnce(
877 &mut HashMap<
878 RoutingTableId<I, Self::DeviceId>,
879 PrimaryRc<RwLock<RoutingTable<I, Self::DeviceId>>>,
880 >,
881 ) -> O,
882 >(
883 &mut self,
884 cb: F,
885 ) -> O;
886
887 fn with_main_ip_routing_table<
891 O,
892 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
893 >(
894 &mut self,
895 cb: F,
896 ) -> O {
897 let main_table_id = self.main_table_id();
898 self.with_ip_routing_table(&main_table_id, cb)
899 }
900
901 fn with_main_ip_routing_table_mut<
905 O,
906 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
907 >(
908 &mut self,
909 cb: F,
910 ) -> O {
911 let main_table_id = self.main_table_id();
912 self.with_ip_routing_table_mut(&main_table_id, cb)
913 }
914}
915
916pub trait IpRouteTableContext<I: IpLayerIpExt>: IpDeviceContext<I> {
918 type IpDeviceIdCtx<'a>: DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
920 + IpRoutingDeviceContext<I>
921 + IpDeviceContext<I>;
922
923 fn with_ip_routing_table<
925 O,
926 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
927 >(
928 &mut self,
929 table_id: &RoutingTableId<I, Self::DeviceId>,
930 cb: F,
931 ) -> O;
932
933 fn with_ip_routing_table_mut<
935 O,
936 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
937 >(
938 &mut self,
939 table_id: &RoutingTableId<I, Self::DeviceId>,
940 cb: F,
941 ) -> O;
942}
943
944pub trait IpDeviceEgressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
946 fn with_next_packet_id<O, F: FnOnce(&I::PacketIdState) -> O>(&self, cb: F) -> O;
948
949 fn get_local_addr_for_remote(
951 &mut self,
952 device_id: &Self::DeviceId,
953 remote: Option<SpecifiedAddr<I::Addr>>,
954 ) -> Option<IpDeviceAddr<I::Addr>>;
955
956 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8;
958}
959
960pub trait IpDeviceIngressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
962 fn address_status_for_device(
968 &mut self,
969 addr: SpecifiedAddr<I::Addr>,
970 device_id: &Self::DeviceId,
971 ) -> AddressStatus<I::AddressStatus>;
972}
973
974pub trait IpDeviceContext<I: IpLayerIpExt>:
976 IpDeviceEgressStateContext<I> + IpDeviceIngressStateContext<I>
977{
978 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
980
981 type DeviceAndAddressStatusIter<'a>: Iterator<Item = (Self::DeviceId, I::AddressStatus)>;
983
984 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
990 &mut self,
991 addr: SpecifiedAddr<I::Addr>,
992 cb: F,
993 ) -> R;
994
995 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
997}
998
999pub trait IpDeviceConfirmReachableContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1001 fn confirm_reachable(
1004 &mut self,
1005 bindings_ctx: &mut BC,
1006 device: &Self::DeviceId,
1007 neighbor: SpecifiedAddr<I::Addr>,
1008 );
1009}
1010
1011pub trait IpDeviceMtuContext<I: Ip>: DeviceIdContext<AnyDevice> {
1013 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu;
1017}
1018
1019#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
1021#[generic_over_ip(I, Ip)]
1022pub enum IpLayerEvent<DeviceId, I: IpLayerIpExt> {
1023 AddRoute(types::AddableEntry<I::Addr, DeviceId>),
1025 RemoveRoutes {
1027 subnet: Subnet<I::Addr>,
1029 device: DeviceId,
1031 gateway: Option<SpecifiedAddr<I::Addr>>,
1033 },
1034 MulticastForwarding(MulticastForwardingEvent<I, DeviceId>),
1036}
1037
1038impl<DeviceId, I: IpLayerIpExt> From<MulticastForwardingEvent<I, DeviceId>>
1039 for IpLayerEvent<DeviceId, I>
1040{
1041 fn from(event: MulticastForwardingEvent<I, DeviceId>) -> IpLayerEvent<DeviceId, I> {
1042 IpLayerEvent::MulticastForwarding(event)
1043 }
1044}
1045
1046impl<DeviceId, I: IpLayerIpExt> IpLayerEvent<DeviceId, I> {
1047 pub fn map_device<N, F: Fn(DeviceId) -> N>(self, map: F) -> IpLayerEvent<N, I> {
1049 match self {
1050 IpLayerEvent::AddRoute(types::AddableEntry { subnet, device, gateway, metric }) => {
1051 IpLayerEvent::AddRoute(types::AddableEntry {
1052 subnet,
1053 device: map(device),
1054 gateway,
1055 metric,
1056 })
1057 }
1058 IpLayerEvent::RemoveRoutes { subnet, device, gateway } => {
1059 IpLayerEvent::RemoveRoutes { subnet, device: map(device), gateway }
1060 }
1061 IpLayerEvent::MulticastForwarding(e) => {
1062 IpLayerEvent::MulticastForwarding(e.map_device(map))
1063 }
1064 }
1065 }
1066}
1067
1068#[derive(Derivative, PartialEq, Eq, Clone, Hash)]
1070#[derivative(Debug)]
1071pub struct RouterAdvertisementEvent<D> {
1072 #[derivative(Debug = "ignore")]
1075 pub options_bytes: Box<[u8]>,
1076 pub source: net_types::ip::Ipv6Addr,
1078 pub device: D,
1080}
1081
1082impl<D> RouterAdvertisementEvent<D> {
1083 pub fn map_device<N, F: Fn(D) -> N>(self, map: F) -> RouterAdvertisementEvent<N> {
1085 let Self { options_bytes, source, device } = self;
1086 RouterAdvertisementEvent { options_bytes, source, device: map(device) }
1087 }
1088}
1089
1090pub trait NdpBindingsContext<DeviceId>: EventContext<RouterAdvertisementEvent<DeviceId>> {}
1092impl<DeviceId, BC: EventContext<RouterAdvertisementEvent<DeviceId>>> NdpBindingsContext<DeviceId>
1093 for BC
1094{
1095}
1096
1097pub trait IpLayerBindingsContext<I: IpLayerIpExt, DeviceId>:
1099 InstantContext
1100 + EventContext<IpLayerEvent<DeviceId, I>>
1101 + FilterBindingsContext
1102 + TxMetadataBindingsTypes
1103{
1104}
1105impl<
1106 I: IpLayerIpExt,
1107 DeviceId,
1108 BC: InstantContext
1109 + EventContext<IpLayerEvent<DeviceId, I>>
1110 + FilterBindingsContext
1111 + TxMetadataBindingsTypes,
1112> IpLayerBindingsContext<I, DeviceId> for BC
1113{
1114}
1115
1116pub trait IpLayerBindingsTypes: IcmpBindingsTypes + IpStateBindingsTypes {}
1118impl<BT: IcmpBindingsTypes + IpStateBindingsTypes> IpLayerBindingsTypes for BT {}
1119
1120pub trait IpLayerContext<
1122 I: IpLayerIpExt,
1123 BC: IpLayerBindingsContext<I, <Self as DeviceIdContext<AnyDevice>>::DeviceId>,
1124>:
1125 IpStateContext<I>
1126 + IpDeviceContext<I>
1127 + IpDeviceMtuContext<I>
1128 + IpDeviceSendContext<I, BC>
1129 + IcmpErrorHandler<I, BC>
1130 + MulticastForwardingStateContext<I, BC>
1131 + MulticastForwardingDeviceContext<I>
1132 + CounterContext<MulticastForwardingCounters<I>>
1133 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>
1134{
1135}
1136
1137impl<
1138 I: IpLayerIpExt,
1139 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
1140 CC: IpStateContext<I>
1141 + IpDeviceContext<I>
1142 + IpDeviceMtuContext<I>
1143 + IpDeviceSendContext<I, BC>
1144 + IcmpErrorHandler<I, BC>
1145 + MulticastForwardingStateContext<I, BC>
1146 + MulticastForwardingDeviceContext<I>
1147 + CounterContext<MulticastForwardingCounters<I>>
1148 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>,
1149> IpLayerContext<I, BC> for CC
1150{
1151}
1152
1153fn is_unicast_assigned<I: IpLayerIpExt>(status: &I::AddressStatus) -> bool {
1154 #[derive(GenericOverIp)]
1155 #[generic_over_ip(I, Ip)]
1156 struct WrapAddressStatus<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
1157
1158 I::map_ip(
1159 WrapAddressStatus(status),
1160 |WrapAddressStatus(status)| match status {
1161 Ipv4PresentAddressStatus::UnicastAssigned
1162 | Ipv4PresentAddressStatus::LoopbackSubnet => true,
1163 Ipv4PresentAddressStatus::UnicastTentative
1164 | Ipv4PresentAddressStatus::LimitedBroadcast
1165 | Ipv4PresentAddressStatus::SubnetBroadcast
1166 | Ipv4PresentAddressStatus::Multicast => false,
1167 },
1168 |WrapAddressStatus(status)| match status {
1169 Ipv6PresentAddressStatus::UnicastAssigned => true,
1170 Ipv6PresentAddressStatus::Multicast | Ipv6PresentAddressStatus::UnicastTentative => {
1171 false
1172 }
1173 },
1174 )
1175}
1176
1177fn is_local_assigned_address<I: Ip + IpLayerIpExt, CC: IpDeviceIngressStateContext<I>>(
1178 core_ctx: &mut CC,
1179 device: &CC::DeviceId,
1180 addr: IpDeviceAddr<I::Addr>,
1181) -> bool {
1182 match core_ctx.address_status_for_device(addr.into(), device) {
1183 AddressStatus::Present(status) => is_unicast_assigned::<I>(&status),
1184 AddressStatus::Unassigned => false,
1185 }
1186}
1187
1188fn get_device_with_assigned_address<I, CC>(
1189 core_ctx: &mut CC,
1190 addr: IpDeviceAddr<I::Addr>,
1191) -> Option<(CC::DeviceId, I::AddressStatus)>
1192where
1193 I: IpLayerIpExt,
1194 CC: IpDeviceContext<I>,
1195{
1196 core_ctx.with_address_statuses(addr.into(), |mut it| {
1197 it.find_map(|(device, status)| {
1198 is_unicast_assigned::<I>(&status).then_some((device, status))
1199 })
1200 })
1201}
1202
1203fn get_local_addr<I: Ip + IpLayerIpExt, CC: IpDeviceContext<I>>(
1207 core_ctx: &mut CC,
1208 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1209 device: &CC::DeviceId,
1210 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1211) -> Result<IpDeviceAddr<I::Addr>, ResolveRouteError> {
1212 match local_ip_and_policy {
1213 Some((local_ip, NonLocalSrcAddrPolicy::Allow)) => Ok(local_ip),
1214 Some((local_ip, NonLocalSrcAddrPolicy::Deny)) => {
1215 is_local_assigned_address(core_ctx, device, local_ip)
1216 .then_some(local_ip)
1217 .ok_or(ResolveRouteError::NoSrcAddr)
1218 }
1219 None => core_ctx
1220 .get_local_addr_for_remote(device, remote_addr.map(Into::into))
1221 .ok_or(ResolveRouteError::NoSrcAddr),
1222 }
1223}
1224
1225#[derive(Error, Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
1227#[generic_over_ip()]
1228pub enum ResolveRouteError {
1229 #[error("a source address could not be selected")]
1231 NoSrcAddr,
1232 #[error("no route exists to the destination IP address")]
1234 Unreachable,
1235}
1236
1237fn get_local_addr_with_internal_forwarding<I, CC>(
1239 core_ctx: &mut CC,
1240 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1241 device: &CC::DeviceId,
1242 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1243) -> Result<(IpDeviceAddr<I::Addr>, InternalForwarding<CC::DeviceId>), ResolveRouteError>
1244where
1245 I: IpLayerIpExt,
1246 CC: IpDeviceContext<I>,
1247{
1248 match get_local_addr(core_ctx, local_ip_and_policy, device, remote_addr) {
1249 Ok(src_addr) => Ok((src_addr, InternalForwarding::NotUsed)),
1250 Err(e) => {
1251 if let Some((local_ip, _policy)) = local_ip_and_policy {
1259 if let Some((device, _addr_status)) =
1260 get_device_with_assigned_address(core_ctx, local_ip)
1261 {
1262 if core_ctx.is_device_unicast_forwarding_enabled(&device) {
1263 return Ok((local_ip, InternalForwarding::Used(device)));
1264 }
1265 }
1266 }
1267 Err(e)
1268 }
1269 }
1270}
1271
1272#[derive(Debug, PartialEq, Eq)]
1275struct RuleWalkInfo<O> {
1276 observed_source_address_matcher: bool,
1278 inner: O,
1281}
1282
1283fn walk_rules<
1297 I: IpLayerIpExt,
1298 CC: IpRouteTablesContext<I, DeviceId: DeviceWithName>,
1299 O,
1300 State,
1301 F: FnMut(
1302 State,
1303 &mut CC::IpDeviceIdCtx<'_>,
1304 &RoutingTable<I, CC::DeviceId>,
1305 ) -> ControlFlow<O, State>,
1306>(
1307 core_ctx: &mut CC,
1308 rules: &RulesTable<I, CC::DeviceId>,
1309 init: State,
1310 rule_input: &RuleInput<'_, I, CC::DeviceId>,
1311 mut lookup_table: F,
1312) -> ControlFlow<RuleAction<RuleWalkInfo<O>>, RuleWalkInfo<State>> {
1313 rules.iter().try_fold(
1314 RuleWalkInfo { inner: init, observed_source_address_matcher: false },
1315 |RuleWalkInfo { inner: state, observed_source_address_matcher },
1316 Rule { action, matcher }| {
1317 let observed_source_address_matcher =
1318 observed_source_address_matcher || matcher.source_address_matcher.is_some();
1319 if !matcher.matches(rule_input) {
1320 return ControlFlow::Continue(RuleWalkInfo {
1321 inner: state,
1322 observed_source_address_matcher,
1323 });
1324 }
1325 match action {
1326 RuleAction::Unreachable => return ControlFlow::Break(RuleAction::Unreachable),
1327 RuleAction::Lookup(table_id) => core_ctx.with_ip_routing_table(
1328 &table_id,
1329 |core_ctx, table| match lookup_table(state, core_ctx, table) {
1330 ControlFlow::Break(out) => {
1331 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1332 inner: out,
1333 observed_source_address_matcher,
1334 }))
1335 }
1336 ControlFlow::Continue(state) => ControlFlow::Continue(RuleWalkInfo {
1337 inner: state,
1338 observed_source_address_matcher,
1339 }),
1340 },
1341 ),
1342 }
1343 },
1344 )
1345}
1346
1347pub fn resolve_output_route_to_destination<
1358 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1359 BC: IpDeviceBindingsContext<I, CC::DeviceId> + IpLayerBindingsContext<I, CC::DeviceId>,
1360 CC: IpStateContext<I> + IpDeviceContext<I> + device::IpDeviceConfigurationContext<I, BC>,
1361>(
1362 core_ctx: &mut CC,
1363 device: Option<&CC::DeviceId>,
1364 src_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1365 dst_ip: Option<RoutableIpAddr<I::Addr>>,
1366 marks: &Marks,
1367) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1368 enum LocalDelivery<A, D> {
1369 WeakLoopback { dst_ip: A, device: D },
1370 StrongForDevice(D),
1371 }
1372
1373 let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1391 let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1392 match (device, dst_ip) {
1393 (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1394 .then_some(LocalDelivery::StrongForDevice(device.clone())),
1395 (None, Some(dst_ip)) => {
1396 get_device_with_assigned_address(core_ctx, dst_ip).map(
1397 |(dst_device, _addr_status)| {
1398 if src_ip_and_policy
1403 .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1404 || dst_ip.as_ref().must_have_zone()
1405 {
1406 LocalDelivery::StrongForDevice(dst_device)
1407 } else {
1408 LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1409 }
1410 },
1411 )
1412 }
1413 (_, None) => None,
1414 }
1415 };
1416
1417 if let Some(local_delivery) = local_delivery_instructions {
1418 let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1419
1420 let (src_addr, dest_device) = match local_delivery {
1421 LocalDelivery::WeakLoopback { dst_ip, device } => {
1422 let src_ip = match src_ip_and_policy {
1423 Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1424 let _device = get_device_with_assigned_address(core_ctx, src_ip)
1425 .ok_or(ResolveRouteError::NoSrcAddr)?;
1426 src_ip
1427 }
1428 Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1429 None => dst_ip,
1430 };
1431 (src_ip, device)
1432 }
1433 LocalDelivery::StrongForDevice(device) => {
1434 (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1435 }
1436 };
1437 return Ok(ResolvedRoute {
1438 src_addr,
1439 local_delivery_device: Some(dest_device),
1440 device: loopback,
1441 next_hop: NextHop::RemoteAsNeighbor,
1442 internal_forwarding: InternalForwarding::NotUsed,
1443 });
1444 }
1445 let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1446 let rule_input = RuleInput {
1447 packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1448 marks,
1449 };
1450 core_ctx.with_rules_table(|core_ctx, rules| {
1451 let mut walk_rules = |rule_input, src_ip_and_policy| {
1452 walk_rules(
1453 core_ctx,
1454 rules,
1455 None, rule_input,
1457 |first_error, core_ctx, table| {
1458 let mut matching_with_addr = table.lookup_filter_map(
1459 core_ctx,
1460 device,
1461 dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1462 |core_ctx, d| {
1463 Some(get_local_addr_with_internal_forwarding(
1464 core_ctx,
1465 src_ip_and_policy,
1466 d,
1467 dst_ip,
1468 ))
1469 },
1470 );
1471
1472 let first_error_in_this_table = match matching_with_addr.next() {
1473 Some((
1474 Destination { device, next_hop },
1475 Ok((local_addr, internal_forwarding)),
1476 )) => {
1477 return ControlFlow::Break(Ok((
1478 Destination { device: device.clone(), next_hop },
1479 local_addr,
1480 internal_forwarding,
1481 )));
1482 }
1483 Some((_, Err(e))) => e,
1484 None => return ControlFlow::Continue(first_error),
1488 };
1489
1490 matching_with_addr
1491 .filter_map(|(destination, local_addr)| {
1492 local_addr.ok_checked::<ResolveRouteError>().map(
1495 |(local_addr, internal_forwarding)| {
1496 (destination, local_addr, internal_forwarding)
1497 },
1498 )
1499 })
1500 .next()
1501 .map_or(
1502 ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1503 |(
1504 Destination { device, next_hop },
1505 local_addr,
1506 internal_forwarding,
1507 )| {
1508 ControlFlow::Break(Ok((
1509 Destination { device: device.clone(), next_hop },
1510 local_addr,
1511 internal_forwarding,
1512 )))
1513 },
1514 )
1515 },
1516 )
1517 };
1518
1519 let result = match walk_rules(&rule_input, src_ip_and_policy) {
1520 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1527 inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1528 observed_source_address_matcher: true,
1529 })) if src_ip_and_policy.is_none() => walk_rules(
1530 &RuleInput {
1531 packet_origin: PacketOrigin::Local {
1532 bound_address: Some(selected_src_addr.into()),
1533 bound_device: device,
1534 },
1535 marks,
1536 },
1537 Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1538 ),
1539 result => result,
1540 };
1541
1542 match result {
1543 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1544 inner: result,
1545 observed_source_address_matcher: _,
1546 })) => {
1547 result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1548 ResolvedRoute {
1549 src_addr,
1550 device,
1551 local_delivery_device: None,
1552 next_hop,
1553 internal_forwarding,
1554 }
1555 })
1556 }
1557 ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1558 ControlFlow::Continue(RuleWalkInfo {
1559 inner: first_error,
1560 observed_source_address_matcher: _,
1561 }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1562 }
1563 })
1564}
1565
1566pub trait UseIpSocketContextBlanket {}
1571
1572impl<
1573 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1574 BC: IpDeviceBindingsContext<I, CC::DeviceId>
1575 + IpLayerBindingsContext<I, CC::DeviceId>
1576 + IpSocketBindingsContext<CC::DeviceId>,
1577 CC: IpLayerEgressContext<I, BC>
1578 + IpStateContext<I>
1579 + IpDeviceContext<I>
1580 + IpDeviceConfirmReachableContext<I, BC>
1581 + IpDeviceMtuContext<I>
1582 + device::IpDeviceConfigurationContext<I, BC>
1583 + UseIpSocketContextBlanket,
1584> IpSocketContext<I, BC> for CC
1585{
1586 fn lookup_route(
1587 &mut self,
1588 _bindings_ctx: &mut BC,
1589 device: Option<&CC::DeviceId>,
1590 local_ip: Option<IpDeviceAddr<I::Addr>>,
1591 addr: RoutableIpAddr<I::Addr>,
1592 transparent: bool,
1593 marks: &Marks,
1594 ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1595 let src_ip_and_policy = local_ip.map(|local_ip| {
1596 (
1597 local_ip,
1598 if transparent {
1599 NonLocalSrcAddrPolicy::Allow
1600 } else {
1601 NonLocalSrcAddrPolicy::Deny
1602 },
1603 )
1604 });
1605 let res =
1606 resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1607 trace!(
1608 "lookup_route(\
1609 device={device:?}, \
1610 local_ip={local_ip:?}, \
1611 addr={addr:?}, \
1612 transparent={transparent:?}, \
1613 marks={marks:?}) => {res:?}"
1614 );
1615 res
1616 }
1617
1618 fn send_ip_packet<S>(
1619 &mut self,
1620 bindings_ctx: &mut BC,
1621 meta: SendIpPacketMeta<
1622 I,
1623 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1624 SpecifiedAddr<I::Addr>,
1625 >,
1626 body: S,
1627 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1628 ) -> Result<(), IpSendFrameError<S>>
1629 where
1630 S: TransportPacketSerializer<I>,
1631 S::Buffer: BufferMut,
1632 {
1633 send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1634 }
1635
1636 fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1637 device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1638 }
1639
1640 fn confirm_reachable(
1641 &mut self,
1642 bindings_ctx: &mut BC,
1643 dst: SpecifiedAddr<I::Addr>,
1644 input: RuleInput<'_, I, Self::DeviceId>,
1645 ) {
1646 match lookup_route_table(self, dst.get(), input) {
1647 Some(Destination { next_hop, device }) => {
1648 let neighbor = match next_hop {
1649 NextHop::RemoteAsNeighbor => dst,
1650 NextHop::Gateway(gateway) => gateway,
1651 NextHop::Broadcast(marker) => {
1652 I::map_ip::<_, ()>(
1653 WrapBroadcastMarker(marker),
1654 |WrapBroadcastMarker(())| {
1655 debug!(
1656 "can't confirm {dst:?}@{device:?} as reachable: \
1657 dst is a broadcast address"
1658 );
1659 },
1660 |WrapBroadcastMarker(never)| match never {},
1661 );
1662 return;
1663 }
1664 };
1665 IpDeviceConfirmReachableContext::confirm_reachable(
1666 self,
1667 bindings_ctx,
1668 &device,
1669 neighbor,
1670 );
1671 }
1672 None => {
1673 debug!("can't confirm {dst:?} as reachable: no route");
1674 }
1675 }
1676 }
1677}
1678
1679pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1684 fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1686 &mut self,
1687 bindings_ctx: &mut BC,
1688 device: &Self::DeviceId,
1689 src_ip: I::RecvSrcAddr,
1690 dst_ip: SpecifiedAddr<I::Addr>,
1691 proto: I::Proto,
1692 body: B,
1693 info: &LocalDeliveryPacketInfo<I, H>,
1694 ) -> Result<(), TransportReceiveError>;
1695}
1696
1697pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1699 IpTransportDispatchContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1700 + IpDeviceIngressStateContext<I>
1701 + IpDeviceMtuContext<I>
1702 + IpDeviceSendContext<I, BC>
1703 + IcmpErrorHandler<I, BC>
1704 + IpLayerContext<I, BC>
1705 + FragmentHandler<I, BC>
1706 + FilterHandlerProvider<I, BC>
1707 + RawIpSocketHandler<I, BC>
1708{
1709}
1710
1711impl<
1712 I: IpLayerIpExt,
1713 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1714 CC: IpTransportDispatchContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1715 + IpDeviceIngressStateContext<I>
1716 + IpDeviceMtuContext<I>
1717 + IpDeviceSendContext<I, BC>
1718 + IcmpErrorHandler<I, BC>
1719 + IpLayerContext<I, BC>
1720 + FragmentHandler<I, BC>
1721 + FilterHandlerProvider<I, BC>
1722 + RawIpSocketHandler<I, BC>,
1723> IpLayerIngressContext<I, BC> for CC
1724{
1725}
1726
1727pub trait IpLayerEgressContext<I, BC>:
1729 IpDeviceSendContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1730 + FilterHandlerProvider<I, BC>
1731 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1732where
1733 I: IpLayerIpExt,
1734 BC: FilterBindingsContext + TxMetadataBindingsTypes,
1735{
1736}
1737
1738impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1739where
1740 I: IpLayerIpExt,
1741 BC: FilterBindingsContext + TxMetadataBindingsTypes,
1742 CC: IpDeviceSendContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1743 + FilterHandlerProvider<I, BC>
1744 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
1745{
1746}
1747
1748pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1750 IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
1751{
1752}
1753
1754impl<
1755 I: IpLayerIpExt,
1756 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1757 CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
1758> IpLayerForwardingContext<I, BC> for CC
1759{
1760}
1761
1762#[derive(Copy, Clone, Default)]
1764pub struct Ipv4StateBuilder {
1765 icmp: Icmpv4StateBuilder,
1766}
1767
1768impl Ipv4StateBuilder {
1769 #[cfg(any(test, feature = "testutils"))]
1771 pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
1772 &mut self.icmp
1773 }
1774
1775 pub fn build<
1777 CC: CoreTimerContext<IpLayerTimerId, BC>,
1778 StrongDeviceId: StrongDeviceIdentifier,
1779 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1780 >(
1781 self,
1782 bindings_ctx: &mut BC,
1783 ) -> Ipv4State<StrongDeviceId, BC> {
1784 let Ipv4StateBuilder { icmp } = self;
1785
1786 Ipv4State {
1787 inner: IpStateInner::new::<CC>(bindings_ctx),
1788 icmp: icmp.build(),
1789 next_packet_id: Default::default(),
1790 }
1791 }
1792}
1793
1794#[derive(Copy, Clone)]
1798pub struct Ipv6StateBuilder {
1799 icmp: Icmpv6StateBuilder,
1800 slaac_stable_secret_key: Option<IidSecret>,
1801}
1802
1803impl Ipv6StateBuilder {
1804 pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
1809 self.slaac_stable_secret_key = Some(secret_key);
1810 self
1811 }
1812
1813 pub fn build<
1819 CC: CoreTimerContext<IpLayerTimerId, BC>,
1820 StrongDeviceId: StrongDeviceIdentifier,
1821 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1822 >(
1823 self,
1824 bindings_ctx: &mut BC,
1825 ) -> Ipv6State<StrongDeviceId, BC> {
1826 let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
1827
1828 let slaac_stable_secret_key = slaac_stable_secret_key
1829 .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
1830
1831 Ipv6State {
1832 inner: IpStateInner::new::<CC>(bindings_ctx),
1833 icmp: icmp.build(),
1834 slaac_counters: Default::default(),
1835 slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
1836 slaac_stable_secret_key,
1837 }
1838 }
1839}
1840
1841impl Default for Ipv6StateBuilder {
1842 fn default() -> Self {
1843 #[cfg(any(test, feature = "testutils"))]
1844 let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
1845
1846 #[cfg(not(any(test, feature = "testutils")))]
1847 let slaac_stable_secret_key = None;
1848
1849 Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
1850 }
1851}
1852
1853pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1855 pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
1857 pub icmp: Icmpv4State<BT>,
1859 pub next_packet_id: AtomicU16,
1861}
1862
1863impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1864 AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
1865{
1866 fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
1867 &self.inner
1868 }
1869}
1870
1871pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
1875 core_ctx: &mut CC,
1876) -> I::PacketId {
1877 core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
1878}
1879
1880pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1882 pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
1884 pub icmp: Icmpv6State<BT>,
1886 pub slaac_counters: SlaacCounters,
1888 pub slaac_temp_secret_key: IidSecret,
1890 pub slaac_stable_secret_key: IidSecret,
1895}
1896
1897impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1898 AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
1899{
1900 fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
1901 &self.inner
1902 }
1903}
1904
1905impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1906 OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
1907{
1908 type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
1909 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1910 OrderedLockRef::new(&self.fragment_cache)
1911 }
1912}
1913
1914impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1915 OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
1916{
1917 type Lock = Mutex<PmtuCache<I, BT>>;
1918 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1919 OrderedLockRef::new(&self.pmtu_cache)
1920 }
1921}
1922
1923impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1924 OrderedLockAccess<RulesTable<I, D>> for IpStateInner<I, D, BT>
1925{
1926 type Lock = RwLock<RulesTable<I, D>>;
1927 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1928 OrderedLockRef::new(&self.rules_table)
1929 }
1930}
1931
1932impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1933 OrderedLockAccess<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>
1934 for IpStateInner<I, D, BT>
1935{
1936 type Lock = Mutex<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>;
1937 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1938 OrderedLockRef::new(&self.tables)
1939 }
1940}
1941
1942impl<I: IpLayerIpExt, D: StrongDeviceIdentifier> OrderedLockAccess<RoutingTable<I, D>>
1943 for RoutingTableId<I, D>
1944{
1945 type Lock = RwLock<RoutingTable<I, D>>;
1946 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1947 let Self(inner) = self;
1948 OrderedLockRef::new(&*inner)
1949 }
1950}
1951
1952impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1953 OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
1954{
1955 type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
1956 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1957 OrderedLockRef::new(&self.multicast_forwarding)
1958 }
1959}
1960
1961impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1962 OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
1963{
1964 type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
1965 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1966 OrderedLockRef::new(&self.raw_sockets)
1967 }
1968}
1969
1970impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1971 OrderedLockAccess<filter::State<I, WeakAddressId<I, BT>, BT>> for IpStateInner<I, D, BT>
1972{
1973 type Lock = RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>;
1974 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1975 OrderedLockRef::new(&self.filter)
1976 }
1977}
1978
1979pub trait IpStateBindingsTypes:
1981 PmtuBindingsTypes
1982 + FragmentBindingsTypes
1983 + RawIpSocketsBindingsTypes
1984 + FilterBindingsTypes
1985 + MulticastForwardingBindingsTypes
1986 + IpDeviceStateBindingsTypes
1987{
1988}
1989impl<BT> IpStateBindingsTypes for BT where
1990 BT: PmtuBindingsTypes
1991 + FragmentBindingsTypes
1992 + RawIpSocketsBindingsTypes
1993 + FilterBindingsTypes
1994 + MulticastForwardingBindingsTypes
1995 + IpDeviceStateBindingsTypes
1996{
1997}
1998
1999#[derive(Clone, PartialEq, Eq, Hash)]
2001pub struct RoutingTableId<I: Ip, D>(StrongRc<RwLock<RoutingTable<I, D>>>);
2002
2003impl<I: Ip, D> Debug for RoutingTableId<I, D> {
2004 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2005 let Self(rc) = self;
2006 f.debug_tuple("RoutingTableId").field(&StrongRc::debug_id(rc)).finish()
2007 }
2008}
2009
2010impl<I: Ip, D> RoutingTableId<I, D> {
2011 pub(crate) fn new(rc: StrongRc<RwLock<RoutingTable<I, D>>>) -> Self {
2013 Self(rc)
2014 }
2015
2016 #[cfg(any(test, feature = "testutils"))]
2018 pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
2019 let Self(inner) = self;
2020 &*inner
2021 }
2022
2023 pub fn downgrade(&self) -> WeakRoutingTableId<I, D> {
2025 let Self(rc) = self;
2026 WeakRoutingTableId(StrongRc::downgrade(rc))
2027 }
2028
2029 #[cfg(test)]
2030 fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2031 let Self(rc) = self;
2032 rc.write()
2033 }
2034}
2035
2036#[derive(Clone, PartialEq, Eq, Hash)]
2038pub struct WeakRoutingTableId<I: Ip, D>(WeakRc<RwLock<RoutingTable<I, D>>>);
2039
2040impl<I: Ip, D> Debug for WeakRoutingTableId<I, D> {
2041 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2042 let Self(rc) = self;
2043 f.debug_tuple("WeakRoutingTableId").field(&WeakRc::debug_id(rc)).finish()
2044 }
2045}
2046
2047#[derive(GenericOverIp)]
2049#[generic_over_ip(I, Ip)]
2050pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2051 rules_table: RwLock<RulesTable<I, D>>,
2052 main_table_id: RoutingTableId<I, D>,
2054 multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2055 multicast_forwarding_counters: MulticastForwardingCounters<I>,
2056 fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2057 pmtu_cache: Mutex<PmtuCache<I, BT>>,
2058 counters: IpCounters<I>,
2059 raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2060 raw_socket_counters: RawIpSocketCounters<I>,
2061 filter: RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>,
2062 tables: Mutex<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>,
2068 igmp_counters: IgmpCounters,
2069 mld_counters: MldCounters,
2070}
2071
2072impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2073 pub fn counters(&self) -> &IpCounters<I> {
2075 &self.counters
2076 }
2077
2078 pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2080 &self.multicast_forwarding_counters
2081 }
2082
2083 pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2085 &self.raw_socket_counters
2086 }
2087
2088 pub fn main_table_id(&self) -> &RoutingTableId<I, D> {
2090 &self.main_table_id
2091 }
2092
2093 #[cfg(any(test, feature = "testutils"))]
2095 pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2096 &self.pmtu_cache
2097 }
2098
2099 #[cfg(any(test, feature = "testutils"))]
2101 pub fn filter(&self) -> &RwLock<filter::State<I, WeakAddressId<I, BT>, BT>> {
2102 &self.filter
2103 }
2104
2105 pub fn igmp_counters(&self) -> &IgmpCounters {
2107 &self.igmp_counters
2108 }
2109
2110 pub fn mld_counters(&self) -> &MldCounters {
2112 &self.mld_counters
2113 }
2114}
2115
2116impl<
2117 I: IpLayerIpExt,
2118 D: StrongDeviceIdentifier,
2119 BC: TimerContext + RngContext + IpStateBindingsTypes,
2120> IpStateInner<I, D, BC>
2121{
2122 fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2124 let main_table: PrimaryRc<RwLock<RoutingTable<I, D>>> = PrimaryRc::new(Default::default());
2125 let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2126 Self {
2127 rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2128 tables: Mutex::new(HashMap::from_iter(core::iter::once((
2129 main_table_id.clone(),
2130 main_table,
2131 )))),
2132 main_table_id,
2133 multicast_forwarding: Default::default(),
2134 multicast_forwarding_counters: Default::default(),
2135 fragment_cache: Mutex::new(
2136 IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2137 ),
2138 pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2139 counters: Default::default(),
2140 raw_sockets: Default::default(),
2141 raw_socket_counters: Default::default(),
2142 filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2143 igmp_counters: Default::default(),
2144 mld_counters: Default::default(),
2145 }
2146 }
2147}
2148
2149#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2151#[generic_over_ip()]
2152pub enum IpLayerTimerId {
2153 ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2155 ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2157 PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2159 PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2161 FilterTimerv4(FilterTimerId<Ipv4>),
2163 FilterTimerv6(FilterTimerId<Ipv6>),
2165 MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2167 MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2169}
2170
2171impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2172 fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2173 I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2174 }
2175}
2176
2177impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2178 fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2179 I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2180 }
2181}
2182
2183impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2184 fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2185 I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2186 }
2187}
2188
2189impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2190 fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2191 I::map_ip(
2192 timer,
2193 IpLayerTimerId::MulticastForwardingTimerv4,
2194 IpLayerTimerId::MulticastForwardingTimerv6,
2195 )
2196 }
2197}
2198
2199impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2200where
2201 CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2202 + TimerHandler<BC, FragmentTimerId<Ipv6>>
2203 + TimerHandler<BC, PmtuTimerId<Ipv4>>
2204 + TimerHandler<BC, PmtuTimerId<Ipv6>>
2205 + TimerHandler<BC, FilterTimerId<Ipv4>>
2206 + TimerHandler<BC, FilterTimerId<Ipv6>>
2207 + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2208 + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2209 BC: TimerBindingsTypes,
2210{
2211 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2212 match self {
2213 IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2214 core_ctx.handle_timer(bindings_ctx, id, timer)
2215 }
2216 IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2217 core_ctx.handle_timer(bindings_ctx, id, timer)
2218 }
2219 IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2220 IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2221 IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2222 IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2223 IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2224 core_ctx.handle_timer(bindings_ctx, id, timer)
2225 }
2226 IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2227 core_ctx.handle_timer(bindings_ctx, id, timer)
2228 }
2229 }
2230 }
2231}
2232
2233pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2240 err: I::IcmpError,
2242 src_ip: I::SourceAddress,
2245 dst_ip: SpecifiedAddr<I::Addr>,
2248 frame_dst: Option<FrameDestination>,
2250 device: &'a D,
2252 meta: ParseMetadata,
2255 marks: Marks,
2257}
2258
2259impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2260 fn respond_with_icmp_error<B, BC, CC>(
2267 self,
2268 core_ctx: &mut CC,
2269 bindings_ctx: &mut BC,
2270 mut body: B,
2271 ) where
2272 B: BufferMut,
2273 CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2274 {
2275 let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks } = self;
2276 body.undo_parse(meta);
2280
2281 core_ctx.send_icmp_error_message(
2282 bindings_ctx,
2283 device,
2284 frame_dst,
2285 src_ip,
2286 dst_ip,
2287 body,
2288 err,
2289 &marks,
2290 );
2291 }
2292}
2293
2294fn dispatch_receive_ipv4_packet<
2315 'a,
2316 'b,
2317 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2318 CC: IpLayerIngressContext<Ipv4, BC>,
2319>(
2320 core_ctx: &'a mut CC,
2321 bindings_ctx: &'a mut BC,
2322 device: &'b CC::DeviceId,
2323 frame_dst: Option<FrameDestination>,
2324 mut packet: Ipv4Packet<&'a mut [u8]>,
2325 mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2326 receive_meta: ReceiveIpPacketMeta<Ipv4>,
2327) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2328 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2329
2330 match frame_dst {
2331 Some(FrameDestination::Individual { local: false }) => {
2332 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2333 }
2334 Some(FrameDestination::Individual { local: true })
2335 | Some(FrameDestination::Multicast)
2336 | Some(FrameDestination::Broadcast)
2337 | None => (),
2338 }
2339
2340 let proto = packet.proto();
2341
2342 match core_ctx.filter_handler().local_ingress_hook(
2343 bindings_ctx,
2344 &mut packet,
2345 device,
2346 &mut packet_metadata,
2347 ) {
2348 filter::Verdict::Drop => {
2349 packet_metadata.acknowledge_drop();
2350 return Ok(());
2351 }
2352 filter::Verdict::Accept(()) => {}
2353 }
2354 let marks = packet_metadata.marks;
2355 packet_metadata.acknowledge_drop();
2356
2357 let Some(src_ip) = packet.src_ipv4() else {
2361 debug!(
2362 "dispatch_receive_ipv4_packet: received packet from invalid source {} after the \
2363 LOCAL_INGRESS hook; dropping",
2364 packet.src_ip()
2365 );
2366 core_ctx.increment_both(device, |c| &c.invalid_source);
2367 return Ok(());
2368 };
2369 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2370 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2371 debug!(
2372 "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2373 after the LOCAL_INGRESS hook; dropping"
2374 );
2375 return Ok(());
2376 };
2377
2378 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2379
2380 let (prefix, options, body) = packet.parts_with_body_mut();
2381 let buffer = Buf::new(body, ..);
2382 let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2383 let receive_info = LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks };
2384
2385 core_ctx
2386 .dispatch_receive_ip_packet(
2387 bindings_ctx,
2388 device,
2389 src_ip,
2390 dst_ip,
2391 proto,
2392 buffer,
2393 &receive_info,
2394 )
2395 .or_else(|err| {
2396 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
2397 let (_, _, _, meta) = packet.into_metadata();
2398 Err(IcmpErrorSender {
2399 err: err.into_icmpv4_error(meta.header_len()),
2400 src_ip,
2401 dst_ip,
2402 frame_dst,
2403 device,
2404 meta,
2405 marks,
2406 })
2407 } else {
2408 Ok(())
2409 }
2410 })
2411}
2412
2413fn dispatch_receive_ipv6_packet<
2418 'a,
2419 'b,
2420 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2421 CC: IpLayerIngressContext<Ipv6, BC>,
2422>(
2423 core_ctx: &'a mut CC,
2424 bindings_ctx: &'a mut BC,
2425 device: &'b CC::DeviceId,
2426 frame_dst: Option<FrameDestination>,
2427 mut packet: Ipv6Packet<&'a mut [u8]>,
2428 mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2429 meta: ReceiveIpPacketMeta<Ipv6>,
2430) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2431 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2438
2439 match frame_dst {
2440 Some(FrameDestination::Individual { local: false }) => {
2441 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2442 }
2443 Some(FrameDestination::Individual { local: true })
2444 | Some(FrameDestination::Multicast)
2445 | Some(FrameDestination::Broadcast)
2446 | None => (),
2447 }
2448
2449 let proto = packet.proto();
2450
2451 match core_ctx.filter_handler().local_ingress_hook(
2452 bindings_ctx,
2453 &mut packet,
2454 device,
2455 &mut packet_metadata,
2456 ) {
2457 filter::Verdict::Drop => {
2458 packet_metadata.acknowledge_drop();
2459 return Ok(());
2460 }
2461 filter::Verdict::Accept(()) => {}
2462 }
2463
2464 let Some(src_ip) = packet.src_ipv6() else {
2468 debug!(
2469 "dispatch_receive_ipv6_packet: received packet from invalid source {} after the \
2470 LOCAL_INGRESS hook; dropping",
2471 packet.src_ip()
2472 );
2473
2474 core_ctx.increment_both(device, |c| &c.invalid_source);
2475 return Ok(());
2476 };
2477 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2478 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2479 debug!(
2480 "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2481 after the LOCAL_INGRESS hook; dropping"
2482 );
2483 return Ok(());
2484 };
2485
2486 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2487
2488 let (fixed, extension, body) = packet.parts_with_body_mut();
2489 let buffer = Buf::new(body, ..);
2490 let header_info = Ipv6HeaderInfo { fixed, extension };
2491 let receive_info = LocalDeliveryPacketInfo { meta, header_info, marks: packet_metadata.marks };
2492
2493 let result = core_ctx
2494 .dispatch_receive_ip_packet(
2495 bindings_ctx,
2496 device,
2497 src_ip,
2498 dst_ip,
2499 proto,
2500 buffer,
2501 &receive_info,
2502 )
2503 .or_else(|err| {
2504 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
2505 let (_, _, _, meta) = packet.into_metadata();
2506 Err(IcmpErrorSender {
2507 err: err.into_icmpv6_error(meta.header_len()),
2508 src_ip: *src_ip,
2509 dst_ip,
2510 frame_dst,
2511 device,
2512 meta,
2513 marks: receive_info.marks,
2514 })
2515 } else {
2516 Ok(())
2517 }
2518 });
2519 packet_metadata.acknowledge_drop();
2520 result
2521}
2522
2523pub(crate) struct IpPacketForwarder<
2530 'a,
2531 I: IpLayerIpExt,
2532 D,
2533 A,
2534 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2535> {
2536 inbound_device: &'a D,
2537 outbound_device: &'a D,
2538 packet_meta: IpLayerPacketMetadata<I, A, BT>,
2539 src_ip: I::RecvSrcAddr,
2540 dst_ip: SpecifiedAddr<I::Addr>,
2541 destination: IpPacketDestination<I, &'a D>,
2542 proto: I::Proto,
2543 parse_meta: ParseMetadata,
2544 frame_dst: Option<FrameDestination>,
2545}
2546
2547impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
2548where
2549 I: IpLayerIpExt,
2550 BC: IpLayerBindingsContext<I, D>,
2551{
2552 fn forward_with_buffer<CC, B>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B)
2554 where
2555 B: BufferMut,
2556 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2557 {
2558 let Self {
2559 inbound_device,
2560 outbound_device,
2561 packet_meta,
2562 src_ip,
2563 dst_ip,
2564 destination,
2565 proto,
2566 parse_meta,
2567 frame_dst,
2568 } = self;
2569
2570 let packet = ForwardedPacket::new(src_ip.get(), dst_ip.get(), proto, parse_meta, buffer);
2571
2572 trace!("forward_with_buffer: forwarding {} packet", I::NAME);
2573
2574 let marks = packet_meta.marks;
2575 match send_ip_frame(
2576 core_ctx,
2577 bindings_ctx,
2578 outbound_device,
2579 destination,
2580 packet,
2581 packet_meta,
2582 Mtu::no_limit(),
2583 ) {
2584 Ok(()) => (),
2585 Err(IpSendFrameError { serializer, error }) => {
2586 match error {
2587 IpSendFrameErrorReason::Device(
2588 SendFrameErrorReason::SizeConstraintsViolation,
2589 ) => {
2590 debug!("failed to forward {} packet: MTU exceeded", I::NAME);
2591 core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
2592 let mtu = core_ctx.get_mtu(inbound_device);
2593 let Some(err) = I::new_mtu_exceeded(proto, parse_meta.header_len(), mtu)
2595 else {
2596 return;
2597 };
2598 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2601 return;
2602 };
2603 core_ctx.send_icmp_error_message(
2613 bindings_ctx,
2614 inbound_device,
2615 frame_dst,
2616 src_ip,
2617 dst_ip,
2618 serializer.into_buffer(),
2619 err,
2620 &marks,
2621 );
2622 }
2623 IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
2624 | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
2625 | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
2626 }
2627 debug!("failed to forward {} packet: {error:?}", I::NAME);
2628 }
2629 }
2630 }
2631}
2632
2633pub(crate) enum ForwardingAction<
2635 'a,
2636 I: IpLayerIpExt,
2637 D,
2638 A,
2639 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2640> {
2641 SilentlyDrop,
2643 Forward(IpPacketForwarder<'a, I, D, A, BT>),
2645 DropWithIcmpError(IcmpErrorSender<'a, I, D>),
2648}
2649
2650impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
2651where
2652 I: IpLayerIpExt,
2653 BC: IpLayerBindingsContext<I, D>,
2654{
2655 pub(crate) fn perform_action_with_buffer<CC, B>(
2657 self,
2658 core_ctx: &mut CC,
2659 bindings_ctx: &mut BC,
2660 buffer: B,
2661 ) where
2662 B: BufferMut,
2663 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2664 {
2665 match self {
2666 ForwardingAction::SilentlyDrop => {}
2667 ForwardingAction::Forward(forwarder) => {
2668 forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer)
2669 }
2670 ForwardingAction::DropWithIcmpError(icmp_sender) => {
2671 icmp_sender.respond_with_icmp_error(core_ctx, bindings_ctx, buffer)
2672 }
2673 }
2674 }
2675}
2676
2677pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
2679 core_ctx: &'a mut CC,
2680 mut packet: I::Packet<&'a mut [u8]>,
2681 mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2682 minimum_ttl: Option<u8>,
2683 inbound_device: &'b CC::DeviceId,
2684 outbound_device: &'b CC::DeviceId,
2685 destination: IpPacketDestination<I, &'b CC::DeviceId>,
2686 frame_dst: Option<FrameDestination>,
2687 src_ip: I::RecvSrcAddr,
2688 dst_ip: SpecifiedAddr<I::Addr>,
2689) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
2690where
2691 I: IpLayerIpExt,
2692 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2693 CC: IpLayerForwardingContext<I, BC>,
2694{
2695 const DEFAULT_MINIMUM_FORWARDING_TTL: u8 = 2;
2700 let minimum_ttl = minimum_ttl.unwrap_or(DEFAULT_MINIMUM_FORWARDING_TTL);
2701
2702 let ttl = packet.ttl();
2703 if ttl < minimum_ttl {
2704 debug!(
2705 "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
2706 I::NAME
2707 );
2708 if ttl > 1 {
2720 packet_meta.acknowledge_drop();
2721 return ForwardingAction::SilentlyDrop;
2722 }
2723
2724 core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
2725
2726 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2728 core_ctx.increment_both(inbound_device, |c| &c.unspecified_source);
2729 packet_meta.acknowledge_drop();
2730 return ForwardingAction::SilentlyDrop;
2731 };
2732
2733 let version_specific_meta = packet.version_specific_meta();
2735 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
2736 let err = I::new_ttl_expired(proto, parse_meta.header_len(), version_specific_meta);
2737 let action = ForwardingAction::DropWithIcmpError(IcmpErrorSender {
2738 err,
2739 src_ip,
2740 dst_ip,
2741 frame_dst,
2742 device: inbound_device,
2743 meta: parse_meta,
2744 marks: packet_meta.marks,
2745 });
2746 packet_meta.acknowledge_drop();
2747 return action;
2748 }
2749
2750 trace!("determine_ip_packet_forwarding_action: adequate TTL");
2751
2752 let maybe_ipv6_packet_action = I::map_ip_in(
2758 &packet,
2759 |_packet| None,
2760 |packet| {
2761 Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
2762 },
2763 );
2764 match maybe_ipv6_packet_action {
2765 None => {} Some(Ipv6PacketAction::_Discard) => {
2767 core_ctx.increment_both(inbound_device, |c| {
2768 #[derive(GenericOverIp)]
2769 #[generic_over_ip(I, Ip)]
2770 struct InCounters<'a, I: IpLayerIpExt>(
2771 &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<Counter>,
2772 );
2773 I::map_ip_in::<_, _>(
2774 InCounters(&c.version_rx),
2775 |_counters| {
2776 unreachable!(
2777 "`I` must be `Ipv6` because we're handling IPv6 extension headers"
2778 )
2779 },
2780 |InCounters(counters)| &counters.extension_header_discard,
2781 )
2782 });
2783 trace!(
2784 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
2785 discarding packet"
2786 );
2787 packet_meta.acknowledge_drop();
2788 return ForwardingAction::SilentlyDrop;
2789 }
2790 Some(Ipv6PacketAction::Continue) => {
2791 trace!(
2792 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
2793 forwarding packet"
2794 );
2795 }
2796 Some(Ipv6PacketAction::ProcessFragment) => {
2797 unreachable!(
2798 "When forwarding packets, we should only ever look at the hop by hop \
2799 options extension header (if present)"
2800 )
2801 }
2802 };
2803
2804 match core_ctx.filter_handler().forwarding_hook(
2805 I::as_filter_packet(&mut packet),
2806 inbound_device,
2807 outbound_device,
2808 &mut packet_meta,
2809 ) {
2810 filter::Verdict::Drop => {
2811 packet_meta.acknowledge_drop();
2812 trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
2813 return ForwardingAction::SilentlyDrop;
2814 }
2815 filter::Verdict::Accept(()) => {}
2816 }
2817
2818 packet.set_ttl(ttl - 1);
2819 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
2820 ForwardingAction::Forward(IpPacketForwarder {
2821 inbound_device,
2822 outbound_device,
2823 packet_meta,
2824 src_ip,
2825 dst_ip,
2826 destination,
2827 proto,
2828 parse_meta,
2829 frame_dst,
2830 })
2831}
2832
2833pub(crate) fn send_ip_frame<I, CC, BC, S>(
2834 core_ctx: &mut CC,
2835 bindings_ctx: &mut BC,
2836 device: &CC::DeviceId,
2837 destination: IpPacketDestination<I, &CC::DeviceId>,
2838 mut body: S,
2839 mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2840 limit_mtu: Mtu,
2841) -> Result<(), IpSendFrameError<S>>
2842where
2843 I: IpLayerIpExt,
2844 BC: FilterBindingsContext + TxMetadataBindingsTypes,
2845 CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
2846 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>,
2847{
2848 let (verdict, proof) = core_ctx.filter_handler().egress_hook(
2849 bindings_ctx,
2850 &mut body,
2851 device,
2852 &mut packet_metadata,
2853 );
2854 match verdict {
2855 filter::Verdict::Drop => {
2856 packet_metadata.acknowledge_drop();
2857 return Ok(());
2858 }
2859 filter::Verdict::Accept(()) => {}
2860 }
2861
2862 let (conntrack_connection_and_direction, tx_metadata, marks) = packet_metadata.into_parts();
2866 let conntrack_entry = if device.is_loopback() {
2867 conntrack_connection_and_direction
2868 .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
2869 } else {
2870 None
2871 };
2872 let device_ip_layer_metadata = DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks };
2873
2874 if !device.is_loopback()
2878 && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
2879 || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
2880 {
2881 core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
2882 return Err(IpSendFrameError {
2883 serializer: body,
2884 error: IpSendFrameErrorReason::IllegalLoopbackAddress,
2885 });
2886 }
2887
2888 let mtu = limit_mtu.min(core_ctx.get_mtu(device));
2890
2891 let body = body.with_size_limit(mtu.into());
2892
2893 let fits_mtu =
2894 match body.serialize_new_buf(PacketConstraints::UNCONSTRAINED, AlwaysFailBufferAlloc) {
2895 Err(SerializeError::Alloc(())) => true,
2898 Err(SerializeError::SizeLimitExceeded) => false,
2900 };
2901
2902 if fits_mtu {
2903 return core_ctx
2904 .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
2905 .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
2906 serializer: serializer.into_inner(),
2907 error: error.into(),
2908 });
2909 }
2910
2911 core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
2914
2915 let mut device_ip_layer_metadata = Some(device_ip_layer_metadata);
2917 let body = body.into_inner();
2918 let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
2919 Ok(mut fragmenter) => loop {
2920 let (fragment, has_more) = match fragmenter.next() {
2921 None => break Ok(()),
2922 Some(f) => f,
2923 };
2924
2925 let device_ip_layer_metadata = if has_more {
2930 let device_ip_layer_metadata = device_ip_layer_metadata.as_ref().unwrap();
2932 DeviceIpLayerMetadata {
2933 conntrack_entry: device_ip_layer_metadata.conntrack_entry.clone(),
2934 tx_metadata: Default::default(),
2935 marks: device_ip_layer_metadata.marks,
2936 }
2937 } else {
2938 device_ip_layer_metadata.take().unwrap()
2940 };
2941
2942 match core_ctx.send_ip_frame(
2943 bindings_ctx,
2944 device,
2945 destination.clone(),
2946 device_ip_layer_metadata,
2947 fragment,
2948 proof.clone_for_fragmentation(),
2949 ) {
2950 Ok(()) => {
2951 core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
2952 }
2953 Err(ErrorAndSerializer { serializer: _, error }) => {
2954 core_ctx
2955 .increment_both(device, |c| &c.fragmentation.error_fragmented_serializer);
2956 break Err(error);
2957 }
2958 }
2959 },
2960 Err(e) => {
2961 core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
2962 Err(SendFrameErrorReason::SizeConstraintsViolation)
2963 }
2964 };
2965 result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
2966}
2967
2968struct AlwaysFailBufferAlloc;
2973
2974impl LayoutBufferAlloc<Never> for AlwaysFailBufferAlloc {
2975 type Error = ();
2976 fn layout_alloc(
2977 self,
2978 _prefix: usize,
2979 _body: usize,
2980 _suffix: usize,
2981 ) -> Result<Never, Self::Error> {
2982 Err(())
2983 }
2984}
2985
2986macro_rules! drop_packet_and_undo_parse {
2995 ($packet:expr, $buffer:expr) => {{
2996 let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
2997 $buffer.undo_parse(meta);
2998 (src_ip, dst_ip, proto, meta)
2999 }};
3000}
3001
3002enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
3005 Done,
3008
3009 NotNeeded(I::Packet<&'a mut [u8]>),
3012
3013 Reassembled(Vec<u8>),
3016}
3017
3018fn process_fragment<'a, I, CC, BC>(
3024 core_ctx: &mut CC,
3025 bindings_ctx: &mut BC,
3026 device: &CC::DeviceId,
3027 packet: I::Packet<&'a mut [u8]>,
3028) -> ProcessFragmentResult<'a, I>
3029where
3030 I: IpLayerIpExt,
3031 for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3032 CC: IpLayerIngressContext<I, BC>,
3033 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3034{
3035 match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3036 FragmentProcessingState::NotNeeded(packet) => {
3038 trace!("receive_ip_packet: not fragmented");
3039 ProcessFragmentResult::NotNeeded(packet)
3040 }
3041 FragmentProcessingState::Ready { key, packet_len } => {
3043 trace!("receive_ip_packet: fragmented, ready for reassembly");
3044 let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3046
3047 let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3049 core_ctx,
3050 bindings_ctx,
3051 &key,
3052 buffer.buffer_view_mut(),
3053 ) {
3054 Ok(()) => ProcessFragmentResult::Reassembled(buffer.into_inner()),
3056 Err(e) => {
3057 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3058 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3059 ProcessFragmentResult::Done
3060 }
3061 };
3062 reassemble_result
3063 }
3064 FragmentProcessingState::NeedMoreFragments => {
3067 core_ctx.increment_both(device, |c| &c.need_more_fragments);
3068 trace!("receive_ip_packet: fragmented, need more before reassembly");
3069 ProcessFragmentResult::Done
3070 }
3071 FragmentProcessingState::InvalidFragment => {
3073 core_ctx.increment_both(device, |c| &c.invalid_fragment);
3074 trace!("receive_ip_packet: fragmented, invalid");
3075 ProcessFragmentResult::Done
3076 }
3077 FragmentProcessingState::OutOfMemory => {
3078 core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3079 trace!("receive_ip_packet: fragmented, dropped because OOM");
3080 ProcessFragmentResult::Done
3081 }
3082 }
3083}
3084
3085macro_rules! try_parse_ip_packet {
3095 ($buffer:expr) => {{
3096 let p_len = $buffer.prefix_len();
3097 let s_len = $buffer.suffix_len();
3098
3099 let result = $buffer.parse_mut();
3100
3101 if let Err(err) = result {
3102 let n_p_len = $buffer.prefix_len();
3104 let n_s_len = $buffer.suffix_len();
3105
3106 if p_len > n_p_len {
3107 $buffer.grow_front(p_len - n_p_len);
3108 }
3109
3110 if s_len > n_s_len {
3111 $buffer.grow_back(s_len - n_s_len);
3112 }
3113
3114 Err(err)
3115 } else {
3116 result
3117 }
3118 }};
3119}
3120
3121macro_rules! clone_packet_for_mcast_forwarding {
3139 {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3140 let mut $new_data = $packet.to_vec();
3141 let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3142 let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3143 };
3144}
3145
3146pub fn receive_ipv4_packet<
3151 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3152 B: BufferMut,
3153 CC: IpLayerIngressContext<Ipv4, BC>,
3154>(
3155 core_ctx: &mut CC,
3156 bindings_ctx: &mut BC,
3157 device: &CC::DeviceId,
3158 frame_dst: Option<FrameDestination>,
3159 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3160 buffer: B,
3161) {
3162 if !core_ctx.is_ip_device_enabled(&device) {
3163 return;
3164 }
3165
3166 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3169
3170 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3171 trace!("receive_ip_packet({device:?})");
3172
3173 let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3174 Ok(packet) => packet,
3175 Err(IpParseError::ParameterProblem {
3184 src_ip,
3185 dst_ip,
3186 code,
3187 pointer,
3188 must_send_icmp,
3189 header_len,
3190 action,
3191 }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
3192 core_ctx.increment_both(device, |c| &c.parameter_problem);
3193 assert!(!action.should_send_icmp_to_multicast());
3195 let dst_ip = match SpecifiedAddr::new(dst_ip) {
3196 Some(ip) => ip,
3197 None => {
3198 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3199 debug!(
3200 "receive_ipv4_packet: Received packet with unspecified destination IP address; dropping"
3201 );
3202 return;
3203 }
3204 };
3205 let src_ip = match Ipv4SourceAddr::new(src_ip) {
3206 None => {
3207 core_ctx.increment_both(device, |c| &c.invalid_source);
3208 return;
3209 }
3210 Some(Ipv4SourceAddr::Unspecified) => {
3211 core_ctx.increment_both(device, |c| &c.unspecified_source);
3212 return;
3213 }
3214 Some(Ipv4SourceAddr::Specified(src_ip)) => src_ip,
3215 };
3216 IcmpErrorHandler::<Ipv4, _>::send_icmp_error_message(
3217 core_ctx,
3218 bindings_ctx,
3219 device,
3220 frame_dst,
3221 src_ip,
3222 dst_ip,
3223 buffer,
3224 Icmpv4Error {
3225 kind: Icmpv4ErrorKind::ParameterProblem {
3226 code,
3227 pointer,
3228 fragment_type: Ipv4FragmentType::InitialFragment,
3231 },
3232 header_len,
3233 },
3234 &device_ip_layer_metadata.marks,
3235 );
3236 return;
3237 }
3238 _ => return, };
3240
3241 if packet.src_ipv4().is_none() {
3245 debug!(
3246 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3247 packet.src_ip()
3248 );
3249 core_ctx.increment_both(device, |c| &c.invalid_source);
3250 return;
3251 };
3252 if !packet.dst_ip().is_specified() {
3253 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3254 debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3255 return;
3256 };
3257
3258 let mut packet = match process_fragment(core_ctx, bindings_ctx, device, packet) {
3271 ProcessFragmentResult::Done => return,
3272 ProcessFragmentResult::NotNeeded(packet) => packet,
3273 ProcessFragmentResult::Reassembled(buf) => {
3274 let buf = Buf::new(buf, ..);
3275 buffer = packet::Either::B(buf);
3276
3277 match buffer.parse_mut() {
3278 Ok(packet) => packet,
3279 Err(err) => {
3280 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3281 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3282 return;
3283 }
3284 }
3285 }
3286 };
3287
3288 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3291 core_ctx,
3292 device,
3293 device_ip_layer_metadata,
3294 );
3295 let mut filter = core_ctx.filter_handler();
3296 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3297 IngressVerdict::Verdict(filter::Verdict::Accept(())) => {}
3298 IngressVerdict::Verdict(filter::Verdict::Drop) => {
3299 packet_metadata.acknowledge_drop();
3300 return;
3301 }
3302 IngressVerdict::TransparentLocalDelivery { addr, port } => {
3303 drop(filter);
3306
3307 let Some(addr) = SpecifiedAddr::new(addr) else {
3308 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3309 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3310 return;
3311 };
3312
3313 let receive_meta = ReceiveIpPacketMeta {
3314 broadcast: None,
3318 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3319 };
3320
3321 dispatch_receive_ipv4_packet(
3325 core_ctx,
3326 bindings_ctx,
3327 device,
3328 frame_dst,
3329 packet,
3330 packet_metadata,
3331 receive_meta,
3332 )
3333 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3334 return;
3335 }
3336 }
3337 drop(filter);
3340
3341 let Some(src_ip) = packet.src_ipv4() else {
3342 core_ctx.increment_both(device, |c| &c.invalid_source);
3343 debug!(
3344 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3345 packet.src_ip()
3346 );
3347 return;
3348 };
3349
3350 let action = receive_ipv4_packet_action(
3351 core_ctx,
3352 bindings_ctx,
3353 device,
3354 &packet,
3355 frame_dst,
3356 &packet_metadata.marks,
3357 );
3358 match action {
3359 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3360 let mut packet_metadata = Some(packet_metadata);
3367 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3368 clone_packet_for_mcast_forwarding! {
3369 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3370 };
3371 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3372 core_ctx,
3373 copy_of_packet,
3374 packet_metadata.take().unwrap_or_default(),
3375 Some(*min_ttl),
3376 device,
3377 &output_interface,
3378 IpPacketDestination::from_addr(dst_ip),
3379 frame_dst,
3380 src_ip,
3381 dst_ip,
3382 )
3383 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3384 }
3385
3386 if let Some(address_status) = address_status {
3388 let receive_meta = ReceiveIpPacketMeta {
3389 broadcast: address_status.to_broadcast_marker(),
3390 transparent_override: None,
3391 };
3392 dispatch_receive_ipv4_packet(
3393 core_ctx,
3394 bindings_ctx,
3395 device,
3396 frame_dst,
3397 packet,
3398 packet_metadata.take().unwrap_or_default(),
3399 receive_meta,
3400 )
3401 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3402 }
3403 }
3404 ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
3405 match internal_forwarding {
3408 InternalForwarding::Used(outbound_device) => {
3409 core_ctx.increment_both(device, |c| &c.forward);
3410 match core_ctx.filter_handler().forwarding_hook(
3411 &mut packet,
3412 device,
3413 &outbound_device,
3414 &mut packet_metadata,
3415 ) {
3416 filter::Verdict::Drop => {
3417 packet_metadata.acknowledge_drop();
3418 return;
3419 }
3420 filter::Verdict::Accept(()) => {}
3421 }
3422 }
3423 InternalForwarding::NotUsed => {}
3424 }
3425
3426 let receive_meta = ReceiveIpPacketMeta {
3427 broadcast: address_status.to_broadcast_marker(),
3428 transparent_override: None,
3429 };
3430 dispatch_receive_ipv4_packet(
3431 core_ctx,
3432 bindings_ctx,
3433 device,
3434 frame_dst,
3435 packet,
3436 packet_metadata,
3437 receive_meta,
3438 )
3439 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3440 }
3441 ReceivePacketAction::Forward {
3442 original_dst,
3443 dst: Destination { device: dst_device, next_hop },
3444 } => {
3445 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3446 core_ctx,
3447 packet,
3448 packet_metadata,
3449 None,
3450 device,
3451 &dst_device,
3452 IpPacketDestination::from_next_hop(next_hop, original_dst),
3453 frame_dst,
3454 src_ip,
3455 original_dst,
3456 )
3457 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3458 }
3459 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3460 use packet_formats::ipv4::Ipv4Header as _;
3461 core_ctx.increment_both(device, |c| &c.no_route_to_host);
3462 debug!("received IPv4 packet with no known route to destination {}", dst_ip);
3463 let fragment_type = packet.fragment_type();
3464 let (_, _, proto, meta): (Ipv4Addr, Ipv4Addr, _, _) =
3465 drop_packet_and_undo_parse!(packet, buffer);
3466 let marks = packet_metadata.marks;
3467 packet_metadata.acknowledge_drop();
3468 let src_ip = match src_ip {
3469 Ipv4SourceAddr::Unspecified => {
3470 core_ctx.increment_both(device, |c| &c.unspecified_source);
3471 return;
3472 }
3473 Ipv4SourceAddr::Specified(src_ip) => src_ip,
3474 };
3475 IcmpErrorHandler::<Ipv4, _>::send_icmp_error_message(
3476 core_ctx,
3477 bindings_ctx,
3478 device,
3479 frame_dst,
3480 src_ip,
3481 dst_ip,
3482 buffer,
3483 Icmpv4Error {
3484 kind: Icmpv4ErrorKind::NetUnreachable { proto, fragment_type },
3485 header_len: meta.header_len(),
3486 },
3487 &marks,
3488 );
3489 }
3490 ReceivePacketAction::Drop { reason } => {
3491 let src_ip = packet.src_ip();
3492 let dst_ip = packet.dst_ip();
3493 packet_metadata.acknowledge_drop();
3494 core_ctx.increment_both(device, |c| &c.dropped);
3495 debug!(
3496 "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
3497 {device:?}: {reason:?}",
3498 );
3499 }
3500 }
3501}
3502
3503pub fn receive_ipv6_packet<
3508 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3509 B: BufferMut,
3510 CC: IpLayerIngressContext<Ipv6, BC>,
3511>(
3512 core_ctx: &mut CC,
3513 bindings_ctx: &mut BC,
3514 device: &CC::DeviceId,
3515 frame_dst: Option<FrameDestination>,
3516 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3517 buffer: B,
3518) {
3519 if !core_ctx.is_ip_device_enabled(&device) {
3520 return;
3521 }
3522
3523 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3526
3527 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3528 trace!("receive_ipv6_packet({:?})", device);
3529
3530 let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
3531 Ok(packet) => packet,
3532 Err(IpParseError::ParameterProblem {
3538 src_ip,
3539 dst_ip,
3540 code,
3541 pointer,
3542 must_send_icmp,
3543 header_len: _,
3544 action,
3545 }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
3546 core_ctx.increment_both(device, |c| &c.parameter_problem);
3547 let dst_ip = match SpecifiedAddr::new(dst_ip) {
3548 Some(ip) => ip,
3549 None => {
3550 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3551 debug!(
3552 "receive_ipv6_packet: Received packet with unspecified destination IP address; dropping"
3553 );
3554 return;
3555 }
3556 };
3557 let src_ip = match Ipv6SourceAddr::new(src_ip) {
3558 None => {
3559 core_ctx.increment_both(device, |c| &c.invalid_source);
3560 return;
3561 }
3562 Some(Ipv6SourceAddr::Unspecified) => {
3563 core_ctx.increment_both(device, |c| &c.unspecified_source);
3564 return;
3565 }
3566 Some(Ipv6SourceAddr::Unicast(src_ip)) => src_ip,
3567 };
3568 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3569 core_ctx,
3570 bindings_ctx,
3571 device,
3572 frame_dst,
3573 *src_ip,
3574 dst_ip,
3575 buffer,
3576 Icmpv6ErrorKind::ParameterProblem {
3577 code,
3578 pointer,
3579 allow_dst_multicast: action.should_send_icmp_to_multicast(),
3580 },
3581 &device_ip_layer_metadata.marks,
3582 );
3583 return;
3584 }
3585 _ => return, };
3587
3588 trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
3589
3590 if packet.src_ipv6().is_none() {
3596 debug!(
3597 "receive_ipv6_packet: received packet from invalid source {}; dropping",
3598 packet.src_ip()
3599 );
3600 core_ctx.increment_both(device, |c| &c.invalid_source);
3601 return;
3602 };
3603 if !packet.dst_ip().is_specified() {
3604 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3605 debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
3606 return;
3607 };
3608
3609 let (mut packet, delivery_extension_header_action) =
3620 match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
3621 Ipv6PacketAction::_Discard => {
3622 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3623 trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
3624 return;
3625 }
3626 Ipv6PacketAction::Continue => {
3627 trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
3628 (packet, Some(Ipv6PacketAction::Continue))
3629 }
3630 Ipv6PacketAction::ProcessFragment => {
3631 trace!(
3632 "receive_ipv6_packet: handled IPv6 extension headers: handling \
3633 fragmented packet"
3634 );
3635
3636 match process_fragment(core_ctx, bindings_ctx, device, packet) {
3648 ProcessFragmentResult::Done => return,
3649 ProcessFragmentResult::NotNeeded(packet) => {
3650 (packet, Some(Ipv6PacketAction::Continue))
3665 }
3666 ProcessFragmentResult::Reassembled(buf) => {
3667 let buf = Buf::new(buf, ..);
3668 buffer = packet::Either::B(buf);
3669
3670 match buffer.parse_mut() {
3671 Ok(packet) => (packet, None),
3672 Err(err) => {
3673 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3674 debug!(
3675 "receive_ip_packet: fragmented, failed to reassemble: {:?}",
3676 err
3677 );
3678 return;
3679 }
3680 }
3681 }
3682 }
3683 }
3684 };
3685
3686 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3687 core_ctx,
3688 device,
3689 device_ip_layer_metadata,
3690 );
3691 let mut filter = core_ctx.filter_handler();
3692
3693 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3694 IngressVerdict::Verdict(filter::Verdict::Accept(())) => {}
3695 IngressVerdict::Verdict(filter::Verdict::Drop) => {
3696 packet_metadata.acknowledge_drop();
3697 return;
3698 }
3699 IngressVerdict::TransparentLocalDelivery { addr, port } => {
3700 drop(filter);
3703
3704 let Some(addr) = SpecifiedAddr::new(addr) else {
3705 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3706 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3707 return;
3708 };
3709
3710 let receive_meta = ReceiveIpPacketMeta {
3711 broadcast: None,
3712 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3713 };
3714
3715 dispatch_receive_ipv6_packet(
3719 core_ctx,
3720 bindings_ctx,
3721 device,
3722 frame_dst,
3723 packet,
3724 packet_metadata,
3725 receive_meta,
3726 )
3727 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3728 return;
3729 }
3730 }
3731 drop(filter);
3734
3735 let Some(src_ip) = packet.src_ipv6() else {
3736 debug!(
3737 "receive_ipv6_packet: received packet from invalid source {}; dropping",
3738 packet.src_ip()
3739 );
3740 core_ctx.increment_both(device, |c| &c.invalid_source);
3741 return;
3742 };
3743
3744 match receive_ipv6_packet_action(
3745 core_ctx,
3746 bindings_ctx,
3747 device,
3748 &packet,
3749 frame_dst,
3750 &packet_metadata.marks,
3751 ) {
3752 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3753 let mut packet_metadata = Some(packet_metadata);
3760 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3761 clone_packet_for_mcast_forwarding! {
3762 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3763 };
3764 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
3765 core_ctx,
3766 copy_of_packet,
3767 packet_metadata.take().unwrap_or_default(),
3768 Some(*min_ttl),
3769 device,
3770 &output_interface,
3771 IpPacketDestination::from_addr(dst_ip),
3772 frame_dst,
3773 src_ip,
3774 dst_ip,
3775 )
3776 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3777 }
3778
3779 if let Some(_) = address_status {
3781 let receive_meta =
3782 ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
3783
3784 dispatch_receive_ipv6_packet(
3785 core_ctx,
3786 bindings_ctx,
3787 device,
3788 frame_dst,
3789 packet,
3790 packet_metadata.take().unwrap_or_default(),
3791 receive_meta,
3792 )
3793 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3794 }
3795 }
3796 ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
3797 trace!("receive_ipv6_packet: delivering locally");
3798
3799 let action = if let Some(action) = delivery_extension_header_action {
3800 action
3801 } else {
3802 ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
3803 };
3804 match action {
3805 Ipv6PacketAction::_Discard => {
3806 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3807 trace!(
3808 "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
3809 );
3810 packet_metadata.acknowledge_drop();
3811 }
3812 Ipv6PacketAction::Continue => {
3813 trace!(
3814 "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
3815 );
3816
3817 match internal_forwarding {
3820 InternalForwarding::Used(outbound_device) => {
3821 core_ctx.increment_both(device, |c| &c.forward);
3822 match core_ctx.filter_handler().forwarding_hook(
3823 &mut packet,
3824 device,
3825 &outbound_device,
3826 &mut packet_metadata,
3827 ) {
3828 filter::Verdict::Drop => {
3829 packet_metadata.acknowledge_drop();
3830 return;
3831 }
3832 filter::Verdict::Accept(()) => {}
3833 }
3834 }
3835 InternalForwarding::NotUsed => {}
3836 }
3837
3838 let meta = ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
3839
3840 dispatch_receive_ipv6_packet(
3845 core_ctx,
3846 bindings_ctx,
3847 device,
3848 frame_dst,
3849 packet,
3850 packet_metadata,
3851 meta,
3852 )
3853 .unwrap_or_else(|err| {
3854 err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer)
3855 });
3856 }
3857 Ipv6PacketAction::ProcessFragment => {
3858 debug!("receive_ipv6_packet: found fragment header after reassembly; dropping");
3859 packet_metadata.acknowledge_drop();
3860 }
3861 }
3862 }
3863 ReceivePacketAction::Forward {
3864 original_dst,
3865 dst: Destination { device: dst_device, next_hop },
3866 } => {
3867 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
3868 core_ctx,
3869 packet,
3870 packet_metadata,
3871 None,
3872 device,
3873 &dst_device,
3874 IpPacketDestination::from_next_hop(next_hop, original_dst),
3875 frame_dst,
3876 src_ip,
3877 original_dst,
3878 )
3879 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3880 }
3881 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3882 core_ctx.increment_both(device, |c| &c.no_route_to_host);
3883 let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
3884 drop_packet_and_undo_parse!(packet, buffer);
3885 debug!("received IPv6 packet with no known route to destination {}", dst_ip);
3886 let marks = packet_metadata.marks;
3887 packet_metadata.acknowledge_drop();
3888
3889 let src_ip = match src_ip {
3890 Ipv6SourceAddr::Unspecified => {
3891 core_ctx.increment_both(device, |c| &c.unspecified_source);
3892 return;
3893 }
3894 Ipv6SourceAddr::Unicast(src_ip) => src_ip,
3895 };
3896 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3897 core_ctx,
3898 bindings_ctx,
3899 device,
3900 frame_dst,
3901 *src_ip,
3902 dst_ip,
3903 buffer,
3904 Icmpv6ErrorKind::NetUnreachable { proto, header_len: meta.header_len() },
3905 &marks,
3906 );
3907 }
3908 ReceivePacketAction::Drop { reason } => {
3909 core_ctx.increment_both(device, |c| &c.dropped);
3910 let src_ip = packet.src_ip();
3911 let dst_ip = packet.dst_ip();
3912 packet_metadata.acknowledge_drop();
3913 debug!(
3914 "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
3915 {device:?}: {reason:?}",
3916 );
3917 }
3918 }
3919}
3920
3921#[derive(Debug, PartialEq)]
3923pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
3924 Deliver {
3926 address_status: I::AddressStatus,
3928 internal_forwarding: InternalForwarding<DeviceId>,
3931 },
3932
3933 Forward {
3935 original_dst: SpecifiedAddr<I::Addr>,
3937 dst: Destination<I::Addr, DeviceId>,
3939 },
3940
3941 MulticastForward {
3949 targets: MulticastRouteTargets<DeviceId>,
3951 address_status: Option<I::AddressStatus>,
3954 dst_ip: SpecifiedAddr<I::Addr>,
3956 },
3957
3958 SendNoRouteToDest {
3964 dst: SpecifiedAddr<I::Addr>,
3966 },
3967
3968 #[allow(missing_docs)]
3972 Drop { reason: DropReason },
3973}
3974
3975fn choose_highest_priority_address_status<I: IpLayerIpExt>(
3978 address_statuses: impl Iterator<Item = I::AddressStatus>,
3979) -> Option<I::AddressStatus> {
3980 address_statuses.max_by_key(|status| {
3981 #[derive(GenericOverIp)]
3982 #[generic_over_ip(I, Ip)]
3983 struct Wrap<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
3984 I::map_ip_in(
3985 Wrap(status),
3986 |Wrap(v4_status)| match v4_status {
3987 Ipv4PresentAddressStatus::UnicastTentative => 0,
3988 _ => 1,
3989 },
3990 |Wrap(v6_status)| match v6_status {
3991 Ipv6PresentAddressStatus::UnicastTentative => 0,
3992 _ => 1,
3993 },
3994 )
3995 })
3996}
3997
3998#[derive(Debug, PartialEq)]
4000pub enum DropReason {
4001 Tentative,
4003 UnspecifiedDestination,
4005 ForwardUnspecifiedSource,
4007 ForwardLinkLocal,
4009 ForwardingDisabledInboundIface,
4012 MulticastNoInterest,
4018}
4019
4020pub fn receive_ipv4_packet_action<BC, CC, B>(
4022 core_ctx: &mut CC,
4023 bindings_ctx: &mut BC,
4024 device: &CC::DeviceId,
4025 packet: &Ipv4Packet<B>,
4026 frame_dst: Option<FrameDestination>,
4027 marks: &Marks,
4028) -> ReceivePacketAction<Ipv4, CC::DeviceId>
4029where
4030 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
4031 CC: IpLayerContext<Ipv4, BC>,
4032 B: SplitByteSlice,
4033{
4034 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4035 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4036 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4037 };
4038
4039 let highest_priority = if device.is_loopback() {
4052 core_ctx.with_address_statuses(dst_ip, |it| {
4053 let it = it.map(|(_device, status)| status);
4054 choose_highest_priority_address_status::<Ipv4>(it)
4055 })
4056 } else {
4057 core_ctx.address_status_for_device(dst_ip, device).into_present()
4058 };
4059 match highest_priority {
4060 Some(
4061 address_status @ (Ipv4PresentAddressStatus::UnicastAssigned
4062 | Ipv4PresentAddressStatus::LoopbackSubnet),
4063 ) => {
4064 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4065 ReceivePacketAction::Deliver {
4066 address_status,
4067 internal_forwarding: InternalForwarding::NotUsed,
4068 }
4069 }
4070 Some(Ipv4PresentAddressStatus::UnicastTentative) => {
4071 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4077 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4078 }
4079
4080 Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4081 receive_ip_multicast_packet_action(
4082 core_ctx,
4083 bindings_ctx,
4084 device,
4085 packet,
4086 Some(address_status),
4087 dst_ip,
4088 frame_dst,
4089 )
4090 }
4091 Some(
4092 address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4093 | Ipv4PresentAddressStatus::SubnetBroadcast),
4094 ) => {
4095 core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
4096 ReceivePacketAction::Deliver {
4097 address_status,
4098 internal_forwarding: InternalForwarding::NotUsed,
4099 }
4100 }
4101 None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4102 core_ctx,
4103 bindings_ctx,
4104 dst_ip,
4105 device,
4106 packet,
4107 frame_dst,
4108 marks,
4109 ),
4110 }
4111}
4112
4113pub fn receive_ipv6_packet_action<BC, CC, B>(
4115 core_ctx: &mut CC,
4116 bindings_ctx: &mut BC,
4117 device: &CC::DeviceId,
4118 packet: &Ipv6Packet<B>,
4119 frame_dst: Option<FrameDestination>,
4120 marks: &Marks,
4121) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4122where
4123 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4124 CC: IpLayerContext<Ipv6, BC>,
4125 B: SplitByteSlice,
4126{
4127 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4128 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4129 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4130 };
4131
4132 let highest_priority = if device.is_loopback() {
4145 core_ctx.with_address_statuses(dst_ip, |it| {
4146 let it = it.map(|(_device, status)| status);
4147 choose_highest_priority_address_status::<Ipv6>(it)
4148 })
4149 } else {
4150 core_ctx.address_status_for_device(dst_ip, device).into_present()
4151 };
4152 match highest_priority {
4153 Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
4154 receive_ip_multicast_packet_action(
4155 core_ctx,
4156 bindings_ctx,
4157 device,
4158 packet,
4159 Some(address_status),
4160 dst_ip,
4161 frame_dst,
4162 )
4163 }
4164 Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
4165 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4166 ReceivePacketAction::Deliver {
4167 address_status,
4168 internal_forwarding: InternalForwarding::NotUsed,
4169 }
4170 }
4171 Some(Ipv6PresentAddressStatus::UnicastTentative) => {
4172 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4203 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4204 }
4205 None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
4206 core_ctx,
4207 bindings_ctx,
4208 dst_ip,
4209 device,
4210 packet,
4211 frame_dst,
4212 marks,
4213 ),
4214 }
4215}
4216
4217fn receive_ip_multicast_packet_action<
4220 I: IpLayerIpExt,
4221 B: SplitByteSlice,
4222 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4223 CC: IpLayerContext<I, BC>,
4224>(
4225 core_ctx: &mut CC,
4226 bindings_ctx: &mut BC,
4227 device: &CC::DeviceId,
4228 packet: &I::Packet<B>,
4229 address_status: Option<I::AddressStatus>,
4230 dst_ip: SpecifiedAddr<I::Addr>,
4231 frame_dst: Option<FrameDestination>,
4232) -> ReceivePacketAction<I, CC::DeviceId> {
4233 let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
4234 core_ctx,
4235 bindings_ctx,
4236 packet,
4237 device,
4238 frame_dst,
4239 );
4240 match (targets, address_status) {
4241 (Some(targets), address_status) => {
4242 if address_status.is_some() {
4243 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4244 }
4245 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
4246 }
4247 (None, Some(address_status)) => {
4248 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4251 ReceivePacketAction::Deliver {
4252 address_status,
4253 internal_forwarding: InternalForwarding::NotUsed,
4254 }
4255 }
4256 (None, None) => {
4257 core_ctx.increment_both(device, |c| &c.multicast_no_interest);
4266 ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
4267 }
4268 }
4269}
4270
4271fn receive_ip_packet_action_common<
4274 I: IpLayerIpExt,
4275 B: SplitByteSlice,
4276 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4277 CC: IpLayerContext<I, BC>,
4278>(
4279 core_ctx: &mut CC,
4280 bindings_ctx: &mut BC,
4281 dst_ip: SpecifiedAddr<I::Addr>,
4282 device_id: &CC::DeviceId,
4283 packet: &I::Packet<B>,
4284 frame_dst: Option<FrameDestination>,
4285 marks: &Marks,
4286) -> ReceivePacketAction<I, CC::DeviceId> {
4287 if dst_ip.is_multicast() {
4288 return receive_ip_multicast_packet_action(
4289 core_ctx,
4290 bindings_ctx,
4291 device_id,
4292 packet,
4293 None,
4294 dst_ip,
4295 frame_dst,
4296 );
4297 }
4298
4299 if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
4301 core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
4314 return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
4315 }
4316 let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
4323 return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
4324 };
4325
4326 if let Some(dst_ip) = NonMappedAddr::new(dst_ip).and_then(NonMulticastAddr::new) {
4333 if let Some((outbound_device, address_status)) =
4334 get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
4335 {
4336 return ReceivePacketAction::Deliver {
4337 address_status,
4338 internal_forwarding: InternalForwarding::Used(outbound_device),
4339 };
4340 }
4341 }
4342
4343 if I::map_ip_in(
4358 &packet,
4359 |_| false,
4360 |packet| packet.src_ip().is_link_local() || packet.dst_ip().is_link_local(),
4361 ) {
4362 return ReceivePacketAction::Drop { reason: DropReason::ForwardLinkLocal };
4363 }
4364
4365 match lookup_route_table(
4366 core_ctx,
4367 *dst_ip,
4368 RuleInput {
4369 packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
4370 marks,
4371 },
4372 ) {
4373 Some(dst) => {
4374 core_ctx.increment_both(device_id, |c| &c.forward);
4375 ReceivePacketAction::Forward { original_dst: dst_ip, dst }
4376 }
4377 None => {
4378 core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
4379 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
4380 }
4381 }
4382}
4383
4384fn lookup_route_table<I: IpLayerIpExt, CC: IpStateContext<I>>(
4386 core_ctx: &mut CC,
4387 dst_ip: I::Addr,
4388 rule_input: RuleInput<'_, I, CC::DeviceId>,
4389) -> Option<Destination<I::Addr, CC::DeviceId>> {
4390 let bound_device = match rule_input.packet_origin {
4391 PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
4392 PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
4393 };
4394 core_ctx.with_rules_table(|core_ctx, rules| {
4395 match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
4396 match table.lookup(core_ctx, bound_device, dst_ip) {
4397 Some(dst) => ControlFlow::Break(Some(dst)),
4398 None => ControlFlow::Continue(()),
4399 }
4400 }) {
4401 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
4402 inner: dst,
4403 observed_source_address_matcher: _,
4404 })) => dst,
4405 ControlFlow::Break(RuleAction::Unreachable) => None,
4406 ControlFlow::Continue(RuleWalkInfo {
4407 inner: (),
4408 observed_source_address_matcher: _,
4409 }) => None,
4410 }
4411 })
4412}
4413
4414#[derive(Debug, Derivative, Clone)]
4416#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
4417pub enum IpPacketDestination<I: BroadcastIpExt, D> {
4418 Broadcast(I::BroadcastMarker),
4420
4421 Multicast(MulticastAddr<I::Addr>),
4423
4424 Neighbor(SpecifiedAddr<I::Addr>),
4427
4428 Loopback(D),
4431}
4432
4433impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
4434 pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
4436 match MulticastAddr::new(addr.into_addr()) {
4437 Some(mc_addr) => Self::Multicast(mc_addr),
4438 None => Self::Neighbor(addr),
4439 }
4440 }
4441
4442 pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
4444 match next_hop {
4445 NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
4446 NextHop::Gateway(gateway) => Self::Neighbor(gateway),
4447 NextHop::Broadcast(marker) => Self::Broadcast(marker),
4448 }
4449 }
4450}
4451
4452#[derive(Debug, Clone)]
4454pub struct SendIpPacketMeta<I: IpExt, D, Src> {
4455 pub device: D,
4457
4458 pub src_ip: Src,
4460
4461 pub dst_ip: SpecifiedAddr<I::Addr>,
4463
4464 pub destination: IpPacketDestination<I, D>,
4466
4467 pub proto: I::Proto,
4469
4470 pub ttl: Option<NonZeroU8>,
4474
4475 pub mtu: Mtu,
4480
4481 pub dscp_and_ecn: DscpAndEcn,
4483}
4484
4485impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4486 for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
4487{
4488 fn from(
4489 SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
4490 I,
4491 D,
4492 SpecifiedAddr<I::Addr>,
4493 >,
4494 ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
4495 SendIpPacketMeta {
4496 device,
4497 src_ip: Some(src_ip),
4498 dst_ip,
4499 destination,
4500 proto,
4501 ttl,
4502 mtu,
4503 dscp_and_ecn,
4504 }
4505 }
4506}
4507
4508pub trait IpLayerHandler<I: IpExt + FragmentationIpExt + FilterIpExt, BC>:
4514 DeviceIdContext<AnyDevice>
4515{
4516 fn send_ip_packet_from_device<S>(
4519 &mut self,
4520 bindings_ctx: &mut BC,
4521 meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4522 body: S,
4523 ) -> Result<(), IpSendFrameError<S>>
4524 where
4525 S: TransportPacketSerializer<I>,
4526 S::Buffer: BufferMut;
4527
4528 fn send_ip_frame<S>(
4535 &mut self,
4536 bindings_ctx: &mut BC,
4537 device: &Self::DeviceId,
4538 destination: IpPacketDestination<I, &Self::DeviceId>,
4539 body: S,
4540 ) -> Result<(), IpSendFrameError<S>>
4541 where
4542 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>;
4543}
4544
4545impl<
4546 I: IpLayerIpExt,
4547 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
4548 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4549> IpLayerHandler<I, BC> for CC
4550{
4551 fn send_ip_packet_from_device<S>(
4552 &mut self,
4553 bindings_ctx: &mut BC,
4554 meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4555 body: S,
4556 ) -> Result<(), IpSendFrameError<S>>
4557 where
4558 S: TransportPacketSerializer<I>,
4559 S::Buffer: BufferMut,
4560 {
4561 send_ip_packet_from_device(self, bindings_ctx, meta, body, IpLayerPacketMetadata::default())
4562 }
4563
4564 fn send_ip_frame<S>(
4565 &mut self,
4566 bindings_ctx: &mut BC,
4567 device: &Self::DeviceId,
4568 destination: IpPacketDestination<I, &Self::DeviceId>,
4569 body: S,
4570 ) -> Result<(), IpSendFrameError<S>>
4571 where
4572 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>,
4573 {
4574 send_ip_frame(
4575 self,
4576 bindings_ctx,
4577 device,
4578 destination,
4579 body,
4580 IpLayerPacketMetadata::default(),
4581 Mtu::no_limit(),
4582 )
4583 }
4584}
4585
4586pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
4593 core_ctx: &mut CC,
4594 bindings_ctx: &mut BC,
4595 meta: SendIpPacketMeta<
4596 I,
4597 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
4598 Option<SpecifiedAddr<I::Addr>>,
4599 >,
4600 body: S,
4601 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
4602) -> Result<(), IpSendFrameError<S>>
4603where
4604 I: IpLayerIpExt,
4605 BC: FilterBindingsContext + TxMetadataBindingsTypes,
4606 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4607 S: TransportPacketSerializer<I>,
4608 S::Buffer: BufferMut,
4609{
4610 let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
4611 meta;
4612 core_ctx.increment_both(device, |c| &c.send_ip_packet);
4613 let next_packet_id = gen_ip_packet_id(core_ctx);
4614 let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
4615 let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
4616 let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
4617
4618 #[derive(GenericOverIp)]
4619 #[generic_over_ip(I, Ip)]
4620 struct Wrap<'a, I: IpLayerIpExt> {
4621 builder: &'a mut I::PacketBuilder,
4622 next_packet_id: I::PacketId,
4623 }
4624
4625 I::map_ip::<_, ()>(
4626 Wrap { builder: &mut builder, next_packet_id },
4627 |Wrap { builder, next_packet_id }| {
4628 builder.id(next_packet_id);
4629 },
4630 |Wrap { builder: _, next_packet_id: () }| {
4631 },
4633 );
4634
4635 builder.set_dscp_and_ecn(dscp_and_ecn);
4636
4637 let ip_frame = builder.wrap_body(body);
4638 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
4639 .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
4640}
4641
4642pub trait FilterHandlerProvider<I: FilterIpExt, BT: FilterBindingsTypes>:
4644 IpDeviceAddressIdContext<I, DeviceId: filter::InterfaceProperties<BT::DeviceClass>>
4645{
4646 type Handler<'a>: filter::FilterHandler<I, BT, DeviceId = Self::DeviceId, WeakAddressId = Self::WeakAddressId>
4648 where
4649 Self: 'a;
4650
4651 fn filter_handler(&mut self) -> Self::Handler<'_>;
4653}
4654
4655#[cfg(any(test, feature = "testutils"))]
4656pub(crate) mod testutil {
4657 use super::*;
4658
4659 use netstack3_base::testutil::{FakeCoreCtx, FakeStrongDeviceId};
4660 use netstack3_base::{AssignedAddrIpExt, SendFrameContext, SendFrameError, SendableFrameMeta};
4661 use packet::Serializer;
4662
4663 #[derive(Debug, GenericOverIp)]
4665 #[generic_over_ip()]
4666 #[allow(missing_docs)]
4667 pub enum DualStackSendIpPacketMeta<D> {
4668 V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
4669 V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
4670 }
4671
4672 impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4673 for DualStackSendIpPacketMeta<D>
4674 {
4675 fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
4676 #[derive(GenericOverIp)]
4677 #[generic_over_ip(I, Ip)]
4678 struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
4679 use DualStackSendIpPacketMeta::*;
4680 I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
4681 }
4682 }
4683
4684 impl<I: IpExt, S, DeviceId, BC>
4685 SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
4686 for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
4687 {
4688 fn send_meta<SS>(
4689 self,
4690 core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
4691 bindings_ctx: &mut BC,
4692 frame: SS,
4693 ) -> Result<(), SendFrameError<SS>>
4694 where
4695 SS: Serializer,
4696 SS::Buffer: BufferMut,
4697 {
4698 SendFrameContext::send_frame(
4699 &mut core_ctx.frames,
4700 bindings_ctx,
4701 DualStackSendIpPacketMeta::from(self),
4702 frame,
4703 )
4704 }
4705 }
4706
4707 #[derive(Debug)]
4709 pub struct WrongIpVersion;
4710
4711 impl<D> DualStackSendIpPacketMeta<D> {
4712 pub fn try_as<I: IpExt>(
4715 &self,
4716 ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
4717 #[derive(GenericOverIp)]
4718 #[generic_over_ip(I, Ip)]
4719 struct Wrap<'a, I: IpExt, D>(
4720 Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
4721 );
4722 use DualStackSendIpPacketMeta::*;
4723 let Wrap(dual_stack) = I::map_ip(
4724 self,
4725 |value| {
4726 Wrap(match value {
4727 V4(meta) => Some(meta),
4728 V6(_) => None,
4729 })
4730 },
4731 |value| {
4732 Wrap(match value {
4733 V4(_) => None,
4734 V6(meta) => Some(meta),
4735 })
4736 },
4737 );
4738 dual_stack.ok_or(WrongIpVersion)
4739 }
4740 }
4741
4742 impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
4743 where
4744 I: AssignedAddrIpExt + FilterIpExt,
4745 BC: FilterBindingsContext,
4746 DeviceId: FakeStrongDeviceId + filter::InterfaceProperties<BC::DeviceClass>,
4747 {
4748 type Handler<'a>
4749 = filter::testutil::NoopImpl<DeviceId>
4750 where
4751 Self: 'a;
4752
4753 fn filter_handler(&mut self) -> Self::Handler<'_> {
4754 filter::testutil::NoopImpl::default()
4755 }
4756 }
4757}
4758
4759#[cfg(test)]
4760mod test {
4761 use super::*;
4762
4763 #[test]
4764 fn highest_priority_address_status_v4() {
4765 assert_eq!(
4767 choose_highest_priority_address_status::<Ipv4>(
4768 [
4769 Ipv4PresentAddressStatus::UnicastAssigned,
4770 Ipv4PresentAddressStatus::UnicastTentative
4771 ]
4772 .into_iter()
4773 ),
4774 Some(Ipv4PresentAddressStatus::UnicastAssigned)
4775 )
4776 }
4777
4778 #[test]
4779 fn highest_priority_address_status_v6() {
4780 assert_eq!(
4782 choose_highest_priority_address_status::<Ipv6>(
4783 [
4784 Ipv6PresentAddressStatus::UnicastAssigned,
4785 Ipv6PresentAddressStatus::UnicastTentative
4786 ]
4787 .into_iter()
4788 ),
4789 Some(Ipv6PresentAddressStatus::UnicastAssigned)
4790 )
4791 }
4792}