1use alloc::boxed::Box;
6use alloc::collections::HashMap;
7use alloc::vec::Vec;
8use core::cmp::Ordering;
9use core::convert::Infallible as Never;
10use core::fmt::Debug;
11use core::hash::Hash;
12use core::marker::PhantomData;
13use core::num::NonZeroU8;
14use core::ops::ControlFlow;
15#[cfg(test)]
16use core::ops::DerefMut;
17use core::sync::atomic::{self, AtomicU16};
18
19use derivative::Derivative;
20use explicit::ResultExt as _;
21use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
22use log::{debug, error, trace};
23use net_types::ip::{
24 GenericOverIp, Ip, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu, Subnet,
25};
26use net_types::{
27 MulticastAddr, MulticastAddress, NonMappedAddr, NonMulticastAddr, SpecifiedAddr,
28 SpecifiedAddress as _, UnicastAddr, Witness,
29};
30use netstack3_base::socket::SocketIpAddrExt as _;
31use netstack3_base::sync::{Mutex, PrimaryRc, RwLock, StrongRc, WeakRc};
32use netstack3_base::{
33 AnyDevice, BroadcastIpExt, CoreTimerContext, Counter, CounterContext, DeviceIdContext,
34 DeviceIdentifier as _, DeviceWithName, ErrorAndSerializer, EventContext, FrameDestination,
35 HandleableTimer, InstantContext, IpAddressId, IpDeviceAddr, IpDeviceAddressIdContext, IpExt,
36 MarkDomain, Marks, Matcher as _, NestedIntoCoreTimerCtx, NotFoundError, ResourceCounterContext,
37 RngContext, SendFrameErrorReason, StrongDeviceIdentifier, TimerBindingsTypes, TimerContext,
38 TimerHandler, TxMetadataBindingsTypes, WeakIpAddressId, WrapBroadcastMarker,
39};
40use netstack3_filter::{
41 self as filter, ConnectionDirection, ConntrackConnection, FilterBindingsContext,
42 FilterBindingsTypes, FilterHandler as _, FilterIpContext, FilterIpExt, FilterIpMetadata,
43 FilterMarkMetadata, FilterTimerId, ForwardedPacket, IngressVerdict, IpPacket, MarkAction,
44 TransportPacketSerializer, Tuple, WeakConnectionError, WeakConntrackConnection,
45};
46use packet::{
47 Buf, BufferAlloc, BufferMut, GrowBuffer, PacketConstraints, ParseBufferMut, ParseMetadata,
48 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 IpDeviceStateBindingsTypes, IpDeviceStateIpExt, Ipv6AddressFlags, Ipv6AddressState,
62};
63use crate::internal::device::{
64 self, IpAddressIdExt, IpDeviceBindingsContext, IpDeviceIpExt, IpDeviceSendContext,
65};
66use crate::internal::fragmentation::{FragmentableIpSerializer, FragmentationIpExt, IpFragmenter};
67use crate::internal::gmp::igmp::IgmpCounters;
68use crate::internal::gmp::mld::MldCounters;
69use crate::internal::gmp::GmpQueryHandler;
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,
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
318#[cfg(debug_assertions)]
319impl Drop for IpLayerPacketMetadataDropCheck {
320 fn drop(&mut self) {
321 if !self.okay_to_drop {
322 panic!(
323 "IpLayerPacketMetadata dropped without acknowledgement. https://fxbug.dev/334127474"
324 );
325 }
326 }
327}
328
329impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
330 FilterIpMetadata<I, A, BT> for IpLayerPacketMetadata<I, A, BT>
331{
332 fn take_connection_and_direction(
333 &mut self,
334 ) -> Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)> {
335 self.conntrack_connection_and_direction.take()
336 }
337
338 fn replace_connection_and_direction(
339 &mut self,
340 conn: ConntrackConnection<I, A, BT>,
341 direction: ConnectionDirection,
342 ) -> Option<ConntrackConnection<I, A, BT>> {
343 self.conntrack_connection_and_direction.replace((conn, direction)).map(|(conn, _dir)| conn)
344 }
345}
346
347impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
348 FilterMarkMetadata for IpLayerPacketMetadata<I, A, BT>
349{
350 fn apply_mark_action(&mut self, domain: MarkDomain, action: MarkAction) {
351 action.apply(self.marks.get_mut(domain))
352 }
353}
354
355pub type IpSendFrameError<S> = ErrorAndSerializer<IpSendFrameErrorReason, S>;
357
358#[derive(Debug, PartialEq)]
360pub enum IpSendFrameErrorReason {
361 Device(SendFrameErrorReason),
363 IllegalLoopbackAddress,
366}
367
368impl From<SendFrameErrorReason> for IpSendFrameErrorReason {
369 fn from(value: SendFrameErrorReason) -> Self {
370 Self::Device(value)
371 }
372}
373
374pub trait IpTransportContext<I: IpExt, BC, CC: DeviceIdContext<AnyDevice> + ?Sized> {
380 fn receive_icmp_error(
394 core_ctx: &mut CC,
395 bindings_ctx: &mut BC,
396 device: &CC::DeviceId,
397 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
398 original_dst_ip: SpecifiedAddr<I::Addr>,
399 original_body: &[u8],
400 err: I::ErrorCode,
401 );
402
403 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
409 core_ctx: &mut CC,
410 bindings_ctx: &mut BC,
411 device: &CC::DeviceId,
412 src_ip: I::RecvSrcAddr,
413 dst_ip: SpecifiedAddr<I::Addr>,
414 buffer: B,
415 info: &LocalDeliveryPacketInfo<I, H>,
416 ) -> Result<(), (B, TransportReceiveError)>;
417}
418
419impl<I: IpExt, BC, CC: DeviceIdContext<AnyDevice> + ?Sized> IpTransportContext<I, BC, CC> for () {
420 fn receive_icmp_error(
421 _core_ctx: &mut CC,
422 _bindings_ctx: &mut BC,
423 _device: &CC::DeviceId,
424 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
425 _original_dst_ip: SpecifiedAddr<I::Addr>,
426 _original_body: &[u8],
427 err: I::ErrorCode,
428 ) {
429 trace!("IpTransportContext::receive_icmp_error: Received ICMP error message ({:?}) for unsupported IP protocol", err);
430 }
431
432 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
433 _core_ctx: &mut CC,
434 _bindings_ctx: &mut BC,
435 _device: &CC::DeviceId,
436 _src_ip: I::RecvSrcAddr,
437 _dst_ip: SpecifiedAddr<I::Addr>,
438 buffer: B,
439 _info: &LocalDeliveryPacketInfo<I, H>,
440 ) -> Result<(), (B, TransportReceiveError)> {
441 Err((buffer, TransportReceiveError::ProtocolUnsupported))
442 }
443}
444
445pub trait BaseTransportIpContext<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
448 type DevicesWithAddrIter<'s>: Iterator<Item = Self::DeviceId>;
451
452 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
458 &mut self,
459 addr: SpecifiedAddr<I::Addr>,
460 cb: F,
461 ) -> O;
462
463 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits;
468
469 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)>;
473}
474
475pub trait TransportIpContext<I: IpExt, BC: TxMetadataBindingsTypes>:
478 BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>
479{
480}
481
482impl<I, CC, BC> TransportIpContext<I, BC> for CC
483where
484 I: IpExt,
485 CC: BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>,
486 BC: TxMetadataBindingsTypes,
487{
488}
489
490pub trait MulticastMembershipHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
492 fn join_multicast_group(
499 &mut self,
500 bindings_ctx: &mut BC,
501 device: &Self::DeviceId,
502 addr: MulticastAddr<I::Addr>,
503 );
504
505 fn leave_multicast_group(
513 &mut self,
514 bindings_ctx: &mut BC,
515 device: &Self::DeviceId,
516 addr: MulticastAddr<I::Addr>,
517 );
518
519 fn select_device_for_multicast_group(
524 &mut self,
525 addr: MulticastAddr<I::Addr>,
526 marks: &Marks,
527 ) -> Result<Self::DeviceId, ResolveRouteError>;
528}
529
530pub trait UseTransportIpContextBlanket {}
542
543pub struct AssignedAddressDeviceIterator<Iter, I, D>(Iter, PhantomData<(I, D)>);
546
547impl<Iter, I, D> Iterator for AssignedAddressDeviceIterator<Iter, I, D>
548where
549 Iter: Iterator<Item = (D, I::AddressStatus)>,
550 I: IpLayerIpExt,
551{
552 type Item = D;
553 fn next(&mut self) -> Option<D> {
554 let Self(iter, PhantomData) = self;
555 iter.by_ref().find_map(|(device, state)| is_unicast_assigned::<I>(&state).then_some(device))
556 }
557}
558
559impl<
560 I: IpLayerIpExt,
561 BC: FilterBindingsContext + TxMetadataBindingsTypes,
562 CC: IpDeviceContext<I>
563 + IpSocketHandler<I, BC>
564 + IpStateContext<I>
565 + FilterIpContext<I, BC>
566 + UseTransportIpContextBlanket,
567 > BaseTransportIpContext<I, BC> for CC
568{
569 type DevicesWithAddrIter<'s> =
570 AssignedAddressDeviceIterator<CC::DeviceAndAddressStatusIter<'s>, I, CC::DeviceId>;
571
572 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
573 &mut self,
574 addr: SpecifiedAddr<I::Addr>,
575 cb: F,
576 ) -> O {
577 self.with_address_statuses(addr, |it| cb(AssignedAddressDeviceIterator(it, PhantomData)))
578 }
579
580 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
581 match device {
582 Some(device) => HopLimits {
583 unicast: IpDeviceEgressStateContext::<I>::get_hop_limit(self, device),
584 ..DEFAULT_HOP_LIMITS
585 },
586 None => DEFAULT_HOP_LIMITS,
587 }
588 }
589
590 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)> {
591 self.with_filter_state(|state| {
592 let conn = state.conntrack.get_connection(&tuple)?;
593
594 if !conn.destination_nat() {
595 return None;
596 }
597
598 let original = conn.original_tuple();
602 Some((original.dst_addr, original.dst_port_or_id))
603 })
604 }
605}
606
607#[derive(Debug, PartialEq)]
609#[allow(missing_docs)]
610pub enum AddressStatus<S> {
611 Present(S),
612 Unassigned,
613}
614
615impl<S> AddressStatus<S> {
616 fn into_present(self) -> Option<S> {
617 match self {
618 Self::Present(s) => Some(s),
619 Self::Unassigned => None,
620 }
621 }
622}
623
624impl AddressStatus<Ipv4PresentAddressStatus> {
625 pub fn from_context_addr_v4<
627 BC: IpDeviceStateBindingsTypes,
628 CC: device::IpDeviceStateContext<Ipv4, BC> + GmpQueryHandler<Ipv4, BC>,
629 >(
630 core_ctx: &mut CC,
631 device: &CC::DeviceId,
632 addr: SpecifiedAddr<Ipv4Addr>,
633 ) -> AddressStatus<Ipv4PresentAddressStatus> {
634 if addr.is_limited_broadcast() {
635 return AddressStatus::Present(Ipv4PresentAddressStatus::LimitedBroadcast);
636 }
637
638 if MulticastAddr::new(addr.get())
639 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
640 {
641 return AddressStatus::Present(Ipv4PresentAddressStatus::Multicast);
642 }
643
644 core_ctx.with_address_ids(device, |mut addrs, _core_ctx| {
645 addrs
646 .find_map(|addr_id| {
647 let dev_addr = addr_id.addr_sub();
648 let (dev_addr, subnet) = dev_addr.addr_subnet();
649
650 if **dev_addr == addr {
651 Some(AddressStatus::Present(Ipv4PresentAddressStatus::Unicast))
652 } else if addr.get() == subnet.broadcast() {
653 Some(AddressStatus::Present(Ipv4PresentAddressStatus::SubnetBroadcast))
654 } else if device.is_loopback() && subnet.contains(addr.as_ref()) {
655 Some(AddressStatus::Present(Ipv4PresentAddressStatus::LoopbackSubnet))
656 } else {
657 None
658 }
659 })
660 .unwrap_or(AddressStatus::Unassigned)
661 })
662 }
663}
664
665impl AddressStatus<Ipv6PresentAddressStatus> {
666 pub fn from_context_addr_v6<
668 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
669 CC: device::Ipv6DeviceContext<BC> + GmpQueryHandler<Ipv6, BC>,
670 >(
671 core_ctx: &mut CC,
672 device: &CC::DeviceId,
673 addr: SpecifiedAddr<Ipv6Addr>,
674 ) -> AddressStatus<Ipv6PresentAddressStatus> {
675 if MulticastAddr::new(addr.get())
676 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
677 {
678 return AddressStatus::Present(Ipv6PresentAddressStatus::Multicast);
679 }
680
681 let addr_id = match core_ctx.get_address_id(device, addr) {
682 Ok(o) => o,
683 Err(NotFoundError) => return AddressStatus::Unassigned,
684 };
685
686 let assigned = core_ctx.with_ip_address_state(
687 device,
688 &addr_id,
689 |Ipv6AddressState { flags: Ipv6AddressFlags { assigned }, config: _ }| *assigned,
690 );
691
692 if assigned {
693 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned)
694 } else {
695 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastTentative)
696 }
697 }
698}
699
700impl<S: GenericOverIp<I>, I: Ip> GenericOverIp<I> for AddressStatus<S> {
701 type Type = AddressStatus<S::Type>;
702}
703
704#[derive(Debug, PartialEq)]
706#[allow(missing_docs)]
707pub enum Ipv4PresentAddressStatus {
708 LimitedBroadcast,
709 SubnetBroadcast,
710 Multicast,
711 Unicast,
712 LoopbackSubnet,
723}
724
725impl Ipv4PresentAddressStatus {
726 fn to_broadcast_marker(&self) -> Option<<Ipv4 as BroadcastIpExt>::BroadcastMarker> {
727 match self {
728 Self::LimitedBroadcast | Self::SubnetBroadcast => Some(()),
729 Self::Multicast | Self::Unicast | Self::LoopbackSubnet => None,
730 }
731 }
732}
733
734#[derive(Debug, PartialEq)]
736#[allow(missing_docs)]
737pub enum Ipv6PresentAddressStatus {
738 Multicast,
739 UnicastAssigned,
740 UnicastTentative,
741}
742
743pub trait IpLayerIpExt:
745 IpExt
746 + MulticastRouteIpExt
747 + IcmpHandlerIpExt
748 + FilterIpExt
749 + FragmentationIpExt
750 + IpDeviceIpExt
751 + IpAddressIdExt
752 + IpCountersIpExt
753{
754 type AddressStatus: Debug;
756 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>: AsRef<
758 IpStateInner<Self, StrongDeviceId, BT>,
759 >;
760 type PacketIdState;
762 type PacketId;
764 fn next_packet_id_from_state(state: &Self::PacketIdState) -> Self::PacketId;
766}
767
768impl IpLayerIpExt for Ipv4 {
769 type AddressStatus = Ipv4PresentAddressStatus;
770 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
771 Ipv4State<StrongDeviceId, BT>;
772 type PacketIdState = AtomicU16;
773 type PacketId = u16;
774 fn next_packet_id_from_state(next_packet_id: &Self::PacketIdState) -> Self::PacketId {
775 next_packet_id.fetch_add(1, atomic::Ordering::Relaxed)
779 }
780}
781
782impl IpLayerIpExt for Ipv6 {
783 type AddressStatus = Ipv6PresentAddressStatus;
784 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
785 Ipv6State<StrongDeviceId, BT>;
786 type PacketIdState = ();
787 type PacketId = ();
788 fn next_packet_id_from_state((): &Self::PacketIdState) -> Self::PacketId {
789 ()
790 }
791}
792
793pub trait IpStateContext<I: IpLayerIpExt>:
795 IpRouteTablesContext<I, DeviceId: DeviceWithName>
796{
797 type IpRouteTablesCtx<'a>: IpRouteTablesContext<I, DeviceId = Self::DeviceId>;
799
800 fn with_rules_table<
802 O,
803 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId>) -> O,
804 >(
805 &mut self,
806 cb: F,
807 ) -> O;
808
809 fn with_rules_table_mut<
811 O,
812 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId>) -> O,
813 >(
814 &mut self,
815 cb: F,
816 ) -> O;
817}
818
819pub trait IpRouteTablesContext<I: IpLayerIpExt>:
821 IpRouteTableContext<I> + IpDeviceContext<I>
822{
823 type Ctx<'a>: IpRouteTableContext<
825 I,
826 DeviceId = Self::DeviceId,
827 WeakDeviceId = Self::WeakDeviceId,
828 >;
829
830 fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId>;
832
833 fn with_ip_routing_tables<
835 O,
836 F: FnOnce(
837 &mut Self::Ctx<'_>,
838 &HashMap<
839 RoutingTableId<I, Self::DeviceId>,
840 PrimaryRc<RwLock<RoutingTable<I, Self::DeviceId>>>,
841 >,
842 ) -> O,
843 >(
844 &mut self,
845 cb: F,
846 ) -> O;
847
848 fn with_ip_routing_tables_mut<
850 O,
851 F: FnOnce(
852 &mut HashMap<
853 RoutingTableId<I, Self::DeviceId>,
854 PrimaryRc<RwLock<RoutingTable<I, Self::DeviceId>>>,
855 >,
856 ) -> O,
857 >(
858 &mut self,
859 cb: F,
860 ) -> O;
861
862 fn with_main_ip_routing_table<
866 O,
867 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
868 >(
869 &mut self,
870 cb: F,
871 ) -> O {
872 let main_table_id = self.main_table_id();
873 self.with_ip_routing_table(&main_table_id, cb)
874 }
875
876 fn with_main_ip_routing_table_mut<
880 O,
881 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
882 >(
883 &mut self,
884 cb: F,
885 ) -> O {
886 let main_table_id = self.main_table_id();
887 self.with_ip_routing_table_mut(&main_table_id, cb)
888 }
889}
890
891pub trait IpRouteTableContext<I: IpLayerIpExt>: IpDeviceContext<I> {
893 type IpDeviceIdCtx<'a>: DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
895 + IpRoutingDeviceContext<I>
896 + IpDeviceContext<I>;
897
898 fn with_ip_routing_table<
900 O,
901 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
902 >(
903 &mut self,
904 table_id: &RoutingTableId<I, Self::DeviceId>,
905 cb: F,
906 ) -> O;
907
908 fn with_ip_routing_table_mut<
910 O,
911 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
912 >(
913 &mut self,
914 table_id: &RoutingTableId<I, Self::DeviceId>,
915 cb: F,
916 ) -> O;
917}
918
919pub trait IpDeviceEgressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
921 fn with_next_packet_id<O, F: FnOnce(&I::PacketIdState) -> O>(&self, cb: F) -> O;
923
924 fn get_local_addr_for_remote(
926 &mut self,
927 device_id: &Self::DeviceId,
928 remote: Option<SpecifiedAddr<I::Addr>>,
929 ) -> Option<IpDeviceAddr<I::Addr>>;
930
931 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8;
933}
934
935pub trait IpDeviceIngressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
937 fn address_status_for_device(
943 &mut self,
944 addr: SpecifiedAddr<I::Addr>,
945 device_id: &Self::DeviceId,
946 ) -> AddressStatus<I::AddressStatus>;
947}
948
949pub trait IpDeviceContext<I: IpLayerIpExt>:
951 IpDeviceEgressStateContext<I> + IpDeviceIngressStateContext<I>
952{
953 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
955
956 type DeviceAndAddressStatusIter<'a>: Iterator<Item = (Self::DeviceId, I::AddressStatus)>;
958
959 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
965 &mut self,
966 addr: SpecifiedAddr<I::Addr>,
967 cb: F,
968 ) -> R;
969
970 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
972}
973
974pub trait IpDeviceConfirmReachableContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
976 fn confirm_reachable(
979 &mut self,
980 bindings_ctx: &mut BC,
981 device: &Self::DeviceId,
982 neighbor: SpecifiedAddr<I::Addr>,
983 );
984}
985
986pub trait IpDeviceMtuContext<I: Ip>: DeviceIdContext<AnyDevice> {
988 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu;
992}
993
994#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
996#[generic_over_ip(I, Ip)]
997pub enum IpLayerEvent<DeviceId, I: IpLayerIpExt> {
998 AddRoute(types::AddableEntry<I::Addr, DeviceId>),
1000 RemoveRoutes {
1002 subnet: Subnet<I::Addr>,
1004 device: DeviceId,
1006 gateway: Option<SpecifiedAddr<I::Addr>>,
1008 },
1009 MulticastForwarding(MulticastForwardingEvent<I, DeviceId>),
1011}
1012
1013impl<DeviceId, I: IpLayerIpExt> From<MulticastForwardingEvent<I, DeviceId>>
1014 for IpLayerEvent<DeviceId, I>
1015{
1016 fn from(event: MulticastForwardingEvent<I, DeviceId>) -> IpLayerEvent<DeviceId, I> {
1017 IpLayerEvent::MulticastForwarding(event)
1018 }
1019}
1020
1021impl<DeviceId, I: IpLayerIpExt> IpLayerEvent<DeviceId, I> {
1022 pub fn map_device<N, F: Fn(DeviceId) -> N>(self, map: F) -> IpLayerEvent<N, I> {
1024 match self {
1025 IpLayerEvent::AddRoute(types::AddableEntry { subnet, device, gateway, metric }) => {
1026 IpLayerEvent::AddRoute(types::AddableEntry {
1027 subnet,
1028 device: map(device),
1029 gateway,
1030 metric,
1031 })
1032 }
1033 IpLayerEvent::RemoveRoutes { subnet, device, gateway } => {
1034 IpLayerEvent::RemoveRoutes { subnet, device: map(device), gateway }
1035 }
1036 IpLayerEvent::MulticastForwarding(e) => {
1037 IpLayerEvent::MulticastForwarding(e.map_device(map))
1038 }
1039 }
1040 }
1041}
1042
1043#[derive(Derivative, PartialEq, Eq, Clone, Hash)]
1045#[derivative(Debug)]
1046pub struct RouterAdvertisementEvent<D> {
1047 #[derivative(Debug = "ignore")]
1050 pub options_bytes: Box<[u8]>,
1051 pub source: net_types::ip::Ipv6Addr,
1053 pub device: D,
1055}
1056
1057impl<D> RouterAdvertisementEvent<D> {
1058 pub fn map_device<N, F: Fn(D) -> N>(self, map: F) -> RouterAdvertisementEvent<N> {
1060 let Self { options_bytes, source, device } = self;
1061 RouterAdvertisementEvent { options_bytes, source, device: map(device) }
1062 }
1063}
1064
1065pub trait NdpBindingsContext<DeviceId>: EventContext<RouterAdvertisementEvent<DeviceId>> {}
1067impl<DeviceId, BC: EventContext<RouterAdvertisementEvent<DeviceId>>> NdpBindingsContext<DeviceId>
1068 for BC
1069{
1070}
1071
1072pub trait IpLayerBindingsContext<I: IpLayerIpExt, DeviceId>:
1074 InstantContext
1075 + EventContext<IpLayerEvent<DeviceId, I>>
1076 + FilterBindingsContext
1077 + TxMetadataBindingsTypes
1078{
1079}
1080impl<
1081 I: IpLayerIpExt,
1082 DeviceId,
1083 BC: InstantContext
1084 + EventContext<IpLayerEvent<DeviceId, I>>
1085 + FilterBindingsContext
1086 + TxMetadataBindingsTypes,
1087 > IpLayerBindingsContext<I, DeviceId> for BC
1088{
1089}
1090
1091pub trait IpLayerBindingsTypes: IcmpBindingsTypes + IpStateBindingsTypes {}
1093impl<BT: IcmpBindingsTypes + IpStateBindingsTypes> IpLayerBindingsTypes for BT {}
1094
1095pub trait IpLayerContext<
1097 I: IpLayerIpExt,
1098 BC: IpLayerBindingsContext<I, <Self as DeviceIdContext<AnyDevice>>::DeviceId>,
1099>:
1100 IpStateContext<I>
1101 + IpDeviceContext<I>
1102 + IpDeviceMtuContext<I>
1103 + IpDeviceSendContext<I, BC>
1104 + IcmpErrorHandler<I, BC>
1105 + MulticastForwardingStateContext<I, BC>
1106 + MulticastForwardingDeviceContext<I>
1107 + CounterContext<MulticastForwardingCounters<I>>
1108 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>
1109{
1110}
1111
1112impl<
1113 I: IpLayerIpExt,
1114 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
1115 CC: IpStateContext<I>
1116 + IpDeviceContext<I>
1117 + IpDeviceMtuContext<I>
1118 + IpDeviceSendContext<I, BC>
1119 + IcmpErrorHandler<I, BC>
1120 + MulticastForwardingStateContext<I, BC>
1121 + MulticastForwardingDeviceContext<I>
1122 + CounterContext<MulticastForwardingCounters<I>>
1123 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>,
1124 > IpLayerContext<I, BC> for CC
1125{
1126}
1127
1128fn is_unicast_assigned<I: IpLayerIpExt>(status: &I::AddressStatus) -> bool {
1129 #[derive(GenericOverIp)]
1130 #[generic_over_ip(I, Ip)]
1131 struct WrapAddressStatus<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
1132
1133 I::map_ip(
1134 WrapAddressStatus(status),
1135 |WrapAddressStatus(status)| match status {
1136 Ipv4PresentAddressStatus::Unicast | Ipv4PresentAddressStatus::LoopbackSubnet => true,
1137 Ipv4PresentAddressStatus::LimitedBroadcast
1138 | Ipv4PresentAddressStatus::SubnetBroadcast
1139 | Ipv4PresentAddressStatus::Multicast => false,
1140 },
1141 |WrapAddressStatus(status)| match status {
1142 Ipv6PresentAddressStatus::UnicastAssigned => true,
1143 Ipv6PresentAddressStatus::Multicast | Ipv6PresentAddressStatus::UnicastTentative => {
1144 false
1145 }
1146 },
1147 )
1148}
1149
1150fn is_local_assigned_address<I: Ip + IpLayerIpExt, CC: IpDeviceIngressStateContext<I>>(
1151 core_ctx: &mut CC,
1152 device: &CC::DeviceId,
1153 addr: IpDeviceAddr<I::Addr>,
1154) -> bool {
1155 match core_ctx.address_status_for_device(addr.into(), device) {
1156 AddressStatus::Present(status) => is_unicast_assigned::<I>(&status),
1157 AddressStatus::Unassigned => false,
1158 }
1159}
1160
1161fn get_device_with_assigned_address<I, CC>(
1162 core_ctx: &mut CC,
1163 addr: IpDeviceAddr<I::Addr>,
1164) -> Option<(CC::DeviceId, I::AddressStatus)>
1165where
1166 I: IpLayerIpExt,
1167 CC: IpDeviceContext<I>,
1168{
1169 core_ctx.with_address_statuses(addr.into(), |mut it| {
1170 it.find_map(|(device, status)| {
1171 is_unicast_assigned::<I>(&status).then_some((device, status))
1172 })
1173 })
1174}
1175
1176fn get_local_addr<I: Ip + IpLayerIpExt, CC: IpDeviceContext<I>>(
1180 core_ctx: &mut CC,
1181 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1182 device: &CC::DeviceId,
1183 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1184) -> Result<IpDeviceAddr<I::Addr>, ResolveRouteError> {
1185 match local_ip_and_policy {
1186 Some((local_ip, NonLocalSrcAddrPolicy::Allow)) => Ok(local_ip),
1187 Some((local_ip, NonLocalSrcAddrPolicy::Deny)) => {
1188 is_local_assigned_address(core_ctx, device, local_ip)
1189 .then_some(local_ip)
1190 .ok_or(ResolveRouteError::NoSrcAddr)
1191 }
1192 None => core_ctx
1193 .get_local_addr_for_remote(device, remote_addr.map(Into::into))
1194 .ok_or(ResolveRouteError::NoSrcAddr),
1195 }
1196}
1197
1198#[derive(Error, Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
1200#[generic_over_ip()]
1201pub enum ResolveRouteError {
1202 #[error("a source address could not be selected")]
1204 NoSrcAddr,
1205 #[error("no route exists to the destination IP address")]
1207 Unreachable,
1208}
1209
1210fn get_local_addr_with_internal_forwarding<I, CC>(
1212 core_ctx: &mut CC,
1213 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1214 device: &CC::DeviceId,
1215 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1216) -> Result<(IpDeviceAddr<I::Addr>, InternalForwarding<CC::DeviceId>), ResolveRouteError>
1217where
1218 I: IpLayerIpExt,
1219 CC: IpDeviceContext<I>,
1220{
1221 match get_local_addr(core_ctx, local_ip_and_policy, device, remote_addr) {
1222 Ok(src_addr) => Ok((src_addr, InternalForwarding::NotUsed)),
1223 Err(e) => {
1224 if let Some((local_ip, _policy)) = local_ip_and_policy {
1232 if let Some((device, _addr_status)) =
1233 get_device_with_assigned_address(core_ctx, local_ip)
1234 {
1235 if core_ctx.is_device_unicast_forwarding_enabled(&device) {
1236 return Ok((local_ip, InternalForwarding::Used(device)));
1237 }
1238 }
1239 }
1240 Err(e)
1241 }
1242 }
1243}
1244
1245#[derive(Debug, PartialEq, Eq)]
1248struct RuleWalkInfo<O> {
1249 observed_source_address_matcher: bool,
1251 inner: O,
1254}
1255
1256fn walk_rules<
1270 I: IpLayerIpExt,
1271 CC: IpRouteTablesContext<I, DeviceId: DeviceWithName>,
1272 O,
1273 State,
1274 F: FnMut(
1275 State,
1276 &mut CC::IpDeviceIdCtx<'_>,
1277 &RoutingTable<I, CC::DeviceId>,
1278 ) -> ControlFlow<O, State>,
1279>(
1280 core_ctx: &mut CC,
1281 rules: &RulesTable<I, CC::DeviceId>,
1282 init: State,
1283 rule_input: &RuleInput<'_, I, CC::DeviceId>,
1284 mut lookup_table: F,
1285) -> ControlFlow<RuleAction<RuleWalkInfo<O>>, RuleWalkInfo<State>> {
1286 rules.iter().try_fold(
1287 RuleWalkInfo { inner: init, observed_source_address_matcher: false },
1288 |RuleWalkInfo { inner: state, observed_source_address_matcher },
1289 Rule { action, matcher }| {
1290 let observed_source_address_matcher =
1291 observed_source_address_matcher || matcher.source_address_matcher.is_some();
1292 if !matcher.matches(rule_input) {
1293 return ControlFlow::Continue(RuleWalkInfo {
1294 inner: state,
1295 observed_source_address_matcher,
1296 });
1297 }
1298 match action {
1299 RuleAction::Unreachable => return ControlFlow::Break(RuleAction::Unreachable),
1300 RuleAction::Lookup(table_id) => core_ctx.with_ip_routing_table(
1301 &table_id,
1302 |core_ctx, table| match lookup_table(state, core_ctx, table) {
1303 ControlFlow::Break(out) => {
1304 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1305 inner: out,
1306 observed_source_address_matcher,
1307 }))
1308 }
1309 ControlFlow::Continue(state) => ControlFlow::Continue(RuleWalkInfo {
1310 inner: state,
1311 observed_source_address_matcher,
1312 }),
1313 },
1314 ),
1315 }
1316 },
1317 )
1318}
1319
1320pub fn resolve_output_route_to_destination<
1331 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1332 BC: IpDeviceBindingsContext<I, CC::DeviceId> + IpLayerBindingsContext<I, CC::DeviceId>,
1333 CC: IpStateContext<I> + IpDeviceContext<I> + device::IpDeviceConfigurationContext<I, BC>,
1334>(
1335 core_ctx: &mut CC,
1336 device: Option<&CC::DeviceId>,
1337 src_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1338 dst_ip: Option<RoutableIpAddr<I::Addr>>,
1339 marks: &Marks,
1340) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1341 enum LocalDelivery<A, D> {
1342 WeakLoopback { dst_ip: A, device: D },
1343 StrongForDevice(D),
1344 }
1345
1346 let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1364 let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1365 match (device, dst_ip) {
1366 (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1367 .then_some(LocalDelivery::StrongForDevice(device.clone())),
1368 (None, Some(dst_ip)) => {
1369 get_device_with_assigned_address(core_ctx, dst_ip).map(
1370 |(dst_device, _addr_status)| {
1371 if src_ip_and_policy
1376 .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1377 || dst_ip.as_ref().must_have_zone()
1378 {
1379 LocalDelivery::StrongForDevice(dst_device)
1380 } else {
1381 LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1382 }
1383 },
1384 )
1385 }
1386 (_, None) => None,
1387 }
1388 };
1389
1390 if let Some(local_delivery) = local_delivery_instructions {
1391 let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1392
1393 let (src_addr, dest_device) = match local_delivery {
1394 LocalDelivery::WeakLoopback { dst_ip, device } => {
1395 let src_ip = match src_ip_and_policy {
1396 Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1397 let _device = get_device_with_assigned_address(core_ctx, src_ip)
1398 .ok_or(ResolveRouteError::NoSrcAddr)?;
1399 src_ip
1400 }
1401 Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1402 None => dst_ip,
1403 };
1404 (src_ip, device)
1405 }
1406 LocalDelivery::StrongForDevice(device) => {
1407 (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1408 }
1409 };
1410 return Ok(ResolvedRoute {
1411 src_addr,
1412 local_delivery_device: Some(dest_device),
1413 device: loopback,
1414 next_hop: NextHop::RemoteAsNeighbor,
1415 internal_forwarding: InternalForwarding::NotUsed,
1416 });
1417 }
1418 let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1419 let rule_input = RuleInput {
1420 packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1421 marks,
1422 };
1423 core_ctx.with_rules_table(|core_ctx, rules| {
1424 let mut walk_rules = |rule_input, src_ip_and_policy| {
1425 walk_rules(
1426 core_ctx,
1427 rules,
1428 None, rule_input,
1430 |first_error, core_ctx, table| {
1431 let mut matching_with_addr = table.lookup_filter_map(
1432 core_ctx,
1433 device,
1434 dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1435 |core_ctx, d| {
1436 Some(get_local_addr_with_internal_forwarding(
1437 core_ctx,
1438 src_ip_and_policy,
1439 d,
1440 dst_ip,
1441 ))
1442 },
1443 );
1444
1445 let first_error_in_this_table = match matching_with_addr.next() {
1446 Some((
1447 Destination { device, next_hop },
1448 Ok((local_addr, internal_forwarding)),
1449 )) => {
1450 return ControlFlow::Break(Ok((
1451 Destination { device: device.clone(), next_hop },
1452 local_addr,
1453 internal_forwarding,
1454 )));
1455 }
1456 Some((_, Err(e))) => e,
1457 None => return ControlFlow::Continue(first_error),
1461 };
1462
1463 matching_with_addr
1464 .filter_map(|(destination, local_addr)| {
1465 local_addr.ok_checked::<ResolveRouteError>().map(
1468 |(local_addr, internal_forwarding)| {
1469 (destination, local_addr, internal_forwarding)
1470 },
1471 )
1472 })
1473 .next()
1474 .map_or(
1475 ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1476 |(
1477 Destination { device, next_hop },
1478 local_addr,
1479 internal_forwarding,
1480 )| {
1481 ControlFlow::Break(Ok((
1482 Destination { device: device.clone(), next_hop },
1483 local_addr,
1484 internal_forwarding,
1485 )))
1486 },
1487 )
1488 },
1489 )
1490 };
1491
1492 let result = match walk_rules(&rule_input, src_ip_and_policy) {
1493 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1500 inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1501 observed_source_address_matcher: true,
1502 })) if src_ip_and_policy.is_none() => walk_rules(
1503 &RuleInput {
1504 packet_origin: PacketOrigin::Local {
1505 bound_address: Some(selected_src_addr.into()),
1506 bound_device: device,
1507 },
1508 marks,
1509 },
1510 Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1511 ),
1512 result => result,
1513 };
1514
1515 match result {
1516 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1517 inner: result,
1518 observed_source_address_matcher: _,
1519 })) => {
1520 result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1521 ResolvedRoute {
1522 src_addr,
1523 device,
1524 local_delivery_device: None,
1525 next_hop,
1526 internal_forwarding,
1527 }
1528 })
1529 }
1530 ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1531 ControlFlow::Continue(RuleWalkInfo {
1532 inner: first_error,
1533 observed_source_address_matcher: _,
1534 }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1535 }
1536 })
1537}
1538
1539pub trait UseIpSocketContextBlanket {}
1544
1545impl<
1546 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1547 BC: IpDeviceBindingsContext<I, CC::DeviceId>
1548 + IpLayerBindingsContext<I, CC::DeviceId>
1549 + IpSocketBindingsContext,
1550 CC: IpLayerEgressContext<I, BC>
1551 + IpStateContext<I>
1552 + IpDeviceContext<I>
1553 + IpDeviceConfirmReachableContext<I, BC>
1554 + IpDeviceMtuContext<I>
1555 + device::IpDeviceConfigurationContext<I, BC>
1556 + UseIpSocketContextBlanket,
1557 > IpSocketContext<I, BC> for CC
1558{
1559 fn lookup_route(
1560 &mut self,
1561 _bindings_ctx: &mut BC,
1562 device: Option<&CC::DeviceId>,
1563 local_ip: Option<IpDeviceAddr<I::Addr>>,
1564 addr: RoutableIpAddr<I::Addr>,
1565 transparent: bool,
1566 marks: &Marks,
1567 ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1568 let src_ip_and_policy = local_ip.map(|local_ip| {
1569 (
1570 local_ip,
1571 if transparent {
1572 NonLocalSrcAddrPolicy::Allow
1573 } else {
1574 NonLocalSrcAddrPolicy::Deny
1575 },
1576 )
1577 });
1578 let res =
1579 resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1580 trace!(
1581 "lookup_route(\
1582 device={device:?}, \
1583 local_ip={local_ip:?}, \
1584 addr={addr:?}, \
1585 transparent={transparent:?}, \
1586 marks={marks:?}) => {res:?}"
1587 );
1588 res
1589 }
1590
1591 fn send_ip_packet<S>(
1592 &mut self,
1593 bindings_ctx: &mut BC,
1594 meta: SendIpPacketMeta<
1595 I,
1596 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1597 SpecifiedAddr<I::Addr>,
1598 >,
1599 body: S,
1600 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1601 ) -> Result<(), IpSendFrameError<S>>
1602 where
1603 S: TransportPacketSerializer<I>,
1604 S::Buffer: BufferMut,
1605 {
1606 send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1607 }
1608
1609 fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1610 device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1611 }
1612
1613 fn confirm_reachable(
1614 &mut self,
1615 bindings_ctx: &mut BC,
1616 dst: SpecifiedAddr<I::Addr>,
1617 input: RuleInput<'_, I, Self::DeviceId>,
1618 ) {
1619 match lookup_route_table(self, dst.get(), input) {
1620 Some(Destination { next_hop, device }) => {
1621 let neighbor = match next_hop {
1622 NextHop::RemoteAsNeighbor => dst,
1623 NextHop::Gateway(gateway) => gateway,
1624 NextHop::Broadcast(marker) => {
1625 I::map_ip::<_, ()>(
1626 WrapBroadcastMarker(marker),
1627 |WrapBroadcastMarker(())| {
1628 debug!(
1629 "can't confirm {dst:?}@{device:?} as reachable: \
1630 dst is a broadcast address"
1631 );
1632 },
1633 |WrapBroadcastMarker(never)| match never {},
1634 );
1635 return;
1636 }
1637 };
1638 IpDeviceConfirmReachableContext::confirm_reachable(
1639 self,
1640 bindings_ctx,
1641 &device,
1642 neighbor,
1643 );
1644 }
1645 None => {
1646 debug!("can't confirm {dst:?} as reachable: no route");
1647 }
1648 }
1649 }
1650}
1651
1652pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1657 fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1659 &mut self,
1660 bindings_ctx: &mut BC,
1661 device: &Self::DeviceId,
1662 src_ip: I::RecvSrcAddr,
1663 dst_ip: SpecifiedAddr<I::Addr>,
1664 proto: I::Proto,
1665 body: B,
1666 info: &LocalDeliveryPacketInfo<I, H>,
1667 ) -> Result<(), TransportReceiveError>;
1668}
1669
1670pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1672 IpTransportDispatchContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1673 + IpDeviceIngressStateContext<I>
1674 + IpDeviceMtuContext<I>
1675 + IpDeviceSendContext<I, BC>
1676 + IcmpErrorHandler<I, BC>
1677 + IpLayerContext<I, BC>
1678 + FragmentHandler<I, BC>
1679 + FilterHandlerProvider<I, BC>
1680 + RawIpSocketHandler<I, BC>
1681{
1682}
1683
1684impl<
1685 I: IpLayerIpExt,
1686 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1687 CC: IpTransportDispatchContext<
1688 I,
1689 BC,
1690 DeviceId: filter::InterfaceProperties<BC::DeviceClass>,
1691 > + IpDeviceIngressStateContext<I>
1692 + IpDeviceMtuContext<I>
1693 + IpDeviceSendContext<I, BC>
1694 + IcmpErrorHandler<I, BC>
1695 + IpLayerContext<I, BC>
1696 + FragmentHandler<I, BC>
1697 + FilterHandlerProvider<I, BC>
1698 + RawIpSocketHandler<I, BC>,
1699 > IpLayerIngressContext<I, BC> for CC
1700{
1701}
1702
1703pub trait IpLayerEgressContext<I, BC>:
1705 IpDeviceSendContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1706 + FilterHandlerProvider<I, BC>
1707 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1708where
1709 I: IpLayerIpExt,
1710 BC: FilterBindingsContext + TxMetadataBindingsTypes,
1711{
1712}
1713
1714impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1715where
1716 I: IpLayerIpExt,
1717 BC: FilterBindingsContext + TxMetadataBindingsTypes,
1718 CC: IpDeviceSendContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1719 + FilterHandlerProvider<I, BC>
1720 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
1721{
1722}
1723
1724pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1726 IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
1727{
1728}
1729
1730impl<
1731 I: IpLayerIpExt,
1732 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1733 CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
1734 > IpLayerForwardingContext<I, BC> for CC
1735{
1736}
1737
1738#[derive(Copy, Clone, Default)]
1740pub struct Ipv4StateBuilder {
1741 icmp: Icmpv4StateBuilder,
1742}
1743
1744impl Ipv4StateBuilder {
1745 #[cfg(any(test, feature = "testutils"))]
1747 pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
1748 &mut self.icmp
1749 }
1750
1751 pub fn build<
1753 CC: CoreTimerContext<IpLayerTimerId, BC>,
1754 StrongDeviceId: StrongDeviceIdentifier,
1755 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1756 >(
1757 self,
1758 bindings_ctx: &mut BC,
1759 ) -> Ipv4State<StrongDeviceId, BC> {
1760 let Ipv4StateBuilder { icmp } = self;
1761
1762 Ipv4State {
1763 inner: IpStateInner::new::<CC>(bindings_ctx),
1764 icmp: icmp.build(),
1765 next_packet_id: Default::default(),
1766 }
1767 }
1768}
1769
1770#[derive(Copy, Clone)]
1774pub struct Ipv6StateBuilder {
1775 icmp: Icmpv6StateBuilder,
1776 slaac_stable_secret_key: Option<IidSecret>,
1777}
1778
1779impl Ipv6StateBuilder {
1780 pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
1785 self.slaac_stable_secret_key = Some(secret_key);
1786 self
1787 }
1788
1789 pub fn build<
1795 CC: CoreTimerContext<IpLayerTimerId, BC>,
1796 StrongDeviceId: StrongDeviceIdentifier,
1797 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1798 >(
1799 self,
1800 bindings_ctx: &mut BC,
1801 ) -> Ipv6State<StrongDeviceId, BC> {
1802 let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
1803
1804 let slaac_stable_secret_key = slaac_stable_secret_key
1805 .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
1806
1807 Ipv6State {
1808 inner: IpStateInner::new::<CC>(bindings_ctx),
1809 icmp: icmp.build(),
1810 slaac_counters: Default::default(),
1811 slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
1812 slaac_stable_secret_key,
1813 }
1814 }
1815}
1816
1817impl Default for Ipv6StateBuilder {
1818 fn default() -> Self {
1819 #[cfg(any(test, feature = "testutils"))]
1820 let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
1821
1822 #[cfg(not(any(test, feature = "testutils")))]
1823 let slaac_stable_secret_key = None;
1824
1825 Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
1826 }
1827}
1828
1829pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1831 pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
1833 pub icmp: Icmpv4State<BT>,
1835 pub next_packet_id: AtomicU16,
1837}
1838
1839impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1840 AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
1841{
1842 fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
1843 &self.inner
1844 }
1845}
1846
1847pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
1851 core_ctx: &mut CC,
1852) -> I::PacketId {
1853 core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
1854}
1855
1856pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1858 pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
1860 pub icmp: Icmpv6State<BT>,
1862 pub slaac_counters: SlaacCounters,
1864 pub slaac_temp_secret_key: IidSecret,
1866 pub slaac_stable_secret_key: IidSecret,
1871}
1872
1873impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1874 AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
1875{
1876 fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
1877 &self.inner
1878 }
1879}
1880
1881impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1882 OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
1883{
1884 type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
1885 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1886 OrderedLockRef::new(&self.fragment_cache)
1887 }
1888}
1889
1890impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1891 OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
1892{
1893 type Lock = Mutex<PmtuCache<I, BT>>;
1894 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1895 OrderedLockRef::new(&self.pmtu_cache)
1896 }
1897}
1898
1899impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1900 OrderedLockAccess<RulesTable<I, D>> for IpStateInner<I, D, BT>
1901{
1902 type Lock = RwLock<RulesTable<I, D>>;
1903 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1904 OrderedLockRef::new(&self.rules_table)
1905 }
1906}
1907
1908impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1909 OrderedLockAccess<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>
1910 for IpStateInner<I, D, BT>
1911{
1912 type Lock = Mutex<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>;
1913 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1914 OrderedLockRef::new(&self.tables)
1915 }
1916}
1917
1918impl<I: IpLayerIpExt, D: StrongDeviceIdentifier> OrderedLockAccess<RoutingTable<I, D>>
1919 for RoutingTableId<I, D>
1920{
1921 type Lock = RwLock<RoutingTable<I, D>>;
1922 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1923 let Self(inner) = self;
1924 OrderedLockRef::new(&*inner)
1925 }
1926}
1927
1928impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1929 OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
1930{
1931 type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
1932 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1933 OrderedLockRef::new(&self.multicast_forwarding)
1934 }
1935}
1936
1937impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1938 OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
1939{
1940 type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
1941 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1942 OrderedLockRef::new(&self.raw_sockets)
1943 }
1944}
1945
1946impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1947 OrderedLockAccess<filter::State<I, I::Weak<BT>, BT>> for IpStateInner<I, D, BT>
1948{
1949 type Lock = RwLock<filter::State<I, I::Weak<BT>, BT>>;
1950 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1951 OrderedLockRef::new(&self.filter)
1952 }
1953}
1954
1955pub trait IpStateBindingsTypes:
1957 PmtuBindingsTypes
1958 + FragmentBindingsTypes
1959 + RawIpSocketsBindingsTypes
1960 + FilterBindingsTypes
1961 + MulticastForwardingBindingsTypes
1962 + IpDeviceStateBindingsTypes
1963{
1964}
1965impl<BT> IpStateBindingsTypes for BT where
1966 BT: PmtuBindingsTypes
1967 + FragmentBindingsTypes
1968 + RawIpSocketsBindingsTypes
1969 + FilterBindingsTypes
1970 + MulticastForwardingBindingsTypes
1971 + IpDeviceStateBindingsTypes
1972{
1973}
1974
1975#[derive(Clone, PartialEq, Eq, Hash)]
1977pub struct RoutingTableId<I: Ip, D>(StrongRc<RwLock<RoutingTable<I, D>>>);
1978
1979impl<I: Ip, D> Debug for RoutingTableId<I, D> {
1980 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1981 let Self(rc) = self;
1982 f.debug_tuple("RoutingTableId").field(&StrongRc::debug_id(rc)).finish()
1983 }
1984}
1985
1986impl<I: Ip, D> RoutingTableId<I, D> {
1987 pub(crate) fn new(rc: StrongRc<RwLock<RoutingTable<I, D>>>) -> Self {
1989 Self(rc)
1990 }
1991
1992 #[cfg(any(test, feature = "testutils"))]
1994 pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
1995 let Self(inner) = self;
1996 &*inner
1997 }
1998
1999 pub fn downgrade(&self) -> WeakRoutingTableId<I, D> {
2001 let Self(rc) = self;
2002 WeakRoutingTableId(StrongRc::downgrade(rc))
2003 }
2004
2005 #[cfg(test)]
2006 fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2007 let Self(rc) = self;
2008 rc.write()
2009 }
2010}
2011
2012#[derive(Clone, PartialEq, Eq, Hash)]
2014pub struct WeakRoutingTableId<I: Ip, D>(WeakRc<RwLock<RoutingTable<I, D>>>);
2015
2016impl<I: Ip, D> Debug for WeakRoutingTableId<I, D> {
2017 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2018 let Self(rc) = self;
2019 f.debug_tuple("WeakRoutingTableId").field(&WeakRc::debug_id(rc)).finish()
2020 }
2021}
2022
2023#[derive(GenericOverIp)]
2025#[generic_over_ip(I, Ip)]
2026pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2027 rules_table: RwLock<RulesTable<I, D>>,
2028 main_table_id: RoutingTableId<I, D>,
2030 multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2031 multicast_forwarding_counters: MulticastForwardingCounters<I>,
2032 fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2033 pmtu_cache: Mutex<PmtuCache<I, BT>>,
2034 counters: IpCounters<I>,
2035 raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2036 raw_socket_counters: RawIpSocketCounters<I>,
2037 filter: RwLock<filter::State<I, I::Weak<BT>, BT>>,
2038 tables: Mutex<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>,
2044 igmp_counters: IgmpCounters,
2045 mld_counters: MldCounters,
2046}
2047
2048impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2049 pub fn counters(&self) -> &IpCounters<I> {
2051 &self.counters
2052 }
2053
2054 pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2056 &self.multicast_forwarding_counters
2057 }
2058
2059 pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2061 &self.raw_socket_counters
2062 }
2063
2064 pub fn main_table_id(&self) -> &RoutingTableId<I, D> {
2066 &self.main_table_id
2067 }
2068
2069 #[cfg(any(test, feature = "testutils"))]
2071 pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2072 &self.pmtu_cache
2073 }
2074
2075 #[cfg(any(test, feature = "testutils"))]
2077 pub fn filter(&self) -> &RwLock<filter::State<I, I::Weak<BT>, BT>> {
2078 &self.filter
2079 }
2080
2081 pub fn igmp_counters(&self) -> &IgmpCounters {
2083 &self.igmp_counters
2084 }
2085
2086 pub fn mld_counters(&self) -> &MldCounters {
2088 &self.mld_counters
2089 }
2090}
2091
2092impl<
2093 I: IpLayerIpExt,
2094 D: StrongDeviceIdentifier,
2095 BC: TimerContext + RngContext + IpStateBindingsTypes,
2096 > IpStateInner<I, D, BC>
2097{
2098 fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2100 let main_table: PrimaryRc<RwLock<RoutingTable<I, D>>> = PrimaryRc::new(Default::default());
2101 let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2102 Self {
2103 rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2104 tables: Mutex::new(HashMap::from_iter(core::iter::once((
2105 main_table_id.clone(),
2106 main_table,
2107 )))),
2108 main_table_id,
2109 multicast_forwarding: Default::default(),
2110 multicast_forwarding_counters: Default::default(),
2111 fragment_cache: Mutex::new(
2112 IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2113 ),
2114 pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2115 counters: Default::default(),
2116 raw_sockets: Default::default(),
2117 raw_socket_counters: Default::default(),
2118 filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2119 igmp_counters: Default::default(),
2120 mld_counters: Default::default(),
2121 }
2122 }
2123}
2124
2125#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2127#[generic_over_ip()]
2128pub enum IpLayerTimerId {
2129 ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2131 ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2133 PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2135 PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2137 FilterTimerv4(FilterTimerId<Ipv4>),
2139 FilterTimerv6(FilterTimerId<Ipv6>),
2141 MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2143 MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2145}
2146
2147impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2148 fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2149 I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2150 }
2151}
2152
2153impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2154 fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2155 I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2156 }
2157}
2158
2159impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2160 fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2161 I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2162 }
2163}
2164
2165impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2166 fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2167 I::map_ip(
2168 timer,
2169 IpLayerTimerId::MulticastForwardingTimerv4,
2170 IpLayerTimerId::MulticastForwardingTimerv6,
2171 )
2172 }
2173}
2174
2175impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2176where
2177 CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2178 + TimerHandler<BC, FragmentTimerId<Ipv6>>
2179 + TimerHandler<BC, PmtuTimerId<Ipv4>>
2180 + TimerHandler<BC, PmtuTimerId<Ipv6>>
2181 + TimerHandler<BC, FilterTimerId<Ipv4>>
2182 + TimerHandler<BC, FilterTimerId<Ipv6>>
2183 + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2184 + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2185 BC: TimerBindingsTypes,
2186{
2187 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2188 match self {
2189 IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2190 core_ctx.handle_timer(bindings_ctx, id, timer)
2191 }
2192 IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2193 core_ctx.handle_timer(bindings_ctx, id, timer)
2194 }
2195 IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2196 IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2197 IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2198 IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2199 IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2200 core_ctx.handle_timer(bindings_ctx, id, timer)
2201 }
2202 IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2203 core_ctx.handle_timer(bindings_ctx, id, timer)
2204 }
2205 }
2206 }
2207}
2208
2209pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2216 err: I::IcmpError,
2218 src_ip: I::SourceAddress,
2221 dst_ip: SpecifiedAddr<I::Addr>,
2224 frame_dst: Option<FrameDestination>,
2226 device: &'a D,
2228 meta: ParseMetadata,
2231 marks: Marks,
2233}
2234
2235impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2236 fn respond_with_icmp_error<B, BC, CC>(
2243 self,
2244 core_ctx: &mut CC,
2245 bindings_ctx: &mut BC,
2246 mut body: B,
2247 ) where
2248 B: BufferMut,
2249 CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2250 {
2251 let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks } = self;
2252 body.undo_parse(meta);
2256
2257 core_ctx.send_icmp_error_message(
2258 bindings_ctx,
2259 device,
2260 frame_dst,
2261 src_ip,
2262 dst_ip,
2263 body,
2264 err,
2265 &marks,
2266 );
2267 }
2268}
2269
2270fn dispatch_receive_ipv4_packet<
2291 'a,
2292 'b,
2293 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2294 CC: IpLayerIngressContext<Ipv4, BC>,
2295>(
2296 core_ctx: &'a mut CC,
2297 bindings_ctx: &'a mut BC,
2298 device: &'b CC::DeviceId,
2299 frame_dst: Option<FrameDestination>,
2300 mut packet: Ipv4Packet<&'a mut [u8]>,
2301 mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2302 receive_meta: ReceiveIpPacketMeta<Ipv4>,
2303) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2304 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2305
2306 match frame_dst {
2307 Some(FrameDestination::Individual { local: false }) => {
2308 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2309 }
2310 Some(FrameDestination::Individual { local: true })
2311 | Some(FrameDestination::Multicast)
2312 | Some(FrameDestination::Broadcast)
2313 | None => (),
2314 }
2315
2316 let proto = packet.proto();
2317
2318 match core_ctx.filter_handler().local_ingress_hook(
2319 bindings_ctx,
2320 &mut packet,
2321 device,
2322 &mut packet_metadata,
2323 ) {
2324 filter::Verdict::Drop => {
2325 packet_metadata.acknowledge_drop();
2326 return Ok(());
2327 }
2328 filter::Verdict::Accept(()) => {}
2329 }
2330 let marks = packet_metadata.marks;
2331 packet_metadata.acknowledge_drop();
2332
2333 let src_ip = packet.src_ip();
2334 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2338 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2339 debug!(
2340 "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2341 after the LOCAL_INGRESS hook; dropping"
2342 );
2343 return Ok(());
2344 };
2345
2346 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2347
2348 let (prefix, options, body) = packet.parts_with_body_mut();
2349 let buffer = Buf::new(body, ..);
2350 let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2351 let receive_info = LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks };
2352
2353 core_ctx
2354 .dispatch_receive_ip_packet(
2355 bindings_ctx,
2356 device,
2357 src_ip,
2358 dst_ip,
2359 proto,
2360 buffer,
2361 &receive_info,
2362 )
2363 .or_else(|err| {
2364 if let Some(src_ip) = SpecifiedAddr::new(src_ip) {
2365 let (_, _, _, meta) = packet.into_metadata();
2366 Err(IcmpErrorSender {
2367 err: err.into_icmpv4_error(meta.header_len()),
2368 src_ip,
2369 dst_ip,
2370 frame_dst,
2371 device,
2372 meta,
2373 marks,
2374 })
2375 } else {
2376 Ok(())
2377 }
2378 })
2379}
2380
2381fn dispatch_receive_ipv6_packet<
2386 'a,
2387 'b,
2388 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2389 CC: IpLayerIngressContext<Ipv6, BC>,
2390>(
2391 core_ctx: &'a mut CC,
2392 bindings_ctx: &'a mut BC,
2393 device: &'b CC::DeviceId,
2394 frame_dst: Option<FrameDestination>,
2395 mut packet: Ipv6Packet<&'a mut [u8]>,
2396 mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2397 meta: ReceiveIpPacketMeta<Ipv6>,
2398) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2399 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2406
2407 match frame_dst {
2408 Some(FrameDestination::Individual { local: false }) => {
2409 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2410 }
2411 Some(FrameDestination::Individual { local: true })
2412 | Some(FrameDestination::Multicast)
2413 | Some(FrameDestination::Broadcast)
2414 | None => (),
2415 }
2416
2417 let proto = packet.proto();
2418
2419 match core_ctx.filter_handler().local_ingress_hook(
2420 bindings_ctx,
2421 &mut packet,
2422 device,
2423 &mut packet_metadata,
2424 ) {
2425 filter::Verdict::Drop => {
2426 packet_metadata.acknowledge_drop();
2427 return Ok(());
2428 }
2429 filter::Verdict::Accept(()) => {}
2430 }
2431
2432 let Some(src_ip) = packet.src_ipv6() else {
2436 debug!(
2437 "dispatch_receive_ipv6_packet: received packet from non-unicast source {} after the \
2438 LOCAL_INGRESS hook; dropping",
2439 packet.src_ip()
2440 );
2441
2442 core_ctx.increment_both(device, |c| &c.version_rx.non_unicast_source);
2443 return Ok(());
2444 };
2445 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2446 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2447 debug!(
2448 "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2449 after the LOCAL_INGRESS hook; dropping"
2450 );
2451 return Ok(());
2452 };
2453
2454 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2455
2456 let (fixed, extension, body) = packet.parts_with_body_mut();
2457 let buffer = Buf::new(body, ..);
2458 let header_info = Ipv6HeaderInfo { fixed, extension };
2459 let receive_info = LocalDeliveryPacketInfo { meta, header_info, marks: packet_metadata.marks };
2460
2461 let result = core_ctx
2462 .dispatch_receive_ip_packet(
2463 bindings_ctx,
2464 device,
2465 src_ip,
2466 dst_ip,
2467 proto,
2468 buffer,
2469 &receive_info,
2470 )
2471 .or_else(|err| {
2472 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
2473 let (_, _, _, meta) = packet.into_metadata();
2474 Err(IcmpErrorSender {
2475 err: err.into_icmpv6_error(meta.header_len()),
2476 src_ip: *src_ip,
2477 dst_ip,
2478 frame_dst,
2479 device,
2480 meta,
2481 marks: receive_info.marks,
2482 })
2483 } else {
2484 Ok(())
2485 }
2486 });
2487 packet_metadata.acknowledge_drop();
2488 result
2489}
2490
2491pub(crate) struct IpPacketForwarder<
2498 'a,
2499 I: IpLayerIpExt,
2500 D,
2501 A,
2502 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2503> {
2504 inbound_device: &'a D,
2505 outbound_device: &'a D,
2506 packet_meta: IpLayerPacketMetadata<I, A, BT>,
2507 src_ip: I::RecvSrcAddr,
2508 dst_ip: SpecifiedAddr<I::Addr>,
2509 destination: IpPacketDestination<I, &'a D>,
2510 proto: I::Proto,
2511 parse_meta: ParseMetadata,
2512 frame_dst: Option<FrameDestination>,
2513}
2514
2515impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
2516where
2517 I: IpLayerIpExt,
2518 BC: IpLayerBindingsContext<I, D>,
2519{
2520 fn forward_with_buffer<CC, B>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B)
2522 where
2523 B: BufferMut,
2524 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2525 {
2526 let Self {
2527 inbound_device,
2528 outbound_device,
2529 packet_meta,
2530 src_ip,
2531 dst_ip,
2532 destination,
2533 proto,
2534 parse_meta,
2535 frame_dst,
2536 } = self;
2537
2538 let packet = ForwardedPacket::new(src_ip.into(), dst_ip.get(), proto, parse_meta, buffer);
2539
2540 trace!("forward_with_buffer: forwarding {} packet", I::NAME);
2541
2542 let marks = packet_meta.marks;
2543 match send_ip_frame(
2544 core_ctx,
2545 bindings_ctx,
2546 outbound_device,
2547 destination,
2548 packet,
2549 packet_meta,
2550 Mtu::no_limit(),
2551 ) {
2552 Ok(()) => (),
2553 Err(IpSendFrameError { serializer, error }) => {
2554 match error {
2555 IpSendFrameErrorReason::Device(
2556 SendFrameErrorReason::SizeConstraintsViolation,
2557 ) => {
2558 debug!("failed to forward {} packet: MTU exceeded", I::NAME);
2559 core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
2560 let mtu = core_ctx.get_mtu(inbound_device);
2561 let Some(err) = I::new_mtu_exceeded(proto, parse_meta.header_len(), mtu)
2563 else {
2564 return;
2565 };
2566 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2569 return;
2570 };
2571 core_ctx.send_icmp_error_message(
2581 bindings_ctx,
2582 inbound_device,
2583 frame_dst,
2584 src_ip,
2585 dst_ip,
2586 serializer.into_buffer(),
2587 err,
2588 &marks,
2589 );
2590 }
2591 IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
2592 | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
2593 | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
2594 }
2595 debug!("failed to forward {} packet: {error:?}", I::NAME);
2596 }
2597 }
2598 }
2599}
2600
2601pub(crate) enum ForwardingAction<
2603 'a,
2604 I: IpLayerIpExt,
2605 D,
2606 A,
2607 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2608> {
2609 SilentlyDrop,
2611 Forward(IpPacketForwarder<'a, I, D, A, BT>),
2613 DropWithIcmpError(IcmpErrorSender<'a, I, D>),
2616}
2617
2618impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
2619where
2620 I: IpLayerIpExt,
2621 BC: IpLayerBindingsContext<I, D>,
2622{
2623 pub(crate) fn perform_action_with_buffer<CC, B>(
2625 self,
2626 core_ctx: &mut CC,
2627 bindings_ctx: &mut BC,
2628 buffer: B,
2629 ) where
2630 B: BufferMut,
2631 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2632 {
2633 match self {
2634 ForwardingAction::SilentlyDrop => {}
2635 ForwardingAction::Forward(forwarder) => {
2636 forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer)
2637 }
2638 ForwardingAction::DropWithIcmpError(icmp_sender) => {
2639 icmp_sender.respond_with_icmp_error(core_ctx, bindings_ctx, buffer)
2640 }
2641 }
2642 }
2643}
2644
2645pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
2647 core_ctx: &'a mut CC,
2648 mut packet: I::Packet<&'a mut [u8]>,
2649 mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2650 minimum_ttl: Option<u8>,
2651 inbound_device: &'b CC::DeviceId,
2652 outbound_device: &'b CC::DeviceId,
2653 destination: IpPacketDestination<I, &'b CC::DeviceId>,
2654 frame_dst: Option<FrameDestination>,
2655 src_ip: I::RecvSrcAddr,
2656 dst_ip: SpecifiedAddr<I::Addr>,
2657) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
2658where
2659 I: IpLayerIpExt,
2660 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2661 CC: IpLayerForwardingContext<I, BC>,
2662{
2663 const DEFAULT_MINIMUM_FORWARDING_TTL: u8 = 2;
2668 let minimum_ttl = minimum_ttl.unwrap_or(DEFAULT_MINIMUM_FORWARDING_TTL);
2669
2670 let ttl = packet.ttl();
2671 if ttl < minimum_ttl {
2672 debug!(
2673 "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
2674 I::NAME
2675 );
2676 if ttl > 1 {
2688 packet_meta.acknowledge_drop();
2689 return ForwardingAction::SilentlyDrop;
2690 }
2691
2692 core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
2693
2694 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2696 core_ctx.increment_both(inbound_device, |c| &c.unspecified_source);
2697 packet_meta.acknowledge_drop();
2698 return ForwardingAction::SilentlyDrop;
2699 };
2700
2701 let version_specific_meta = packet.version_specific_meta();
2703 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
2704 let err = I::new_ttl_expired(proto, parse_meta.header_len(), version_specific_meta);
2705 let action = ForwardingAction::DropWithIcmpError(IcmpErrorSender {
2706 err,
2707 src_ip,
2708 dst_ip,
2709 frame_dst,
2710 device: inbound_device,
2711 meta: parse_meta,
2712 marks: packet_meta.marks,
2713 });
2714 packet_meta.acknowledge_drop();
2715 return action;
2716 }
2717
2718 trace!("determine_ip_packet_forwarding_action: adequate TTL");
2719
2720 let maybe_ipv6_packet_action = I::map_ip_in(
2726 &packet,
2727 |_packet| None,
2728 |packet| {
2729 Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
2730 },
2731 );
2732 match maybe_ipv6_packet_action {
2733 None => {} Some(Ipv6PacketAction::_Discard) => {
2735 core_ctx.increment_both(inbound_device, |c| {
2736 #[derive(GenericOverIp)]
2737 #[generic_over_ip(I, Ip)]
2738 struct InCounters<'a, I: IpLayerIpExt>(&'a I::RxCounters<Counter>);
2739 I::map_ip_in::<_, _>(
2740 InCounters(&c.version_rx),
2741 |_counters| {
2742 unreachable!(
2743 "`I` must be `Ipv6` because we're handling IPv6 extension headers"
2744 )
2745 },
2746 |InCounters(counters)| &counters.extension_header_discard,
2747 )
2748 });
2749 trace!(
2750 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
2751 discarding packet"
2752 );
2753 packet_meta.acknowledge_drop();
2754 return ForwardingAction::SilentlyDrop;
2755 }
2756 Some(Ipv6PacketAction::Continue) => {
2757 trace!(
2758 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
2759 forwarding packet"
2760 );
2761 }
2762 Some(Ipv6PacketAction::ProcessFragment) => {
2763 unreachable!(
2764 "When forwarding packets, we should only ever look at the hop by hop \
2765 options extension header (if present)"
2766 )
2767 }
2768 };
2769
2770 match core_ctx.filter_handler().forwarding_hook(
2771 I::as_filter_packet(&mut packet),
2772 inbound_device,
2773 outbound_device,
2774 &mut packet_meta,
2775 ) {
2776 filter::Verdict::Drop => {
2777 packet_meta.acknowledge_drop();
2778 trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
2779 return ForwardingAction::SilentlyDrop;
2780 }
2781 filter::Verdict::Accept(()) => {}
2782 }
2783
2784 packet.set_ttl(ttl - 1);
2785 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
2786 ForwardingAction::Forward(IpPacketForwarder {
2787 inbound_device,
2788 outbound_device,
2789 packet_meta,
2790 src_ip,
2791 dst_ip,
2792 destination,
2793 proto,
2794 parse_meta,
2795 frame_dst,
2796 })
2797}
2798
2799pub(crate) fn send_ip_frame<I, CC, BC, S>(
2800 core_ctx: &mut CC,
2801 bindings_ctx: &mut BC,
2802 device: &CC::DeviceId,
2803 destination: IpPacketDestination<I, &CC::DeviceId>,
2804 mut body: S,
2805 mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2806 limit_mtu: Mtu,
2807) -> Result<(), IpSendFrameError<S>>
2808where
2809 I: IpLayerIpExt,
2810 BC: FilterBindingsContext + TxMetadataBindingsTypes,
2811 CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
2812 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>,
2813{
2814 let (verdict, proof) = core_ctx.filter_handler().egress_hook(
2815 bindings_ctx,
2816 &mut body,
2817 device,
2818 &mut packet_metadata,
2819 );
2820 match verdict {
2821 filter::Verdict::Drop => {
2822 packet_metadata.acknowledge_drop();
2823 return Ok(());
2824 }
2825 filter::Verdict::Accept(()) => {}
2826 }
2827
2828 let (conntrack_connection_and_direction, tx_metadata, marks) = packet_metadata.into_parts();
2832 let conntrack_entry = if device.is_loopback() {
2833 conntrack_connection_and_direction
2834 .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
2835 } else {
2836 None
2837 };
2838 let device_ip_layer_metadata = DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks };
2839
2840 if !device.is_loopback()
2844 && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
2845 || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
2846 {
2847 core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
2848 return Err(IpSendFrameError {
2849 serializer: body,
2850 error: IpSendFrameErrorReason::IllegalLoopbackAddress,
2851 });
2852 }
2853
2854 let mtu = limit_mtu.min(core_ctx.get_mtu(device));
2856
2857 let body = body.with_size_limit(mtu.into());
2858
2859 let fits_mtu =
2860 match body.serialize_new_buf(PacketConstraints::UNCONSTRAINED, AlwaysFailBufferAlloc) {
2861 Err(SerializeError::Alloc(())) => true,
2864 Err(SerializeError::SizeLimitExceeded) => false,
2866 };
2867
2868 if fits_mtu {
2869 return core_ctx
2870 .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
2871 .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
2872 serializer: serializer.into_inner(),
2873 error: error.into(),
2874 });
2875 }
2876
2877 core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
2880
2881 let mut device_ip_layer_metadata = Some(device_ip_layer_metadata);
2883 let body = body.into_inner();
2884 let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
2885 Ok(mut fragmenter) => loop {
2886 let (fragment, has_more) = match fragmenter.next() {
2887 None => break Ok(()),
2888 Some(f) => f,
2889 };
2890
2891 let device_ip_layer_metadata = if has_more {
2896 let device_ip_layer_metadata = device_ip_layer_metadata.as_ref().unwrap();
2898 DeviceIpLayerMetadata {
2899 conntrack_entry: device_ip_layer_metadata.conntrack_entry.clone(),
2900 tx_metadata: Default::default(),
2901 marks: device_ip_layer_metadata.marks,
2902 }
2903 } else {
2904 device_ip_layer_metadata.take().unwrap()
2906 };
2907
2908 match core_ctx.send_ip_frame(
2909 bindings_ctx,
2910 device,
2911 destination.clone(),
2912 device_ip_layer_metadata,
2913 fragment,
2914 proof.clone_for_fragmentation(),
2915 ) {
2916 Ok(()) => {
2917 core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
2918 }
2919 Err(ErrorAndSerializer { serializer: _, error }) => {
2920 core_ctx
2921 .increment_both(device, |c| &c.fragmentation.error_fragmented_serializer);
2922 break Err(error);
2923 }
2924 }
2925 },
2926 Err(e) => {
2927 core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
2928 Err(SendFrameErrorReason::SizeConstraintsViolation)
2929 }
2930 };
2931 result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
2932}
2933
2934struct AlwaysFailBufferAlloc;
2939
2940impl BufferAlloc<Never> for AlwaysFailBufferAlloc {
2941 type Error = ();
2942 fn alloc(self, _len: usize) -> Result<Never, Self::Error> {
2943 Err(())
2944 }
2945}
2946
2947macro_rules! drop_packet_and_undo_parse {
2956 ($packet:expr, $buffer:expr) => {{
2957 let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
2958 $buffer.undo_parse(meta);
2959 (src_ip, dst_ip, proto, meta)
2960 }};
2961}
2962
2963enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
2966 Done,
2969
2970 NotNeeded(I::Packet<&'a mut [u8]>),
2973
2974 Reassembled(Vec<u8>),
2977}
2978
2979fn process_fragment<'a, I, CC, BC>(
2985 core_ctx: &mut CC,
2986 bindings_ctx: &mut BC,
2987 device: &CC::DeviceId,
2988 packet: I::Packet<&'a mut [u8]>,
2989) -> ProcessFragmentResult<'a, I>
2990where
2991 I: IpLayerIpExt,
2992 for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
2993 CC: IpLayerIngressContext<I, BC>,
2994 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2995{
2996 match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
2997 FragmentProcessingState::NotNeeded(packet) => {
2999 trace!("receive_ip_packet: not fragmented");
3000 ProcessFragmentResult::NotNeeded(packet)
3001 }
3002 FragmentProcessingState::Ready { key, packet_len } => {
3004 trace!("receive_ip_packet: fragmented, ready for reassembly");
3005 let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3007
3008 let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3010 core_ctx,
3011 bindings_ctx,
3012 &key,
3013 buffer.buffer_view_mut(),
3014 ) {
3015 Ok(()) => ProcessFragmentResult::Reassembled(buffer.into_inner()),
3017 Err(e) => {
3018 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3019 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3020 ProcessFragmentResult::Done
3021 }
3022 };
3023 reassemble_result
3024 }
3025 FragmentProcessingState::NeedMoreFragments => {
3028 core_ctx.increment_both(device, |c| &c.need_more_fragments);
3029 trace!("receive_ip_packet: fragmented, need more before reassembly");
3030 ProcessFragmentResult::Done
3031 }
3032 FragmentProcessingState::InvalidFragment => {
3034 core_ctx.increment_both(device, |c| &c.invalid_fragment);
3035 trace!("receive_ip_packet: fragmented, invalid");
3036 ProcessFragmentResult::Done
3037 }
3038 FragmentProcessingState::OutOfMemory => {
3039 core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3040 trace!("receive_ip_packet: fragmented, dropped because OOM");
3041 ProcessFragmentResult::Done
3042 }
3043 }
3044}
3045
3046macro_rules! try_parse_ip_packet {
3056 ($buffer:expr) => {{
3057 let p_len = $buffer.prefix_len();
3058 let s_len = $buffer.suffix_len();
3059
3060 let result = $buffer.parse_mut();
3061
3062 if let Err(err) = result {
3063 let n_p_len = $buffer.prefix_len();
3065 let n_s_len = $buffer.suffix_len();
3066
3067 if p_len > n_p_len {
3068 $buffer.grow_front(p_len - n_p_len);
3069 }
3070
3071 if s_len > n_s_len {
3072 $buffer.grow_back(s_len - n_s_len);
3073 }
3074
3075 Err(err)
3076 } else {
3077 result
3078 }
3079 }};
3080}
3081
3082macro_rules! clone_packet_for_mcast_forwarding {
3100 {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3101 let mut $new_data = $packet.to_vec();
3102 let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3103 let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3104 };
3105}
3106
3107pub fn receive_ipv4_packet<
3112 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3113 B: BufferMut,
3114 CC: IpLayerIngressContext<Ipv4, BC>,
3115>(
3116 core_ctx: &mut CC,
3117 bindings_ctx: &mut BC,
3118 device: &CC::DeviceId,
3119 frame_dst: Option<FrameDestination>,
3120 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3121 buffer: B,
3122) {
3123 if !core_ctx.is_ip_device_enabled(&device) {
3124 return;
3125 }
3126
3127 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3130
3131 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3132 trace!("receive_ip_packet({device:?})");
3133
3134 let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3135 Ok(packet) => packet,
3136 Err(IpParseError::ParameterProblem {
3145 src_ip,
3146 dst_ip,
3147 code,
3148 pointer,
3149 must_send_icmp,
3150 header_len,
3151 action,
3152 }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
3153 core_ctx.increment_both(device, |c| &c.parameter_problem);
3154 assert!(!action.should_send_icmp_to_multicast());
3156 let dst_ip = match SpecifiedAddr::new(dst_ip) {
3157 Some(ip) => ip,
3158 None => {
3159 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3160 debug!("receive_ipv4_packet: Received packet with unspecified destination IP address; dropping");
3161 return;
3162 }
3163 };
3164 let src_ip = match SpecifiedAddr::new(src_ip) {
3165 Some(ip) => ip,
3166 None => {
3167 core_ctx.increment_both(device, |c| &c.unspecified_source);
3168 trace!("receive_ipv4_packet: Cannot send ICMP error in response to packet with unspecified source IP address");
3169 return;
3170 }
3171 };
3172 IcmpErrorHandler::<Ipv4, _>::send_icmp_error_message(
3173 core_ctx,
3174 bindings_ctx,
3175 device,
3176 frame_dst,
3177 src_ip,
3178 dst_ip,
3179 buffer,
3180 Icmpv4Error {
3181 kind: Icmpv4ErrorKind::ParameterProblem {
3182 code,
3183 pointer,
3184 fragment_type: Ipv4FragmentType::InitialFragment,
3187 },
3188 header_len,
3189 },
3190 &device_ip_layer_metadata.marks,
3191 );
3192 return;
3193 }
3194 _ => return, };
3196
3197 if !packet.dst_ip().is_specified() {
3202 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3203 debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3204 return;
3205 };
3206
3207 let mut packet = match process_fragment(core_ctx, bindings_ctx, device, packet) {
3220 ProcessFragmentResult::Done => return,
3221 ProcessFragmentResult::NotNeeded(packet) => packet,
3222 ProcessFragmentResult::Reassembled(buf) => {
3223 let buf = Buf::new(buf, ..);
3224 buffer = packet::Either::B(buf);
3225
3226 match buffer.parse_mut() {
3227 Ok(packet) => packet,
3228 Err(err) => {
3229 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3230 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3231 return;
3232 }
3233 }
3234 }
3235 };
3236
3237 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3240 core_ctx,
3241 device,
3242 device_ip_layer_metadata,
3243 );
3244 let mut filter = core_ctx.filter_handler();
3245 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3246 IngressVerdict::Verdict(filter::Verdict::Accept(())) => {}
3247 IngressVerdict::Verdict(filter::Verdict::Drop) => {
3248 packet_metadata.acknowledge_drop();
3249 return;
3250 }
3251 IngressVerdict::TransparentLocalDelivery { addr, port } => {
3252 drop(filter);
3255
3256 let Some(addr) = SpecifiedAddr::new(addr) else {
3257 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3258 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3259 return;
3260 };
3261
3262 let receive_meta = ReceiveIpPacketMeta {
3263 broadcast: None,
3267 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3268 };
3269
3270 dispatch_receive_ipv4_packet(
3274 core_ctx,
3275 bindings_ctx,
3276 device,
3277 frame_dst,
3278 packet,
3279 packet_metadata,
3280 receive_meta,
3281 )
3282 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3283 return;
3284 }
3285 }
3286 drop(filter);
3289
3290 let action = receive_ipv4_packet_action(
3291 core_ctx,
3292 bindings_ctx,
3293 device,
3294 &packet,
3295 frame_dst,
3296 &packet_metadata.marks,
3297 );
3298 match action {
3299 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3300 let src_ip = packet.src_ip();
3301 let mut packet_metadata = Some(packet_metadata);
3308 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3309 clone_packet_for_mcast_forwarding! {
3310 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3311 };
3312 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3313 core_ctx,
3314 copy_of_packet,
3315 packet_metadata.take().unwrap_or_default(),
3316 Some(*min_ttl),
3317 device,
3318 &output_interface,
3319 IpPacketDestination::from_addr(dst_ip),
3320 frame_dst,
3321 src_ip,
3322 dst_ip,
3323 )
3324 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3325 }
3326
3327 if let Some(address_status) = address_status {
3329 let receive_meta = ReceiveIpPacketMeta {
3330 broadcast: address_status.to_broadcast_marker(),
3331 transparent_override: None,
3332 };
3333 dispatch_receive_ipv4_packet(
3334 core_ctx,
3335 bindings_ctx,
3336 device,
3337 frame_dst,
3338 packet,
3339 packet_metadata.take().unwrap_or_default(),
3340 receive_meta,
3341 )
3342 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3343 }
3344 }
3345 ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
3346 match internal_forwarding {
3349 InternalForwarding::Used(outbound_device) => {
3350 core_ctx.increment_both(device, |c| &c.forward);
3351 match core_ctx.filter_handler().forwarding_hook(
3352 &mut packet,
3353 device,
3354 &outbound_device,
3355 &mut packet_metadata,
3356 ) {
3357 filter::Verdict::Drop => {
3358 packet_metadata.acknowledge_drop();
3359 return;
3360 }
3361 filter::Verdict::Accept(()) => {}
3362 }
3363 }
3364 InternalForwarding::NotUsed => {}
3365 }
3366
3367 let receive_meta = ReceiveIpPacketMeta {
3368 broadcast: address_status.to_broadcast_marker(),
3369 transparent_override: None,
3370 };
3371 dispatch_receive_ipv4_packet(
3372 core_ctx,
3373 bindings_ctx,
3374 device,
3375 frame_dst,
3376 packet,
3377 packet_metadata,
3378 receive_meta,
3379 )
3380 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3381 }
3382 ReceivePacketAction::Forward {
3383 original_dst,
3384 dst: Destination { device: dst_device, next_hop },
3385 } => {
3386 let src_ip = packet.src_ip();
3387 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3388 core_ctx,
3389 packet,
3390 packet_metadata,
3391 None,
3392 device,
3393 &dst_device,
3394 IpPacketDestination::from_next_hop(next_hop, original_dst),
3395 frame_dst,
3396 src_ip,
3397 original_dst,
3398 )
3399 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3400 }
3401 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3402 use packet_formats::ipv4::Ipv4Header as _;
3403 core_ctx.increment_both(device, |c| &c.no_route_to_host);
3404 debug!("received IPv4 packet with no known route to destination {}", dst_ip);
3405 let fragment_type = packet.fragment_type();
3406 let (src_ip, _, proto, meta): (_, Ipv4Addr, _, _) =
3407 drop_packet_and_undo_parse!(packet, buffer);
3408 let marks = packet_metadata.marks;
3409 packet_metadata.acknowledge_drop();
3410 let src_ip = match SpecifiedAddr::new(src_ip) {
3411 Some(ip) => ip,
3412 None => {
3413 core_ctx.increment_both(device, |c| &c.unspecified_source);
3414 trace!("receive_ipv4_packet: Cannot send ICMP error in response to packet with unspecified source IP address");
3415 return;
3416 }
3417 };
3418 IcmpErrorHandler::<Ipv4, _>::send_icmp_error_message(
3419 core_ctx,
3420 bindings_ctx,
3421 device,
3422 frame_dst,
3423 src_ip,
3424 dst_ip,
3425 buffer,
3426 Icmpv4Error {
3427 kind: Icmpv4ErrorKind::NetUnreachable { proto, fragment_type },
3428 header_len: meta.header_len(),
3429 },
3430 &marks,
3431 );
3432 }
3433 ReceivePacketAction::Drop { reason } => {
3434 let src_ip = packet.src_ip();
3435 let dst_ip = packet.dst_ip();
3436 packet_metadata.acknowledge_drop();
3437 core_ctx.increment_both(device, |c| &c.dropped);
3438 debug!(
3439 "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
3440 {device:?}: {reason:?}",
3441 );
3442 }
3443 }
3444}
3445
3446pub fn receive_ipv6_packet<
3451 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3452 B: BufferMut,
3453 CC: IpLayerIngressContext<Ipv6, BC>,
3454>(
3455 core_ctx: &mut CC,
3456 bindings_ctx: &mut BC,
3457 device: &CC::DeviceId,
3458 frame_dst: Option<FrameDestination>,
3459 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3460 buffer: B,
3461) {
3462 if !core_ctx.is_ip_device_enabled(&device) {
3463 return;
3464 }
3465
3466 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3469
3470 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3471 trace!("receive_ipv6_packet({:?})", device);
3472
3473 let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
3474 Ok(packet) => packet,
3475 Err(IpParseError::ParameterProblem {
3481 src_ip,
3482 dst_ip,
3483 code,
3484 pointer,
3485 must_send_icmp,
3486 header_len: _,
3487 action,
3488 }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
3489 core_ctx.increment_both(device, |c| &c.parameter_problem);
3490 let dst_ip = match SpecifiedAddr::new(dst_ip) {
3491 Some(ip) => ip,
3492 None => {
3493 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3494 debug!("receive_ipv6_packet: Received packet with unspecified destination IP address; dropping");
3495 return;
3496 }
3497 };
3498 let src_ip = match UnicastAddr::new(src_ip) {
3499 Some(ip) => ip,
3500 None => {
3501 core_ctx.increment_both(device, |c| &c.version_rx.non_unicast_source);
3502 trace!("receive_ipv6_packet: Cannot send ICMP error in response to packet with non unicast source IP address");
3503 return;
3504 }
3505 };
3506 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3507 core_ctx,
3508 bindings_ctx,
3509 device,
3510 frame_dst,
3511 src_ip,
3512 dst_ip,
3513 buffer,
3514 Icmpv6ErrorKind::ParameterProblem {
3515 code,
3516 pointer,
3517 allow_dst_multicast: action.should_send_icmp_to_multicast(),
3518 },
3519 &device_ip_layer_metadata.marks,
3520 );
3521 return;
3522 }
3523 _ => return, };
3525
3526 trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
3527
3528 if packet.src_ipv6().is_none() {
3534 debug!(
3535 "receive_ipv6_packet: received packet from non-unicast source {}; dropping",
3536 packet.src_ip()
3537 );
3538 core_ctx.increment_both(device, |c| &c.version_rx.non_unicast_source);
3539 return;
3540 };
3541 if !packet.dst_ip().is_specified() {
3542 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3543 debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
3544 return;
3545 };
3546
3547 let (mut packet, delivery_extension_header_action) =
3558 match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
3559 Ipv6PacketAction::_Discard => {
3560 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3561 trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
3562 return;
3563 }
3564 Ipv6PacketAction::Continue => {
3565 trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
3566 (packet, Some(Ipv6PacketAction::Continue))
3567 }
3568 Ipv6PacketAction::ProcessFragment => {
3569 trace!(
3570 "receive_ipv6_packet: handled IPv6 extension headers: handling \
3571 fragmented packet"
3572 );
3573
3574 match process_fragment(core_ctx, bindings_ctx, device, packet) {
3586 ProcessFragmentResult::Done => return,
3587 ProcessFragmentResult::NotNeeded(packet) => {
3588 (packet, Some(Ipv6PacketAction::Continue))
3603 }
3604 ProcessFragmentResult::Reassembled(buf) => {
3605 let buf = Buf::new(buf, ..);
3606 buffer = packet::Either::B(buf);
3607
3608 match buffer.parse_mut() {
3609 Ok(packet) => (packet, None),
3610 Err(err) => {
3611 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3612 debug!(
3613 "receive_ip_packet: fragmented, failed to reassemble: {:?}",
3614 err
3615 );
3616 return;
3617 }
3618 }
3619 }
3620 }
3621 }
3622 };
3623
3624 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3625 core_ctx,
3626 device,
3627 device_ip_layer_metadata,
3628 );
3629 let mut filter = core_ctx.filter_handler();
3630
3631 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3632 IngressVerdict::Verdict(filter::Verdict::Accept(())) => {}
3633 IngressVerdict::Verdict(filter::Verdict::Drop) => {
3634 packet_metadata.acknowledge_drop();
3635 return;
3636 }
3637 IngressVerdict::TransparentLocalDelivery { addr, port } => {
3638 drop(filter);
3641
3642 let Some(addr) = SpecifiedAddr::new(addr) else {
3643 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3644 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3645 return;
3646 };
3647
3648 let receive_meta = ReceiveIpPacketMeta {
3649 broadcast: None,
3650 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3651 };
3652
3653 dispatch_receive_ipv6_packet(
3657 core_ctx,
3658 bindings_ctx,
3659 device,
3660 frame_dst,
3661 packet,
3662 packet_metadata,
3663 receive_meta,
3664 )
3665 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3666 return;
3667 }
3668 }
3669 drop(filter);
3672
3673 let Some(src_ip) = packet.src_ipv6() else {
3674 debug!(
3675 "receive_ipv6_packet: received packet from non-unicast source {}; dropping",
3676 packet.src_ip()
3677 );
3678 core_ctx.increment_both(device, |c| &c.version_rx.non_unicast_source);
3679 return;
3680 };
3681
3682 match receive_ipv6_packet_action(
3683 core_ctx,
3684 bindings_ctx,
3685 device,
3686 &packet,
3687 frame_dst,
3688 &packet_metadata.marks,
3689 ) {
3690 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3691 let mut packet_metadata = Some(packet_metadata);
3698 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3699 clone_packet_for_mcast_forwarding! {
3700 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3701 };
3702 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
3703 core_ctx,
3704 copy_of_packet,
3705 packet_metadata.take().unwrap_or_default(),
3706 Some(*min_ttl),
3707 device,
3708 &output_interface,
3709 IpPacketDestination::from_addr(dst_ip),
3710 frame_dst,
3711 src_ip,
3712 dst_ip,
3713 )
3714 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3715 }
3716
3717 if let Some(_) = address_status {
3719 let receive_meta =
3720 ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
3721
3722 dispatch_receive_ipv6_packet(
3723 core_ctx,
3724 bindings_ctx,
3725 device,
3726 frame_dst,
3727 packet,
3728 packet_metadata.take().unwrap_or_default(),
3729 receive_meta,
3730 )
3731 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3732 }
3733 }
3734 ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
3735 trace!("receive_ipv6_packet: delivering locally");
3736
3737 let action = if let Some(action) = delivery_extension_header_action {
3738 action
3739 } else {
3740 ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
3741 };
3742 match action {
3743 Ipv6PacketAction::_Discard => {
3744 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3745 trace!(
3746 "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
3747 );
3748 packet_metadata.acknowledge_drop();
3749 }
3750 Ipv6PacketAction::Continue => {
3751 trace!(
3752 "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
3753 );
3754
3755 match internal_forwarding {
3758 InternalForwarding::Used(outbound_device) => {
3759 core_ctx.increment_both(device, |c| &c.forward);
3760 match core_ctx.filter_handler().forwarding_hook(
3761 &mut packet,
3762 device,
3763 &outbound_device,
3764 &mut packet_metadata,
3765 ) {
3766 filter::Verdict::Drop => {
3767 packet_metadata.acknowledge_drop();
3768 return;
3769 }
3770 filter::Verdict::Accept(()) => {}
3771 }
3772 }
3773 InternalForwarding::NotUsed => {}
3774 }
3775
3776 let meta = ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
3777
3778 dispatch_receive_ipv6_packet(
3783 core_ctx,
3784 bindings_ctx,
3785 device,
3786 frame_dst,
3787 packet,
3788 packet_metadata,
3789 meta,
3790 )
3791 .unwrap_or_else(|err| {
3792 err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer)
3793 });
3794 }
3795 Ipv6PacketAction::ProcessFragment => {
3796 debug!("receive_ipv6_packet: found fragment header after reassembly; dropping");
3797 packet_metadata.acknowledge_drop();
3798 }
3799 }
3800 }
3801 ReceivePacketAction::Forward {
3802 original_dst,
3803 dst: Destination { device: dst_device, next_hop },
3804 } => {
3805 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
3806 core_ctx,
3807 packet,
3808 packet_metadata,
3809 None,
3810 device,
3811 &dst_device,
3812 IpPacketDestination::from_next_hop(next_hop, original_dst),
3813 frame_dst,
3814 src_ip,
3815 original_dst,
3816 )
3817 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3818 }
3819 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3820 core_ctx.increment_both(device, |c| &c.no_route_to_host);
3821 let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
3822 drop_packet_and_undo_parse!(packet, buffer);
3823 debug!("received IPv6 packet with no known route to destination {}", dst_ip);
3824 let marks = packet_metadata.marks;
3825 packet_metadata.acknowledge_drop();
3826
3827 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
3828 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3829 core_ctx,
3830 bindings_ctx,
3831 device,
3832 frame_dst,
3833 *src_ip,
3834 dst_ip,
3835 buffer,
3836 Icmpv6ErrorKind::NetUnreachable { proto, header_len: meta.header_len() },
3837 &marks,
3838 );
3839 }
3840 }
3841 ReceivePacketAction::Drop { reason } => {
3842 core_ctx.increment_both(device, |c| &c.dropped);
3843 let src_ip = packet.src_ip();
3844 let dst_ip = packet.dst_ip();
3845 packet_metadata.acknowledge_drop();
3846 debug!(
3847 "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
3848 {device:?}: {reason:?}",
3849 );
3850 }
3851 }
3852}
3853
3854#[derive(Debug, PartialEq)]
3856pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
3857 Deliver {
3859 address_status: I::AddressStatus,
3861 internal_forwarding: InternalForwarding<DeviceId>,
3864 },
3865
3866 Forward {
3868 original_dst: SpecifiedAddr<I::Addr>,
3870 dst: Destination<I::Addr, DeviceId>,
3872 },
3873
3874 MulticastForward {
3882 targets: MulticastRouteTargets<DeviceId>,
3884 address_status: Option<I::AddressStatus>,
3887 dst_ip: SpecifiedAddr<I::Addr>,
3889 },
3890
3891 SendNoRouteToDest {
3897 dst: SpecifiedAddr<I::Addr>,
3899 },
3900
3901 #[allow(missing_docs)]
3905 Drop { reason: DropReason },
3906}
3907
3908#[derive(Debug, PartialEq)]
3910pub enum DropReason {
3911 Tentative,
3913 UnspecifiedDestination,
3915 ForwardUnspecifiedSource,
3917 ForwardingDisabledInboundIface,
3920 MulticastNoInterest,
3926}
3927
3928pub fn receive_ipv4_packet_action<BC, CC, B>(
3930 core_ctx: &mut CC,
3931 bindings_ctx: &mut BC,
3932 device: &CC::DeviceId,
3933 packet: &Ipv4Packet<B>,
3934 frame_dst: Option<FrameDestination>,
3935 marks: &Marks,
3936) -> ReceivePacketAction<Ipv4, CC::DeviceId>
3937where
3938 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3939 CC: IpLayerContext<Ipv4, BC>,
3940 B: SplitByteSlice,
3941{
3942 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
3943 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3944 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
3945 };
3946
3947 let first_status = if device.is_loopback() {
3963 core_ctx.with_address_statuses(dst_ip, |it| it.map(|(_device, status)| status).next())
3964 } else {
3965 core_ctx.address_status_for_device(dst_ip, device).into_present()
3966 };
3967 match first_status {
3968 Some(
3969 address_status @ (Ipv4PresentAddressStatus::Unicast
3970 | Ipv4PresentAddressStatus::LoopbackSubnet),
3971 ) => {
3972 core_ctx.increment_both(device, |c| &c.deliver_unicast);
3973 ReceivePacketAction::Deliver {
3974 address_status,
3975 internal_forwarding: InternalForwarding::NotUsed,
3976 }
3977 }
3978 Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
3979 receive_ip_multicast_packet_action(
3980 core_ctx,
3981 bindings_ctx,
3982 device,
3983 packet,
3984 Some(address_status),
3985 dst_ip,
3986 frame_dst,
3987 )
3988 }
3989 Some(
3990 address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
3991 | Ipv4PresentAddressStatus::SubnetBroadcast),
3992 ) => {
3993 core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
3994 ReceivePacketAction::Deliver {
3995 address_status,
3996 internal_forwarding: InternalForwarding::NotUsed,
3997 }
3998 }
3999 None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4000 core_ctx,
4001 bindings_ctx,
4002 dst_ip,
4003 device,
4004 packet,
4005 frame_dst,
4006 marks,
4007 ),
4008 }
4009}
4010
4011pub fn receive_ipv6_packet_action<BC, CC, B>(
4013 core_ctx: &mut CC,
4014 bindings_ctx: &mut BC,
4015 device: &CC::DeviceId,
4016 packet: &Ipv6Packet<B>,
4017 frame_dst: Option<FrameDestination>,
4018 marks: &Marks,
4019) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4020where
4021 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4022 CC: IpLayerContext<Ipv6, BC>,
4023 B: SplitByteSlice,
4024{
4025 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4026 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4027 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4028 };
4029
4030 fn choose_highest_priority(
4049 address_statuses: impl Iterator<Item = Ipv6PresentAddressStatus>,
4050 dst_ip: SpecifiedAddr<Ipv6Addr>,
4051 ) -> Option<Ipv6PresentAddressStatus> {
4052 address_statuses.max_by(|lhs, rhs| {
4053 use Ipv6PresentAddressStatus::*;
4054 match (lhs, rhs) {
4055 (UnicastAssigned | UnicastTentative, Multicast)
4056 | (Multicast, UnicastAssigned | UnicastTentative) => {
4057 unreachable!("the IPv6 address {:?} is not both unicast and multicast", dst_ip)
4058 }
4059 (UnicastAssigned, UnicastTentative) => Ordering::Greater,
4060 (UnicastTentative, UnicastAssigned) => Ordering::Less,
4061 (UnicastTentative, UnicastTentative)
4062 | (UnicastAssigned, UnicastAssigned)
4063 | (Multicast, Multicast) => Ordering::Equal,
4064 }
4065 })
4066 }
4067
4068 let highest_priority = if device.is_loopback() {
4069 core_ctx.with_address_statuses(dst_ip, |it| {
4070 let it = it.map(|(_device, status)| status);
4071 choose_highest_priority(it, dst_ip)
4072 })
4073 } else {
4074 core_ctx.address_status_for_device(dst_ip, device).into_present()
4075 };
4076 match highest_priority {
4077 Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
4078 receive_ip_multicast_packet_action(
4079 core_ctx,
4080 bindings_ctx,
4081 device,
4082 packet,
4083 Some(address_status),
4084 dst_ip,
4085 frame_dst,
4086 )
4087 }
4088 Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
4089 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4090 ReceivePacketAction::Deliver {
4091 address_status,
4092 internal_forwarding: InternalForwarding::NotUsed,
4093 }
4094 }
4095 Some(Ipv6PresentAddressStatus::UnicastTentative) => {
4096 core_ctx.increment_both(device, |c| &c.version_rx.drop_for_tentative);
4127 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4128 }
4129 None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
4130 core_ctx,
4131 bindings_ctx,
4132 dst_ip,
4133 device,
4134 packet,
4135 frame_dst,
4136 marks,
4137 ),
4138 }
4139}
4140
4141fn receive_ip_multicast_packet_action<
4144 I: IpLayerIpExt,
4145 B: SplitByteSlice,
4146 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4147 CC: IpLayerContext<I, BC>,
4148>(
4149 core_ctx: &mut CC,
4150 bindings_ctx: &mut BC,
4151 device: &CC::DeviceId,
4152 packet: &I::Packet<B>,
4153 address_status: Option<I::AddressStatus>,
4154 dst_ip: SpecifiedAddr<I::Addr>,
4155 frame_dst: Option<FrameDestination>,
4156) -> ReceivePacketAction<I, CC::DeviceId> {
4157 let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
4158 core_ctx,
4159 bindings_ctx,
4160 packet,
4161 device,
4162 frame_dst,
4163 );
4164 match (targets, address_status) {
4165 (Some(targets), address_status) => {
4166 if address_status.is_some() {
4167 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4168 }
4169 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
4170 }
4171 (None, Some(address_status)) => {
4172 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4175 ReceivePacketAction::Deliver {
4176 address_status,
4177 internal_forwarding: InternalForwarding::NotUsed,
4178 }
4179 }
4180 (None, None) => {
4181 core_ctx.increment_both(device, |c| &c.multicast_no_interest);
4190 ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
4191 }
4192 }
4193}
4194
4195fn receive_ip_packet_action_common<
4198 I: IpLayerIpExt,
4199 B: SplitByteSlice,
4200 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4201 CC: IpLayerContext<I, BC>,
4202>(
4203 core_ctx: &mut CC,
4204 bindings_ctx: &mut BC,
4205 dst_ip: SpecifiedAddr<I::Addr>,
4206 device_id: &CC::DeviceId,
4207 packet: &I::Packet<B>,
4208 frame_dst: Option<FrameDestination>,
4209 marks: &Marks,
4210) -> ReceivePacketAction<I, CC::DeviceId> {
4211 if dst_ip.is_multicast() {
4212 return receive_ip_multicast_packet_action(
4213 core_ctx,
4214 bindings_ctx,
4215 device_id,
4216 packet,
4217 None,
4218 dst_ip,
4219 frame_dst,
4220 );
4221 }
4222
4223 if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
4225 core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
4238 return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
4239 }
4240 let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
4247 return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
4248 };
4249
4250 if let Some(dst_ip) = NonMappedAddr::new(dst_ip).and_then(NonMulticastAddr::new) {
4257 if let Some((outbound_device, address_status)) =
4258 get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
4259 {
4260 return ReceivePacketAction::Deliver {
4261 address_status,
4262 internal_forwarding: InternalForwarding::Used(outbound_device),
4263 };
4264 }
4265 }
4266
4267 match lookup_route_table(
4268 core_ctx,
4269 *dst_ip,
4270 RuleInput {
4271 packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
4272 marks,
4273 },
4274 ) {
4275 Some(dst) => {
4276 core_ctx.increment_both(device_id, |c| &c.forward);
4277 ReceivePacketAction::Forward { original_dst: dst_ip, dst }
4278 }
4279 None => {
4280 core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
4281 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
4282 }
4283 }
4284}
4285
4286fn lookup_route_table<I: IpLayerIpExt, CC: IpStateContext<I>>(
4288 core_ctx: &mut CC,
4289 dst_ip: I::Addr,
4290 rule_input: RuleInput<'_, I, CC::DeviceId>,
4291) -> Option<Destination<I::Addr, CC::DeviceId>> {
4292 let bound_device = match rule_input.packet_origin {
4293 PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
4294 PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
4295 };
4296 core_ctx.with_rules_table(|core_ctx, rules| {
4297 match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
4298 match table.lookup(core_ctx, bound_device, dst_ip) {
4299 Some(dst) => ControlFlow::Break(Some(dst)),
4300 None => ControlFlow::Continue(()),
4301 }
4302 }) {
4303 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
4304 inner: dst,
4305 observed_source_address_matcher: _,
4306 })) => dst,
4307 ControlFlow::Break(RuleAction::Unreachable) => None,
4308 ControlFlow::Continue(RuleWalkInfo {
4309 inner: (),
4310 observed_source_address_matcher: _,
4311 }) => None,
4312 }
4313 })
4314}
4315
4316#[derive(Debug, Derivative, Clone)]
4318#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
4319pub enum IpPacketDestination<I: BroadcastIpExt, D> {
4320 Broadcast(I::BroadcastMarker),
4322
4323 Multicast(MulticastAddr<I::Addr>),
4325
4326 Neighbor(SpecifiedAddr<I::Addr>),
4329
4330 Loopback(D),
4333}
4334
4335impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
4336 pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
4338 match MulticastAddr::new(addr.into_addr()) {
4339 Some(mc_addr) => Self::Multicast(mc_addr),
4340 None => Self::Neighbor(addr),
4341 }
4342 }
4343
4344 pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
4346 match next_hop {
4347 NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
4348 NextHop::Gateway(gateway) => Self::Neighbor(gateway),
4349 NextHop::Broadcast(marker) => Self::Broadcast(marker),
4350 }
4351 }
4352}
4353
4354#[derive(Debug, Clone)]
4356pub struct SendIpPacketMeta<I: IpExt, D, Src> {
4357 pub device: D,
4359
4360 pub src_ip: Src,
4362
4363 pub dst_ip: SpecifiedAddr<I::Addr>,
4365
4366 pub destination: IpPacketDestination<I, D>,
4368
4369 pub proto: I::Proto,
4371
4372 pub ttl: Option<NonZeroU8>,
4376
4377 pub mtu: Mtu,
4382
4383 pub dscp_and_ecn: DscpAndEcn,
4385}
4386
4387impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4388 for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
4389{
4390 fn from(
4391 SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
4392 I,
4393 D,
4394 SpecifiedAddr<I::Addr>,
4395 >,
4396 ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
4397 SendIpPacketMeta {
4398 device,
4399 src_ip: Some(src_ip),
4400 dst_ip,
4401 destination,
4402 proto,
4403 ttl,
4404 mtu,
4405 dscp_and_ecn,
4406 }
4407 }
4408}
4409
4410pub trait IpLayerHandler<I: IpExt + FragmentationIpExt, BC>: DeviceIdContext<AnyDevice> {
4416 fn send_ip_packet_from_device<S>(
4419 &mut self,
4420 bindings_ctx: &mut BC,
4421 meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4422 body: S,
4423 ) -> Result<(), IpSendFrameError<S>>
4424 where
4425 S: TransportPacketSerializer<I>,
4426 S::Buffer: BufferMut;
4427
4428 fn send_ip_frame<S>(
4435 &mut self,
4436 bindings_ctx: &mut BC,
4437 device: &Self::DeviceId,
4438 destination: IpPacketDestination<I, &Self::DeviceId>,
4439 body: S,
4440 ) -> Result<(), IpSendFrameError<S>>
4441 where
4442 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>;
4443}
4444
4445impl<
4446 I: IpLayerIpExt,
4447 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
4448 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4449 > IpLayerHandler<I, BC> for CC
4450{
4451 fn send_ip_packet_from_device<S>(
4452 &mut self,
4453 bindings_ctx: &mut BC,
4454 meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4455 body: S,
4456 ) -> Result<(), IpSendFrameError<S>>
4457 where
4458 S: TransportPacketSerializer<I>,
4459 S::Buffer: BufferMut,
4460 {
4461 send_ip_packet_from_device(self, bindings_ctx, meta, body, IpLayerPacketMetadata::default())
4462 }
4463
4464 fn send_ip_frame<S>(
4465 &mut self,
4466 bindings_ctx: &mut BC,
4467 device: &Self::DeviceId,
4468 destination: IpPacketDestination<I, &Self::DeviceId>,
4469 body: S,
4470 ) -> Result<(), IpSendFrameError<S>>
4471 where
4472 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>,
4473 {
4474 send_ip_frame(
4475 self,
4476 bindings_ctx,
4477 device,
4478 destination,
4479 body,
4480 IpLayerPacketMetadata::default(),
4481 Mtu::no_limit(),
4482 )
4483 }
4484}
4485
4486pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
4493 core_ctx: &mut CC,
4494 bindings_ctx: &mut BC,
4495 meta: SendIpPacketMeta<
4496 I,
4497 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
4498 Option<SpecifiedAddr<I::Addr>>,
4499 >,
4500 body: S,
4501 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
4502) -> Result<(), IpSendFrameError<S>>
4503where
4504 I: IpLayerIpExt,
4505 BC: FilterBindingsContext + TxMetadataBindingsTypes,
4506 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4507 S: TransportPacketSerializer<I>,
4508 S::Buffer: BufferMut,
4509{
4510 let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
4511 meta;
4512 core_ctx.increment_both(device, |c| &c.send_ip_packet);
4513 let next_packet_id = gen_ip_packet_id(core_ctx);
4514 let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
4515 let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
4516 let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
4517
4518 #[derive(GenericOverIp)]
4519 #[generic_over_ip(I, Ip)]
4520 struct Wrap<'a, I: IpLayerIpExt> {
4521 builder: &'a mut I::PacketBuilder,
4522 next_packet_id: I::PacketId,
4523 }
4524
4525 I::map_ip::<_, ()>(
4526 Wrap { builder: &mut builder, next_packet_id },
4527 |Wrap { builder, next_packet_id }| {
4528 builder.id(next_packet_id);
4529 },
4530 |Wrap { builder: _, next_packet_id: () }| {
4531 },
4533 );
4534
4535 builder.set_dscp_and_ecn(dscp_and_ecn);
4536
4537 let ip_frame = body.encapsulate(builder);
4538 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
4539 .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
4540}
4541
4542pub trait FilterHandlerProvider<I: packet_formats::ip::IpExt, BT: FilterBindingsTypes>:
4544 IpDeviceAddressIdContext<I, DeviceId: filter::InterfaceProperties<BT::DeviceClass>>
4545{
4546 type Handler<'a>: filter::FilterHandler<
4548 I,
4549 BT,
4550 DeviceId = Self::DeviceId,
4551 WeakAddressId = Self::WeakAddressId,
4552 >
4553 where
4554 Self: 'a;
4555
4556 fn filter_handler(&mut self) -> Self::Handler<'_>;
4558}
4559
4560#[cfg(any(test, feature = "testutils"))]
4561pub(crate) mod testutil {
4562 use super::*;
4563
4564 use netstack3_base::testutil::{FakeCoreCtx, FakeStrongDeviceId};
4565 use netstack3_base::{AssignedAddrIpExt, SendFrameContext, SendFrameError, SendableFrameMeta};
4566 use packet::Serializer;
4567
4568 #[derive(Debug, GenericOverIp)]
4570 #[generic_over_ip()]
4571 #[allow(missing_docs)]
4572 pub enum DualStackSendIpPacketMeta<D> {
4573 V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
4574 V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
4575 }
4576
4577 impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4578 for DualStackSendIpPacketMeta<D>
4579 {
4580 fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
4581 #[derive(GenericOverIp)]
4582 #[generic_over_ip(I, Ip)]
4583 struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
4584 use DualStackSendIpPacketMeta::*;
4585 I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
4586 }
4587 }
4588
4589 impl<I: IpExt, S, DeviceId, BC>
4590 SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
4591 for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
4592 {
4593 fn send_meta<SS>(
4594 self,
4595 core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
4596 bindings_ctx: &mut BC,
4597 frame: SS,
4598 ) -> Result<(), SendFrameError<SS>>
4599 where
4600 SS: Serializer,
4601 SS::Buffer: BufferMut,
4602 {
4603 SendFrameContext::send_frame(
4604 &mut core_ctx.frames,
4605 bindings_ctx,
4606 DualStackSendIpPacketMeta::from(self),
4607 frame,
4608 )
4609 }
4610 }
4611
4612 #[derive(Debug)]
4614 pub struct WrongIpVersion;
4615
4616 impl<D> DualStackSendIpPacketMeta<D> {
4617 pub fn try_as<I: IpExt>(
4620 &self,
4621 ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
4622 #[derive(GenericOverIp)]
4623 #[generic_over_ip(I, Ip)]
4624 struct Wrap<'a, I: IpExt, D>(
4625 Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
4626 );
4627 use DualStackSendIpPacketMeta::*;
4628 let Wrap(dual_stack) = I::map_ip(
4629 self,
4630 |value| {
4631 Wrap(match value {
4632 V4(meta) => Some(meta),
4633 V6(_) => None,
4634 })
4635 },
4636 |value| {
4637 Wrap(match value {
4638 V4(_) => None,
4639 V6(meta) => Some(meta),
4640 })
4641 },
4642 );
4643 dual_stack.ok_or(WrongIpVersion)
4644 }
4645 }
4646
4647 impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
4648 where
4649 I: packet_formats::ip::IpExt + AssignedAddrIpExt,
4650 BC: FilterBindingsContext,
4651 DeviceId: FakeStrongDeviceId + filter::InterfaceProperties<BC::DeviceClass>,
4652 {
4653 type Handler<'a>
4654 = filter::testutil::NoopImpl<DeviceId>
4655 where
4656 Self: 'a;
4657
4658 fn filter_handler(&mut self) -> Self::Handler<'_> {
4659 filter::testutil::NoopImpl::default()
4660 }
4661 }
4662}