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, Ipv4SourceAddr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu, Subnet,
25};
26use net_types::{
27 MulticastAddr, MulticastAddress, NonMappedAddr, NonMulticastAddr, SpecifiedAddr,
28 SpecifiedAddress as _, 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 IpAddressData, IpAddressFlags, IpDeviceStateBindingsTypes, IpDeviceStateIpExt, WeakAddressId,
62};
63use crate::internal::device::{self, IpDeviceBindingsContext, IpDeviceIpExt, IpDeviceSendContext};
64use crate::internal::fragmentation::{FragmentableIpSerializer, FragmentationIpExt, IpFragmenter};
65use crate::internal::gmp::igmp::IgmpCounters;
66use crate::internal::gmp::mld::MldCounters;
67use crate::internal::gmp::GmpQueryHandler;
68use crate::internal::icmp::{
69 IcmpBindingsTypes, IcmpErrorHandler, IcmpHandlerIpExt, Icmpv4Error, Icmpv4ErrorKind,
70 Icmpv4State, Icmpv4StateBuilder, Icmpv6ErrorKind, Icmpv6State, Icmpv6StateBuilder,
71};
72use crate::internal::ipv6::Ipv6PacketAction;
73use crate::internal::local_delivery::{
74 IpHeaderInfo, Ipv4HeaderInfo, Ipv6HeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta,
75 TransparentLocalDelivery,
76};
77use crate::internal::multicast_forwarding::counters::MulticastForwardingCounters;
78use crate::internal::multicast_forwarding::route::{
79 MulticastRouteIpExt, MulticastRouteTarget, MulticastRouteTargets,
80};
81use crate::internal::multicast_forwarding::state::{
82 MulticastForwardingState, MulticastForwardingStateContext,
83};
84use crate::internal::multicast_forwarding::{
85 MulticastForwardingBindingsTypes, MulticastForwardingDeviceContext, MulticastForwardingEvent,
86 MulticastForwardingTimerId,
87};
88use crate::internal::path_mtu::{PmtuBindingsTypes, PmtuCache, PmtuTimerId};
89use crate::internal::raw::counters::RawIpSocketCounters;
90use crate::internal::raw::{RawIpSocketHandler, RawIpSocketMap, RawIpSocketsBindingsTypes};
91use crate::internal::reassembly::{
92 FragmentBindingsTypes, FragmentHandler, FragmentProcessingState, FragmentTimerId,
93 FragmentablePacket, IpPacketFragmentCache, ReassemblyIpExt,
94};
95use crate::internal::routing::rules::{Rule, RuleAction, RuleInput, RulesTable};
96use crate::internal::routing::{
97 IpRoutingDeviceContext, NonLocalSrcAddrPolicy, PacketOrigin, RoutingTable,
98};
99use crate::internal::socket::{IpSocketBindingsContext, IpSocketContext, IpSocketHandler};
100use crate::internal::types::{
101 self, Destination, InternalForwarding, NextHop, ResolvedRoute, RoutableIpAddr,
102};
103use crate::internal::{ipv6, multicast_forwarding};
104
105#[cfg(test)]
106mod tests;
107
108pub const DEFAULT_TTL: NonZeroU8 = NonZeroU8::new(64).unwrap();
110
111#[derive(Copy, Clone, Debug, Eq, PartialEq)]
113#[allow(missing_docs)]
114pub struct HopLimits {
115 pub unicast: NonZeroU8,
116 pub multicast: NonZeroU8,
117}
118
119pub const DEFAULT_HOP_LIMITS: HopLimits =
121 HopLimits { unicast: DEFAULT_TTL, multicast: NonZeroU8::new(1).unwrap() };
122
123pub const IPV6_DEFAULT_SUBNET: Subnet<Ipv6Addr> =
126 unsafe { Subnet::new_unchecked(Ipv6::UNSPECIFIED_ADDRESS, 0) };
127
128#[derive(Debug)]
130#[allow(missing_docs)]
131pub enum TransportReceiveError {
132 ProtocolUnsupported,
133 PortUnreachable,
134}
135
136impl TransportReceiveError {
137 fn into_icmpv4_error(self, header_len: usize) -> Icmpv4Error {
138 let kind = match self {
139 TransportReceiveError::ProtocolUnsupported => Icmpv4ErrorKind::ProtocolUnreachable,
140 TransportReceiveError::PortUnreachable => Icmpv4ErrorKind::PortUnreachable,
141 };
142 Icmpv4Error { kind, header_len }
143 }
144
145 fn into_icmpv6_error(self, header_len: usize) -> Icmpv6ErrorKind {
146 match self {
147 TransportReceiveError::ProtocolUnsupported => {
148 Icmpv6ErrorKind::ProtocolUnreachable { header_len }
149 }
150 TransportReceiveError::PortUnreachable => Icmpv6ErrorKind::PortUnreachable,
151 }
152 }
153}
154
155#[derive(Derivative)]
161#[derivative(Default(bound = ""))]
162pub struct IpLayerPacketMetadata<
163 I: packet_formats::ip::IpExt,
164 A,
165 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
166> {
167 conntrack_connection_and_direction:
168 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
169 tx_metadata: BT::TxMetadata,
174 marks: Marks,
176 #[cfg(debug_assertions)]
177 drop_check: IpLayerPacketMetadataDropCheck,
178}
179
180#[cfg(debug_assertions)]
187#[derive(Default)]
188struct IpLayerPacketMetadataDropCheck {
189 okay_to_drop: bool,
190}
191
192#[derive(Derivative)]
195#[derivative(Debug(bound = ""), Default(bound = ""))]
196pub struct DeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
197 conntrack_entry: Option<(WeakConntrackConnection, ConnectionDirection)>,
205 tx_metadata: BT::TxMetadata,
210 marks: Marks,
217}
218
219impl<BT: TxMetadataBindingsTypes> DeviceIpLayerMetadata<BT> {
220 pub fn into_tx_metadata(self) -> BT::TxMetadata {
223 self.tx_metadata
224 }
225 #[cfg(any(test, feature = "testutils"))]
227 pub fn with_marks(marks: Marks) -> Self {
228 Self { conntrack_entry: None, tx_metadata: Default::default(), marks }
229 }
230}
231
232impl<
233 I: IpLayerIpExt,
234 A: WeakIpAddressId<I::Addr>,
235 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
236 > IpLayerPacketMetadata<I, A, BT>
237{
238 fn from_device_ip_layer_metadata<CC, D>(
239 core_ctx: &mut CC,
240 device: &D,
241 DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks }: DeviceIpLayerMetadata<BT>,
242 ) -> Self
243 where
244 CC: ResourceCounterContext<D, IpCounters<I>>,
245 {
246 let conntrack_connection_and_direction = match conntrack_entry
247 .map(|(conn, dir)| conn.into_inner().map(|conn| (conn, dir)))
248 .transpose()
249 {
250 Ok(conn_and_dir) => conn_and_dir,
253 Err(WeakConnectionError::EntryRemoved) => None,
255 Err(WeakConnectionError::InvalidEntry) => {
259 core_ctx.increment_both(device, |c| &c.invalid_cached_conntrack_entry);
260 None
261 }
262 };
263 Self {
264 conntrack_connection_and_direction,
265 tx_metadata,
266 marks,
267 #[cfg(debug_assertions)]
268 drop_check: Default::default(),
269 }
270 }
271}
272
273impl<I: IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
274 IpLayerPacketMetadata<I, A, BT>
275{
276 pub(crate) fn from_tx_metadata_and_marks(tx_metadata: BT::TxMetadata, marks: Marks) -> Self {
277 Self {
278 conntrack_connection_and_direction: None,
279 tx_metadata,
280 marks,
281 #[cfg(debug_assertions)]
282 drop_check: Default::default(),
283 }
284 }
285
286 pub(crate) fn into_parts(
287 self,
288 ) -> (Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>, BT::TxMetadata, Marks) {
289 let Self {
290 tx_metadata,
291 marks,
292 conntrack_connection_and_direction,
293 #[cfg(debug_assertions)]
294 mut drop_check,
295 } = self;
296 #[cfg(debug_assertions)]
297 {
298 drop_check.okay_to_drop = true;
299 }
300 (conntrack_connection_and_direction, tx_metadata, marks)
301 }
302
303 pub(crate) fn acknowledge_drop(self) {
308 #[cfg(debug_assertions)]
309 {
310 let mut this = self;
311 this.drop_check.okay_to_drop = true;
312 }
313 }
314
315 pub(crate) fn tx_metadata(&self) -> &BT::TxMetadata {
317 &self.tx_metadata
318 }
319
320 pub(crate) fn marks(&self) -> &Marks {
322 &self.marks
323 }
324}
325
326#[cfg(debug_assertions)]
327impl Drop for IpLayerPacketMetadataDropCheck {
328 fn drop(&mut self) {
329 if !self.okay_to_drop {
330 panic!(
331 "IpLayerPacketMetadata dropped without acknowledgement. https://fxbug.dev/334127474"
332 );
333 }
334 }
335}
336
337impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
338 FilterIpMetadata<I, A, BT> for IpLayerPacketMetadata<I, A, BT>
339{
340 fn take_connection_and_direction(
341 &mut self,
342 ) -> Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)> {
343 self.conntrack_connection_and_direction.take()
344 }
345
346 fn replace_connection_and_direction(
347 &mut self,
348 conn: ConntrackConnection<I, A, BT>,
349 direction: ConnectionDirection,
350 ) -> Option<ConntrackConnection<I, A, BT>> {
351 self.conntrack_connection_and_direction.replace((conn, direction)).map(|(conn, _dir)| conn)
352 }
353}
354
355impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
356 FilterMarkMetadata for IpLayerPacketMetadata<I, A, BT>
357{
358 fn apply_mark_action(&mut self, domain: MarkDomain, action: MarkAction) {
359 action.apply(self.marks.get_mut(domain))
360 }
361}
362
363pub type IpSendFrameError<S> = ErrorAndSerializer<IpSendFrameErrorReason, S>;
365
366#[derive(Debug, PartialEq)]
368pub enum IpSendFrameErrorReason {
369 Device(SendFrameErrorReason),
371 IllegalLoopbackAddress,
374}
375
376impl From<SendFrameErrorReason> for IpSendFrameErrorReason {
377 fn from(value: SendFrameErrorReason) -> Self {
378 Self::Device(value)
379 }
380}
381
382pub trait IpTransportContext<I: IpExt, BC, CC: DeviceIdContext<AnyDevice> + ?Sized> {
388 fn receive_icmp_error(
402 core_ctx: &mut CC,
403 bindings_ctx: &mut BC,
404 device: &CC::DeviceId,
405 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
406 original_dst_ip: SpecifiedAddr<I::Addr>,
407 original_body: &[u8],
408 err: I::ErrorCode,
409 );
410
411 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
417 core_ctx: &mut CC,
418 bindings_ctx: &mut BC,
419 device: &CC::DeviceId,
420 src_ip: I::RecvSrcAddr,
421 dst_ip: SpecifiedAddr<I::Addr>,
422 buffer: B,
423 info: &LocalDeliveryPacketInfo<I, H>,
424 ) -> Result<(), (B, TransportReceiveError)>;
425}
426
427impl<I: IpExt, BC, CC: DeviceIdContext<AnyDevice> + ?Sized> IpTransportContext<I, BC, CC> for () {
428 fn receive_icmp_error(
429 _core_ctx: &mut CC,
430 _bindings_ctx: &mut BC,
431 _device: &CC::DeviceId,
432 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
433 _original_dst_ip: SpecifiedAddr<I::Addr>,
434 _original_body: &[u8],
435 err: I::ErrorCode,
436 ) {
437 trace!("IpTransportContext::receive_icmp_error: Received ICMP error message ({:?}) for unsupported IP protocol", err);
438 }
439
440 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
441 _core_ctx: &mut CC,
442 _bindings_ctx: &mut BC,
443 _device: &CC::DeviceId,
444 _src_ip: I::RecvSrcAddr,
445 _dst_ip: SpecifiedAddr<I::Addr>,
446 buffer: B,
447 _info: &LocalDeliveryPacketInfo<I, H>,
448 ) -> Result<(), (B, TransportReceiveError)> {
449 Err((buffer, TransportReceiveError::ProtocolUnsupported))
450 }
451}
452
453pub trait BaseTransportIpContext<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
456 type DevicesWithAddrIter<'s>: Iterator<Item = Self::DeviceId>;
459
460 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
466 &mut self,
467 addr: SpecifiedAddr<I::Addr>,
468 cb: F,
469 ) -> O;
470
471 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits;
476
477 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)>;
481}
482
483pub trait TransportIpContext<I: IpExt + FilterIpExt, BC: TxMetadataBindingsTypes>:
486 BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>
487{
488}
489
490impl<I, CC, BC> TransportIpContext<I, BC> for CC
491where
492 I: IpExt + FilterIpExt,
493 CC: BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>,
494 BC: TxMetadataBindingsTypes,
495{
496}
497
498pub trait MulticastMembershipHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
500 fn join_multicast_group(
507 &mut self,
508 bindings_ctx: &mut BC,
509 device: &Self::DeviceId,
510 addr: MulticastAddr<I::Addr>,
511 );
512
513 fn leave_multicast_group(
521 &mut self,
522 bindings_ctx: &mut BC,
523 device: &Self::DeviceId,
524 addr: MulticastAddr<I::Addr>,
525 );
526
527 fn select_device_for_multicast_group(
532 &mut self,
533 addr: MulticastAddr<I::Addr>,
534 marks: &Marks,
535 ) -> Result<Self::DeviceId, ResolveRouteError>;
536}
537
538pub trait UseTransportIpContextBlanket {}
550
551pub struct AssignedAddressDeviceIterator<Iter, I, D>(Iter, PhantomData<(I, D)>);
554
555impl<Iter, I, D> Iterator for AssignedAddressDeviceIterator<Iter, I, D>
556where
557 Iter: Iterator<Item = (D, I::AddressStatus)>,
558 I: IpLayerIpExt,
559{
560 type Item = D;
561 fn next(&mut self) -> Option<D> {
562 let Self(iter, PhantomData) = self;
563 iter.by_ref().find_map(|(device, state)| is_unicast_assigned::<I>(&state).then_some(device))
564 }
565}
566
567impl<
568 I: IpLayerIpExt,
569 BC: FilterBindingsContext + TxMetadataBindingsTypes,
570 CC: IpDeviceContext<I>
571 + IpSocketHandler<I, BC>
572 + IpStateContext<I>
573 + FilterIpContext<I, BC>
574 + UseTransportIpContextBlanket,
575 > BaseTransportIpContext<I, BC> for CC
576{
577 type DevicesWithAddrIter<'s> =
578 AssignedAddressDeviceIterator<CC::DeviceAndAddressStatusIter<'s>, I, CC::DeviceId>;
579
580 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
581 &mut self,
582 addr: SpecifiedAddr<I::Addr>,
583 cb: F,
584 ) -> O {
585 self.with_address_statuses(addr, |it| cb(AssignedAddressDeviceIterator(it, PhantomData)))
586 }
587
588 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
589 match device {
590 Some(device) => HopLimits {
591 unicast: IpDeviceEgressStateContext::<I>::get_hop_limit(self, device),
592 ..DEFAULT_HOP_LIMITS
593 },
594 None => DEFAULT_HOP_LIMITS,
595 }
596 }
597
598 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)> {
599 self.with_filter_state(|state| {
600 let conn = state.conntrack.get_connection(&tuple)?;
601
602 if !conn.destination_nat() {
603 return None;
604 }
605
606 let original = conn.original_tuple();
610 Some((original.dst_addr, original.dst_port_or_id))
611 })
612 }
613}
614
615#[derive(Debug, PartialEq)]
617#[allow(missing_docs)]
618pub enum AddressStatus<S> {
619 Present(S),
620 Unassigned,
621}
622
623impl<S> AddressStatus<S> {
624 fn into_present(self) -> Option<S> {
625 match self {
626 Self::Present(s) => Some(s),
627 Self::Unassigned => None,
628 }
629 }
630}
631
632impl AddressStatus<Ipv4PresentAddressStatus> {
633 pub fn from_context_addr_v4<
635 BC: IpDeviceStateBindingsTypes,
636 CC: device::IpDeviceStateContext<Ipv4, BC> + GmpQueryHandler<Ipv4, BC>,
637 >(
638 core_ctx: &mut CC,
639 device: &CC::DeviceId,
640 addr: SpecifiedAddr<Ipv4Addr>,
641 ) -> AddressStatus<Ipv4PresentAddressStatus> {
642 if addr.is_limited_broadcast() {
643 return AddressStatus::Present(Ipv4PresentAddressStatus::LimitedBroadcast);
644 }
645
646 if MulticastAddr::new(addr.get())
647 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
648 {
649 return AddressStatus::Present(Ipv4PresentAddressStatus::Multicast);
650 }
651
652 core_ctx.with_address_ids(device, |mut addrs, _core_ctx| {
653 addrs
654 .find_map(|addr_id| {
655 let dev_addr = addr_id.addr_sub();
656 let (dev_addr, subnet) = dev_addr.addr_subnet();
657
658 if **dev_addr == addr {
659 Some(AddressStatus::Present(Ipv4PresentAddressStatus::Unicast))
660 } else if addr.get() == subnet.broadcast() {
661 Some(AddressStatus::Present(Ipv4PresentAddressStatus::SubnetBroadcast))
662 } else if device.is_loopback() && subnet.contains(addr.as_ref()) {
663 Some(AddressStatus::Present(Ipv4PresentAddressStatus::LoopbackSubnet))
664 } else {
665 None
666 }
667 })
668 .unwrap_or(AddressStatus::Unassigned)
669 })
670 }
671}
672
673impl AddressStatus<Ipv6PresentAddressStatus> {
674 pub fn from_context_addr_v6<
676 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
677 CC: device::Ipv6DeviceContext<BC> + GmpQueryHandler<Ipv6, BC>,
678 >(
679 core_ctx: &mut CC,
680 device: &CC::DeviceId,
681 addr: SpecifiedAddr<Ipv6Addr>,
682 ) -> AddressStatus<Ipv6PresentAddressStatus> {
683 if MulticastAddr::new(addr.get())
684 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
685 {
686 return AddressStatus::Present(Ipv6PresentAddressStatus::Multicast);
687 }
688
689 let addr_id = match core_ctx.get_address_id(device, addr) {
690 Ok(o) => o,
691 Err(NotFoundError) => return AddressStatus::Unassigned,
692 };
693
694 let assigned = core_ctx.with_ip_address_data(
695 device,
696 &addr_id,
697 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
698 );
699
700 if assigned {
701 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned)
702 } else {
703 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastTentative)
704 }
705 }
706}
707
708impl<S: GenericOverIp<I>, I: Ip> GenericOverIp<I> for AddressStatus<S> {
709 type Type = AddressStatus<S::Type>;
710}
711
712#[derive(Debug, PartialEq)]
714#[allow(missing_docs)]
715pub enum Ipv4PresentAddressStatus {
716 LimitedBroadcast,
717 SubnetBroadcast,
718 Multicast,
719 Unicast,
720 LoopbackSubnet,
731}
732
733impl Ipv4PresentAddressStatus {
734 fn to_broadcast_marker(&self) -> Option<<Ipv4 as BroadcastIpExt>::BroadcastMarker> {
735 match self {
736 Self::LimitedBroadcast | Self::SubnetBroadcast => Some(()),
737 Self::Multicast | Self::Unicast | Self::LoopbackSubnet => None,
738 }
739 }
740}
741
742#[derive(Debug, PartialEq)]
744#[allow(missing_docs)]
745pub enum Ipv6PresentAddressStatus {
746 Multicast,
747 UnicastAssigned,
748 UnicastTentative,
749}
750
751pub trait IpLayerIpExt:
753 IpExt
754 + MulticastRouteIpExt
755 + IcmpHandlerIpExt
756 + FilterIpExt
757 + FragmentationIpExt
758 + IpDeviceIpExt
759 + IpCountersIpExt
760 + ReassemblyIpExt
761{
762 type AddressStatus: Debug;
764 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>: AsRef<
766 IpStateInner<Self, StrongDeviceId, BT>,
767 >;
768 type PacketIdState;
770 type PacketId;
772 fn next_packet_id_from_state(state: &Self::PacketIdState) -> Self::PacketId;
774}
775
776impl IpLayerIpExt for Ipv4 {
777 type AddressStatus = Ipv4PresentAddressStatus;
778 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
779 Ipv4State<StrongDeviceId, BT>;
780 type PacketIdState = AtomicU16;
781 type PacketId = u16;
782 fn next_packet_id_from_state(next_packet_id: &Self::PacketIdState) -> Self::PacketId {
783 next_packet_id.fetch_add(1, atomic::Ordering::Relaxed)
787 }
788}
789
790impl IpLayerIpExt for Ipv6 {
791 type AddressStatus = Ipv6PresentAddressStatus;
792 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
793 Ipv6State<StrongDeviceId, BT>;
794 type PacketIdState = ();
795 type PacketId = ();
796 fn next_packet_id_from_state((): &Self::PacketIdState) -> Self::PacketId {
797 ()
798 }
799}
800
801pub trait IpStateContext<I: IpLayerIpExt>:
803 IpRouteTablesContext<I, DeviceId: DeviceWithName>
804{
805 type IpRouteTablesCtx<'a>: IpRouteTablesContext<I, DeviceId = Self::DeviceId>;
807
808 fn with_rules_table<
810 O,
811 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId>) -> O,
812 >(
813 &mut self,
814 cb: F,
815 ) -> O;
816
817 fn with_rules_table_mut<
819 O,
820 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId>) -> O,
821 >(
822 &mut self,
823 cb: F,
824 ) -> O;
825}
826
827pub trait IpRouteTablesContext<I: IpLayerIpExt>:
829 IpRouteTableContext<I> + IpDeviceContext<I>
830{
831 type Ctx<'a>: IpRouteTableContext<
833 I,
834 DeviceId = Self::DeviceId,
835 WeakDeviceId = Self::WeakDeviceId,
836 >;
837
838 fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId>;
840
841 fn with_ip_routing_tables<
843 O,
844 F: FnOnce(
845 &mut Self::Ctx<'_>,
846 &HashMap<
847 RoutingTableId<I, Self::DeviceId>,
848 PrimaryRc<RwLock<RoutingTable<I, Self::DeviceId>>>,
849 >,
850 ) -> O,
851 >(
852 &mut self,
853 cb: F,
854 ) -> O;
855
856 fn with_ip_routing_tables_mut<
858 O,
859 F: FnOnce(
860 &mut HashMap<
861 RoutingTableId<I, Self::DeviceId>,
862 PrimaryRc<RwLock<RoutingTable<I, Self::DeviceId>>>,
863 >,
864 ) -> O,
865 >(
866 &mut self,
867 cb: F,
868 ) -> O;
869
870 fn with_main_ip_routing_table<
874 O,
875 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
876 >(
877 &mut self,
878 cb: F,
879 ) -> O {
880 let main_table_id = self.main_table_id();
881 self.with_ip_routing_table(&main_table_id, cb)
882 }
883
884 fn with_main_ip_routing_table_mut<
888 O,
889 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
890 >(
891 &mut self,
892 cb: F,
893 ) -> O {
894 let main_table_id = self.main_table_id();
895 self.with_ip_routing_table_mut(&main_table_id, cb)
896 }
897}
898
899pub trait IpRouteTableContext<I: IpLayerIpExt>: IpDeviceContext<I> {
901 type IpDeviceIdCtx<'a>: DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
903 + IpRoutingDeviceContext<I>
904 + IpDeviceContext<I>;
905
906 fn with_ip_routing_table<
908 O,
909 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
910 >(
911 &mut self,
912 table_id: &RoutingTableId<I, Self::DeviceId>,
913 cb: F,
914 ) -> O;
915
916 fn with_ip_routing_table_mut<
918 O,
919 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
920 >(
921 &mut self,
922 table_id: &RoutingTableId<I, Self::DeviceId>,
923 cb: F,
924 ) -> O;
925}
926
927pub trait IpDeviceEgressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
929 fn with_next_packet_id<O, F: FnOnce(&I::PacketIdState) -> O>(&self, cb: F) -> O;
931
932 fn get_local_addr_for_remote(
934 &mut self,
935 device_id: &Self::DeviceId,
936 remote: Option<SpecifiedAddr<I::Addr>>,
937 ) -> Option<IpDeviceAddr<I::Addr>>;
938
939 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8;
941}
942
943pub trait IpDeviceIngressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
945 fn address_status_for_device(
951 &mut self,
952 addr: SpecifiedAddr<I::Addr>,
953 device_id: &Self::DeviceId,
954 ) -> AddressStatus<I::AddressStatus>;
955}
956
957pub trait IpDeviceContext<I: IpLayerIpExt>:
959 IpDeviceEgressStateContext<I> + IpDeviceIngressStateContext<I>
960{
961 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
963
964 type DeviceAndAddressStatusIter<'a>: Iterator<Item = (Self::DeviceId, I::AddressStatus)>;
966
967 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
973 &mut self,
974 addr: SpecifiedAddr<I::Addr>,
975 cb: F,
976 ) -> R;
977
978 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
980}
981
982pub trait IpDeviceConfirmReachableContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
984 fn confirm_reachable(
987 &mut self,
988 bindings_ctx: &mut BC,
989 device: &Self::DeviceId,
990 neighbor: SpecifiedAddr<I::Addr>,
991 );
992}
993
994pub trait IpDeviceMtuContext<I: Ip>: DeviceIdContext<AnyDevice> {
996 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu;
1000}
1001
1002#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
1004#[generic_over_ip(I, Ip)]
1005pub enum IpLayerEvent<DeviceId, I: IpLayerIpExt> {
1006 AddRoute(types::AddableEntry<I::Addr, DeviceId>),
1008 RemoveRoutes {
1010 subnet: Subnet<I::Addr>,
1012 device: DeviceId,
1014 gateway: Option<SpecifiedAddr<I::Addr>>,
1016 },
1017 MulticastForwarding(MulticastForwardingEvent<I, DeviceId>),
1019}
1020
1021impl<DeviceId, I: IpLayerIpExt> From<MulticastForwardingEvent<I, DeviceId>>
1022 for IpLayerEvent<DeviceId, I>
1023{
1024 fn from(event: MulticastForwardingEvent<I, DeviceId>) -> IpLayerEvent<DeviceId, I> {
1025 IpLayerEvent::MulticastForwarding(event)
1026 }
1027}
1028
1029impl<DeviceId, I: IpLayerIpExt> IpLayerEvent<DeviceId, I> {
1030 pub fn map_device<N, F: Fn(DeviceId) -> N>(self, map: F) -> IpLayerEvent<N, I> {
1032 match self {
1033 IpLayerEvent::AddRoute(types::AddableEntry { subnet, device, gateway, metric }) => {
1034 IpLayerEvent::AddRoute(types::AddableEntry {
1035 subnet,
1036 device: map(device),
1037 gateway,
1038 metric,
1039 })
1040 }
1041 IpLayerEvent::RemoveRoutes { subnet, device, gateway } => {
1042 IpLayerEvent::RemoveRoutes { subnet, device: map(device), gateway }
1043 }
1044 IpLayerEvent::MulticastForwarding(e) => {
1045 IpLayerEvent::MulticastForwarding(e.map_device(map))
1046 }
1047 }
1048 }
1049}
1050
1051#[derive(Derivative, PartialEq, Eq, Clone, Hash)]
1053#[derivative(Debug)]
1054pub struct RouterAdvertisementEvent<D> {
1055 #[derivative(Debug = "ignore")]
1058 pub options_bytes: Box<[u8]>,
1059 pub source: net_types::ip::Ipv6Addr,
1061 pub device: D,
1063}
1064
1065impl<D> RouterAdvertisementEvent<D> {
1066 pub fn map_device<N, F: Fn(D) -> N>(self, map: F) -> RouterAdvertisementEvent<N> {
1068 let Self { options_bytes, source, device } = self;
1069 RouterAdvertisementEvent { options_bytes, source, device: map(device) }
1070 }
1071}
1072
1073pub trait NdpBindingsContext<DeviceId>: EventContext<RouterAdvertisementEvent<DeviceId>> {}
1075impl<DeviceId, BC: EventContext<RouterAdvertisementEvent<DeviceId>>> NdpBindingsContext<DeviceId>
1076 for BC
1077{
1078}
1079
1080pub trait IpLayerBindingsContext<I: IpLayerIpExt, DeviceId>:
1082 InstantContext
1083 + EventContext<IpLayerEvent<DeviceId, I>>
1084 + FilterBindingsContext
1085 + TxMetadataBindingsTypes
1086{
1087}
1088impl<
1089 I: IpLayerIpExt,
1090 DeviceId,
1091 BC: InstantContext
1092 + EventContext<IpLayerEvent<DeviceId, I>>
1093 + FilterBindingsContext
1094 + TxMetadataBindingsTypes,
1095 > IpLayerBindingsContext<I, DeviceId> for BC
1096{
1097}
1098
1099pub trait IpLayerBindingsTypes: IcmpBindingsTypes + IpStateBindingsTypes {}
1101impl<BT: IcmpBindingsTypes + IpStateBindingsTypes> IpLayerBindingsTypes for BT {}
1102
1103pub trait IpLayerContext<
1105 I: IpLayerIpExt,
1106 BC: IpLayerBindingsContext<I, <Self as DeviceIdContext<AnyDevice>>::DeviceId>,
1107>:
1108 IpStateContext<I>
1109 + IpDeviceContext<I>
1110 + IpDeviceMtuContext<I>
1111 + IpDeviceSendContext<I, BC>
1112 + IcmpErrorHandler<I, BC>
1113 + MulticastForwardingStateContext<I, BC>
1114 + MulticastForwardingDeviceContext<I>
1115 + CounterContext<MulticastForwardingCounters<I>>
1116 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>
1117{
1118}
1119
1120impl<
1121 I: IpLayerIpExt,
1122 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
1123 CC: IpStateContext<I>
1124 + IpDeviceContext<I>
1125 + IpDeviceMtuContext<I>
1126 + IpDeviceSendContext<I, BC>
1127 + IcmpErrorHandler<I, BC>
1128 + MulticastForwardingStateContext<I, BC>
1129 + MulticastForwardingDeviceContext<I>
1130 + CounterContext<MulticastForwardingCounters<I>>
1131 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>,
1132 > IpLayerContext<I, BC> for CC
1133{
1134}
1135
1136fn is_unicast_assigned<I: IpLayerIpExt>(status: &I::AddressStatus) -> bool {
1137 #[derive(GenericOverIp)]
1138 #[generic_over_ip(I, Ip)]
1139 struct WrapAddressStatus<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
1140
1141 I::map_ip(
1142 WrapAddressStatus(status),
1143 |WrapAddressStatus(status)| match status {
1144 Ipv4PresentAddressStatus::Unicast | Ipv4PresentAddressStatus::LoopbackSubnet => true,
1145 Ipv4PresentAddressStatus::LimitedBroadcast
1146 | Ipv4PresentAddressStatus::SubnetBroadcast
1147 | Ipv4PresentAddressStatus::Multicast => false,
1148 },
1149 |WrapAddressStatus(status)| match status {
1150 Ipv6PresentAddressStatus::UnicastAssigned => true,
1151 Ipv6PresentAddressStatus::Multicast | Ipv6PresentAddressStatus::UnicastTentative => {
1152 false
1153 }
1154 },
1155 )
1156}
1157
1158fn is_local_assigned_address<I: Ip + IpLayerIpExt, CC: IpDeviceIngressStateContext<I>>(
1159 core_ctx: &mut CC,
1160 device: &CC::DeviceId,
1161 addr: IpDeviceAddr<I::Addr>,
1162) -> bool {
1163 match core_ctx.address_status_for_device(addr.into(), device) {
1164 AddressStatus::Present(status) => is_unicast_assigned::<I>(&status),
1165 AddressStatus::Unassigned => false,
1166 }
1167}
1168
1169fn get_device_with_assigned_address<I, CC>(
1170 core_ctx: &mut CC,
1171 addr: IpDeviceAddr<I::Addr>,
1172) -> Option<(CC::DeviceId, I::AddressStatus)>
1173where
1174 I: IpLayerIpExt,
1175 CC: IpDeviceContext<I>,
1176{
1177 core_ctx.with_address_statuses(addr.into(), |mut it| {
1178 it.find_map(|(device, status)| {
1179 is_unicast_assigned::<I>(&status).then_some((device, status))
1180 })
1181 })
1182}
1183
1184fn get_local_addr<I: Ip + IpLayerIpExt, CC: IpDeviceContext<I>>(
1188 core_ctx: &mut CC,
1189 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1190 device: &CC::DeviceId,
1191 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1192) -> Result<IpDeviceAddr<I::Addr>, ResolveRouteError> {
1193 match local_ip_and_policy {
1194 Some((local_ip, NonLocalSrcAddrPolicy::Allow)) => Ok(local_ip),
1195 Some((local_ip, NonLocalSrcAddrPolicy::Deny)) => {
1196 is_local_assigned_address(core_ctx, device, local_ip)
1197 .then_some(local_ip)
1198 .ok_or(ResolveRouteError::NoSrcAddr)
1199 }
1200 None => core_ctx
1201 .get_local_addr_for_remote(device, remote_addr.map(Into::into))
1202 .ok_or(ResolveRouteError::NoSrcAddr),
1203 }
1204}
1205
1206#[derive(Error, Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
1208#[generic_over_ip()]
1209pub enum ResolveRouteError {
1210 #[error("a source address could not be selected")]
1212 NoSrcAddr,
1213 #[error("no route exists to the destination IP address")]
1215 Unreachable,
1216}
1217
1218fn get_local_addr_with_internal_forwarding<I, CC>(
1220 core_ctx: &mut CC,
1221 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1222 device: &CC::DeviceId,
1223 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1224) -> Result<(IpDeviceAddr<I::Addr>, InternalForwarding<CC::DeviceId>), ResolveRouteError>
1225where
1226 I: IpLayerIpExt,
1227 CC: IpDeviceContext<I>,
1228{
1229 match get_local_addr(core_ctx, local_ip_and_policy, device, remote_addr) {
1230 Ok(src_addr) => Ok((src_addr, InternalForwarding::NotUsed)),
1231 Err(e) => {
1232 if let Some((local_ip, _policy)) = local_ip_and_policy {
1240 if let Some((device, _addr_status)) =
1241 get_device_with_assigned_address(core_ctx, local_ip)
1242 {
1243 if core_ctx.is_device_unicast_forwarding_enabled(&device) {
1244 return Ok((local_ip, InternalForwarding::Used(device)));
1245 }
1246 }
1247 }
1248 Err(e)
1249 }
1250 }
1251}
1252
1253#[derive(Debug, PartialEq, Eq)]
1256struct RuleWalkInfo<O> {
1257 observed_source_address_matcher: bool,
1259 inner: O,
1262}
1263
1264fn walk_rules<
1278 I: IpLayerIpExt,
1279 CC: IpRouteTablesContext<I, DeviceId: DeviceWithName>,
1280 O,
1281 State,
1282 F: FnMut(
1283 State,
1284 &mut CC::IpDeviceIdCtx<'_>,
1285 &RoutingTable<I, CC::DeviceId>,
1286 ) -> ControlFlow<O, State>,
1287>(
1288 core_ctx: &mut CC,
1289 rules: &RulesTable<I, CC::DeviceId>,
1290 init: State,
1291 rule_input: &RuleInput<'_, I, CC::DeviceId>,
1292 mut lookup_table: F,
1293) -> ControlFlow<RuleAction<RuleWalkInfo<O>>, RuleWalkInfo<State>> {
1294 rules.iter().try_fold(
1295 RuleWalkInfo { inner: init, observed_source_address_matcher: false },
1296 |RuleWalkInfo { inner: state, observed_source_address_matcher },
1297 Rule { action, matcher }| {
1298 let observed_source_address_matcher =
1299 observed_source_address_matcher || matcher.source_address_matcher.is_some();
1300 if !matcher.matches(rule_input) {
1301 return ControlFlow::Continue(RuleWalkInfo {
1302 inner: state,
1303 observed_source_address_matcher,
1304 });
1305 }
1306 match action {
1307 RuleAction::Unreachable => return ControlFlow::Break(RuleAction::Unreachable),
1308 RuleAction::Lookup(table_id) => core_ctx.with_ip_routing_table(
1309 &table_id,
1310 |core_ctx, table| match lookup_table(state, core_ctx, table) {
1311 ControlFlow::Break(out) => {
1312 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1313 inner: out,
1314 observed_source_address_matcher,
1315 }))
1316 }
1317 ControlFlow::Continue(state) => ControlFlow::Continue(RuleWalkInfo {
1318 inner: state,
1319 observed_source_address_matcher,
1320 }),
1321 },
1322 ),
1323 }
1324 },
1325 )
1326}
1327
1328pub fn resolve_output_route_to_destination<
1339 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1340 BC: IpDeviceBindingsContext<I, CC::DeviceId> + IpLayerBindingsContext<I, CC::DeviceId>,
1341 CC: IpStateContext<I> + IpDeviceContext<I> + device::IpDeviceConfigurationContext<I, BC>,
1342>(
1343 core_ctx: &mut CC,
1344 device: Option<&CC::DeviceId>,
1345 src_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1346 dst_ip: Option<RoutableIpAddr<I::Addr>>,
1347 marks: &Marks,
1348) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1349 enum LocalDelivery<A, D> {
1350 WeakLoopback { dst_ip: A, device: D },
1351 StrongForDevice(D),
1352 }
1353
1354 let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1372 let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1373 match (device, dst_ip) {
1374 (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1375 .then_some(LocalDelivery::StrongForDevice(device.clone())),
1376 (None, Some(dst_ip)) => {
1377 get_device_with_assigned_address(core_ctx, dst_ip).map(
1378 |(dst_device, _addr_status)| {
1379 if src_ip_and_policy
1384 .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1385 || dst_ip.as_ref().must_have_zone()
1386 {
1387 LocalDelivery::StrongForDevice(dst_device)
1388 } else {
1389 LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1390 }
1391 },
1392 )
1393 }
1394 (_, None) => None,
1395 }
1396 };
1397
1398 if let Some(local_delivery) = local_delivery_instructions {
1399 let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1400
1401 let (src_addr, dest_device) = match local_delivery {
1402 LocalDelivery::WeakLoopback { dst_ip, device } => {
1403 let src_ip = match src_ip_and_policy {
1404 Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1405 let _device = get_device_with_assigned_address(core_ctx, src_ip)
1406 .ok_or(ResolveRouteError::NoSrcAddr)?;
1407 src_ip
1408 }
1409 Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1410 None => dst_ip,
1411 };
1412 (src_ip, device)
1413 }
1414 LocalDelivery::StrongForDevice(device) => {
1415 (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1416 }
1417 };
1418 return Ok(ResolvedRoute {
1419 src_addr,
1420 local_delivery_device: Some(dest_device),
1421 device: loopback,
1422 next_hop: NextHop::RemoteAsNeighbor,
1423 internal_forwarding: InternalForwarding::NotUsed,
1424 });
1425 }
1426 let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1427 let rule_input = RuleInput {
1428 packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1429 marks,
1430 };
1431 core_ctx.with_rules_table(|core_ctx, rules| {
1432 let mut walk_rules = |rule_input, src_ip_and_policy| {
1433 walk_rules(
1434 core_ctx,
1435 rules,
1436 None, rule_input,
1438 |first_error, core_ctx, table| {
1439 let mut matching_with_addr = table.lookup_filter_map(
1440 core_ctx,
1441 device,
1442 dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1443 |core_ctx, d| {
1444 Some(get_local_addr_with_internal_forwarding(
1445 core_ctx,
1446 src_ip_and_policy,
1447 d,
1448 dst_ip,
1449 ))
1450 },
1451 );
1452
1453 let first_error_in_this_table = match matching_with_addr.next() {
1454 Some((
1455 Destination { device, next_hop },
1456 Ok((local_addr, internal_forwarding)),
1457 )) => {
1458 return ControlFlow::Break(Ok((
1459 Destination { device: device.clone(), next_hop },
1460 local_addr,
1461 internal_forwarding,
1462 )));
1463 }
1464 Some((_, Err(e))) => e,
1465 None => return ControlFlow::Continue(first_error),
1469 };
1470
1471 matching_with_addr
1472 .filter_map(|(destination, local_addr)| {
1473 local_addr.ok_checked::<ResolveRouteError>().map(
1476 |(local_addr, internal_forwarding)| {
1477 (destination, local_addr, internal_forwarding)
1478 },
1479 )
1480 })
1481 .next()
1482 .map_or(
1483 ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1484 |(
1485 Destination { device, next_hop },
1486 local_addr,
1487 internal_forwarding,
1488 )| {
1489 ControlFlow::Break(Ok((
1490 Destination { device: device.clone(), next_hop },
1491 local_addr,
1492 internal_forwarding,
1493 )))
1494 },
1495 )
1496 },
1497 )
1498 };
1499
1500 let result = match walk_rules(&rule_input, src_ip_and_policy) {
1501 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1508 inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1509 observed_source_address_matcher: true,
1510 })) if src_ip_and_policy.is_none() => walk_rules(
1511 &RuleInput {
1512 packet_origin: PacketOrigin::Local {
1513 bound_address: Some(selected_src_addr.into()),
1514 bound_device: device,
1515 },
1516 marks,
1517 },
1518 Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1519 ),
1520 result => result,
1521 };
1522
1523 match result {
1524 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1525 inner: result,
1526 observed_source_address_matcher: _,
1527 })) => {
1528 result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1529 ResolvedRoute {
1530 src_addr,
1531 device,
1532 local_delivery_device: None,
1533 next_hop,
1534 internal_forwarding,
1535 }
1536 })
1537 }
1538 ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1539 ControlFlow::Continue(RuleWalkInfo {
1540 inner: first_error,
1541 observed_source_address_matcher: _,
1542 }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1543 }
1544 })
1545}
1546
1547pub trait UseIpSocketContextBlanket {}
1552
1553impl<
1554 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1555 BC: IpDeviceBindingsContext<I, CC::DeviceId>
1556 + IpLayerBindingsContext<I, CC::DeviceId>
1557 + IpSocketBindingsContext<CC::DeviceId>,
1558 CC: IpLayerEgressContext<I, BC>
1559 + IpStateContext<I>
1560 + IpDeviceContext<I>
1561 + IpDeviceConfirmReachableContext<I, BC>
1562 + IpDeviceMtuContext<I>
1563 + device::IpDeviceConfigurationContext<I, BC>
1564 + UseIpSocketContextBlanket,
1565 > IpSocketContext<I, BC> for CC
1566{
1567 fn lookup_route(
1568 &mut self,
1569 _bindings_ctx: &mut BC,
1570 device: Option<&CC::DeviceId>,
1571 local_ip: Option<IpDeviceAddr<I::Addr>>,
1572 addr: RoutableIpAddr<I::Addr>,
1573 transparent: bool,
1574 marks: &Marks,
1575 ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1576 let src_ip_and_policy = local_ip.map(|local_ip| {
1577 (
1578 local_ip,
1579 if transparent {
1580 NonLocalSrcAddrPolicy::Allow
1581 } else {
1582 NonLocalSrcAddrPolicy::Deny
1583 },
1584 )
1585 });
1586 let res =
1587 resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1588 trace!(
1589 "lookup_route(\
1590 device={device:?}, \
1591 local_ip={local_ip:?}, \
1592 addr={addr:?}, \
1593 transparent={transparent:?}, \
1594 marks={marks:?}) => {res:?}"
1595 );
1596 res
1597 }
1598
1599 fn send_ip_packet<S>(
1600 &mut self,
1601 bindings_ctx: &mut BC,
1602 meta: SendIpPacketMeta<
1603 I,
1604 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1605 SpecifiedAddr<I::Addr>,
1606 >,
1607 body: S,
1608 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1609 ) -> Result<(), IpSendFrameError<S>>
1610 where
1611 S: TransportPacketSerializer<I>,
1612 S::Buffer: BufferMut,
1613 {
1614 send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1615 }
1616
1617 fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1618 device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1619 }
1620
1621 fn confirm_reachable(
1622 &mut self,
1623 bindings_ctx: &mut BC,
1624 dst: SpecifiedAddr<I::Addr>,
1625 input: RuleInput<'_, I, Self::DeviceId>,
1626 ) {
1627 match lookup_route_table(self, dst.get(), input) {
1628 Some(Destination { next_hop, device }) => {
1629 let neighbor = match next_hop {
1630 NextHop::RemoteAsNeighbor => dst,
1631 NextHop::Gateway(gateway) => gateway,
1632 NextHop::Broadcast(marker) => {
1633 I::map_ip::<_, ()>(
1634 WrapBroadcastMarker(marker),
1635 |WrapBroadcastMarker(())| {
1636 debug!(
1637 "can't confirm {dst:?}@{device:?} as reachable: \
1638 dst is a broadcast address"
1639 );
1640 },
1641 |WrapBroadcastMarker(never)| match never {},
1642 );
1643 return;
1644 }
1645 };
1646 IpDeviceConfirmReachableContext::confirm_reachable(
1647 self,
1648 bindings_ctx,
1649 &device,
1650 neighbor,
1651 );
1652 }
1653 None => {
1654 debug!("can't confirm {dst:?} as reachable: no route");
1655 }
1656 }
1657 }
1658}
1659
1660pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1665 fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1667 &mut self,
1668 bindings_ctx: &mut BC,
1669 device: &Self::DeviceId,
1670 src_ip: I::RecvSrcAddr,
1671 dst_ip: SpecifiedAddr<I::Addr>,
1672 proto: I::Proto,
1673 body: B,
1674 info: &LocalDeliveryPacketInfo<I, H>,
1675 ) -> Result<(), TransportReceiveError>;
1676}
1677
1678pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1680 IpTransportDispatchContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1681 + IpDeviceIngressStateContext<I>
1682 + IpDeviceMtuContext<I>
1683 + IpDeviceSendContext<I, BC>
1684 + IcmpErrorHandler<I, BC>
1685 + IpLayerContext<I, BC>
1686 + FragmentHandler<I, BC>
1687 + FilterHandlerProvider<I, BC>
1688 + RawIpSocketHandler<I, BC>
1689{
1690}
1691
1692impl<
1693 I: IpLayerIpExt,
1694 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1695 CC: IpTransportDispatchContext<
1696 I,
1697 BC,
1698 DeviceId: filter::InterfaceProperties<BC::DeviceClass>,
1699 > + IpDeviceIngressStateContext<I>
1700 + IpDeviceMtuContext<I>
1701 + IpDeviceSendContext<I, BC>
1702 + IcmpErrorHandler<I, BC>
1703 + IpLayerContext<I, BC>
1704 + FragmentHandler<I, BC>
1705 + FilterHandlerProvider<I, BC>
1706 + RawIpSocketHandler<I, BC>,
1707 > IpLayerIngressContext<I, BC> for CC
1708{
1709}
1710
1711pub trait IpLayerEgressContext<I, BC>:
1713 IpDeviceSendContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1714 + FilterHandlerProvider<I, BC>
1715 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1716where
1717 I: IpLayerIpExt,
1718 BC: FilterBindingsContext + TxMetadataBindingsTypes,
1719{
1720}
1721
1722impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1723where
1724 I: IpLayerIpExt,
1725 BC: FilterBindingsContext + TxMetadataBindingsTypes,
1726 CC: IpDeviceSendContext<I, BC, DeviceId: filter::InterfaceProperties<BC::DeviceClass>>
1727 + FilterHandlerProvider<I, BC>
1728 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
1729{
1730}
1731
1732pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1734 IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
1735{
1736}
1737
1738impl<
1739 I: IpLayerIpExt,
1740 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1741 CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
1742 > IpLayerForwardingContext<I, BC> for CC
1743{
1744}
1745
1746#[derive(Copy, Clone, Default)]
1748pub struct Ipv4StateBuilder {
1749 icmp: Icmpv4StateBuilder,
1750}
1751
1752impl Ipv4StateBuilder {
1753 #[cfg(any(test, feature = "testutils"))]
1755 pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
1756 &mut self.icmp
1757 }
1758
1759 pub fn build<
1761 CC: CoreTimerContext<IpLayerTimerId, BC>,
1762 StrongDeviceId: StrongDeviceIdentifier,
1763 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1764 >(
1765 self,
1766 bindings_ctx: &mut BC,
1767 ) -> Ipv4State<StrongDeviceId, BC> {
1768 let Ipv4StateBuilder { icmp } = self;
1769
1770 Ipv4State {
1771 inner: IpStateInner::new::<CC>(bindings_ctx),
1772 icmp: icmp.build(),
1773 next_packet_id: Default::default(),
1774 }
1775 }
1776}
1777
1778#[derive(Copy, Clone)]
1782pub struct Ipv6StateBuilder {
1783 icmp: Icmpv6StateBuilder,
1784 slaac_stable_secret_key: Option<IidSecret>,
1785}
1786
1787impl Ipv6StateBuilder {
1788 pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
1793 self.slaac_stable_secret_key = Some(secret_key);
1794 self
1795 }
1796
1797 pub fn build<
1803 CC: CoreTimerContext<IpLayerTimerId, BC>,
1804 StrongDeviceId: StrongDeviceIdentifier,
1805 BC: TimerContext + RngContext + IpLayerBindingsTypes,
1806 >(
1807 self,
1808 bindings_ctx: &mut BC,
1809 ) -> Ipv6State<StrongDeviceId, BC> {
1810 let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
1811
1812 let slaac_stable_secret_key = slaac_stable_secret_key
1813 .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
1814
1815 Ipv6State {
1816 inner: IpStateInner::new::<CC>(bindings_ctx),
1817 icmp: icmp.build(),
1818 slaac_counters: Default::default(),
1819 slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
1820 slaac_stable_secret_key,
1821 }
1822 }
1823}
1824
1825impl Default for Ipv6StateBuilder {
1826 fn default() -> Self {
1827 #[cfg(any(test, feature = "testutils"))]
1828 let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
1829
1830 #[cfg(not(any(test, feature = "testutils")))]
1831 let slaac_stable_secret_key = None;
1832
1833 Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
1834 }
1835}
1836
1837pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1839 pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
1841 pub icmp: Icmpv4State<BT>,
1843 pub next_packet_id: AtomicU16,
1845}
1846
1847impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1848 AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
1849{
1850 fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
1851 &self.inner
1852 }
1853}
1854
1855pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
1859 core_ctx: &mut CC,
1860) -> I::PacketId {
1861 core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
1862}
1863
1864pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1866 pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
1868 pub icmp: Icmpv6State<BT>,
1870 pub slaac_counters: SlaacCounters,
1872 pub slaac_temp_secret_key: IidSecret,
1874 pub slaac_stable_secret_key: IidSecret,
1879}
1880
1881impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1882 AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
1883{
1884 fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
1885 &self.inner
1886 }
1887}
1888
1889impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1890 OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
1891{
1892 type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
1893 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1894 OrderedLockRef::new(&self.fragment_cache)
1895 }
1896}
1897
1898impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1899 OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
1900{
1901 type Lock = Mutex<PmtuCache<I, BT>>;
1902 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1903 OrderedLockRef::new(&self.pmtu_cache)
1904 }
1905}
1906
1907impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1908 OrderedLockAccess<RulesTable<I, D>> for IpStateInner<I, D, BT>
1909{
1910 type Lock = RwLock<RulesTable<I, D>>;
1911 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1912 OrderedLockRef::new(&self.rules_table)
1913 }
1914}
1915
1916impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1917 OrderedLockAccess<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>
1918 for IpStateInner<I, D, BT>
1919{
1920 type Lock = Mutex<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>;
1921 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1922 OrderedLockRef::new(&self.tables)
1923 }
1924}
1925
1926impl<I: IpLayerIpExt, D: StrongDeviceIdentifier> OrderedLockAccess<RoutingTable<I, D>>
1927 for RoutingTableId<I, D>
1928{
1929 type Lock = RwLock<RoutingTable<I, D>>;
1930 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1931 let Self(inner) = self;
1932 OrderedLockRef::new(&*inner)
1933 }
1934}
1935
1936impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1937 OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
1938{
1939 type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
1940 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1941 OrderedLockRef::new(&self.multicast_forwarding)
1942 }
1943}
1944
1945impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1946 OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
1947{
1948 type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
1949 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1950 OrderedLockRef::new(&self.raw_sockets)
1951 }
1952}
1953
1954impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1955 OrderedLockAccess<filter::State<I, WeakAddressId<I, BT>, BT>> for IpStateInner<I, D, BT>
1956{
1957 type Lock = RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>;
1958 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1959 OrderedLockRef::new(&self.filter)
1960 }
1961}
1962
1963pub trait IpStateBindingsTypes:
1965 PmtuBindingsTypes
1966 + FragmentBindingsTypes
1967 + RawIpSocketsBindingsTypes
1968 + FilterBindingsTypes
1969 + MulticastForwardingBindingsTypes
1970 + IpDeviceStateBindingsTypes
1971{
1972}
1973impl<BT> IpStateBindingsTypes for BT where
1974 BT: PmtuBindingsTypes
1975 + FragmentBindingsTypes
1976 + RawIpSocketsBindingsTypes
1977 + FilterBindingsTypes
1978 + MulticastForwardingBindingsTypes
1979 + IpDeviceStateBindingsTypes
1980{
1981}
1982
1983#[derive(Clone, PartialEq, Eq, Hash)]
1985pub struct RoutingTableId<I: Ip, D>(StrongRc<RwLock<RoutingTable<I, D>>>);
1986
1987impl<I: Ip, D> Debug for RoutingTableId<I, D> {
1988 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1989 let Self(rc) = self;
1990 f.debug_tuple("RoutingTableId").field(&StrongRc::debug_id(rc)).finish()
1991 }
1992}
1993
1994impl<I: Ip, D> RoutingTableId<I, D> {
1995 pub(crate) fn new(rc: StrongRc<RwLock<RoutingTable<I, D>>>) -> Self {
1997 Self(rc)
1998 }
1999
2000 #[cfg(any(test, feature = "testutils"))]
2002 pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
2003 let Self(inner) = self;
2004 &*inner
2005 }
2006
2007 pub fn downgrade(&self) -> WeakRoutingTableId<I, D> {
2009 let Self(rc) = self;
2010 WeakRoutingTableId(StrongRc::downgrade(rc))
2011 }
2012
2013 #[cfg(test)]
2014 fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2015 let Self(rc) = self;
2016 rc.write()
2017 }
2018}
2019
2020#[derive(Clone, PartialEq, Eq, Hash)]
2022pub struct WeakRoutingTableId<I: Ip, D>(WeakRc<RwLock<RoutingTable<I, D>>>);
2023
2024impl<I: Ip, D> Debug for WeakRoutingTableId<I, D> {
2025 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2026 let Self(rc) = self;
2027 f.debug_tuple("WeakRoutingTableId").field(&WeakRc::debug_id(rc)).finish()
2028 }
2029}
2030
2031#[derive(GenericOverIp)]
2033#[generic_over_ip(I, Ip)]
2034pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2035 rules_table: RwLock<RulesTable<I, D>>,
2036 main_table_id: RoutingTableId<I, D>,
2038 multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2039 multicast_forwarding_counters: MulticastForwardingCounters<I>,
2040 fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2041 pmtu_cache: Mutex<PmtuCache<I, BT>>,
2042 counters: IpCounters<I>,
2043 raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2044 raw_socket_counters: RawIpSocketCounters<I>,
2045 filter: RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>,
2046 tables: Mutex<HashMap<RoutingTableId<I, D>, PrimaryRc<RwLock<RoutingTable<I, D>>>>>,
2052 igmp_counters: IgmpCounters,
2053 mld_counters: MldCounters,
2054}
2055
2056impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2057 pub fn counters(&self) -> &IpCounters<I> {
2059 &self.counters
2060 }
2061
2062 pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2064 &self.multicast_forwarding_counters
2065 }
2066
2067 pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2069 &self.raw_socket_counters
2070 }
2071
2072 pub fn main_table_id(&self) -> &RoutingTableId<I, D> {
2074 &self.main_table_id
2075 }
2076
2077 #[cfg(any(test, feature = "testutils"))]
2079 pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2080 &self.pmtu_cache
2081 }
2082
2083 #[cfg(any(test, feature = "testutils"))]
2085 pub fn filter(&self) -> &RwLock<filter::State<I, WeakAddressId<I, BT>, BT>> {
2086 &self.filter
2087 }
2088
2089 pub fn igmp_counters(&self) -> &IgmpCounters {
2091 &self.igmp_counters
2092 }
2093
2094 pub fn mld_counters(&self) -> &MldCounters {
2096 &self.mld_counters
2097 }
2098}
2099
2100impl<
2101 I: IpLayerIpExt,
2102 D: StrongDeviceIdentifier,
2103 BC: TimerContext + RngContext + IpStateBindingsTypes,
2104 > IpStateInner<I, D, BC>
2105{
2106 fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2108 let main_table: PrimaryRc<RwLock<RoutingTable<I, D>>> = PrimaryRc::new(Default::default());
2109 let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2110 Self {
2111 rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2112 tables: Mutex::new(HashMap::from_iter(core::iter::once((
2113 main_table_id.clone(),
2114 main_table,
2115 )))),
2116 main_table_id,
2117 multicast_forwarding: Default::default(),
2118 multicast_forwarding_counters: Default::default(),
2119 fragment_cache: Mutex::new(
2120 IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2121 ),
2122 pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2123 counters: Default::default(),
2124 raw_sockets: Default::default(),
2125 raw_socket_counters: Default::default(),
2126 filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2127 igmp_counters: Default::default(),
2128 mld_counters: Default::default(),
2129 }
2130 }
2131}
2132
2133#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2135#[generic_over_ip()]
2136pub enum IpLayerTimerId {
2137 ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2139 ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2141 PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2143 PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2145 FilterTimerv4(FilterTimerId<Ipv4>),
2147 FilterTimerv6(FilterTimerId<Ipv6>),
2149 MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2151 MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2153}
2154
2155impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2156 fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2157 I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2158 }
2159}
2160
2161impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2162 fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2163 I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2164 }
2165}
2166
2167impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2168 fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2169 I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2170 }
2171}
2172
2173impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2174 fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2175 I::map_ip(
2176 timer,
2177 IpLayerTimerId::MulticastForwardingTimerv4,
2178 IpLayerTimerId::MulticastForwardingTimerv6,
2179 )
2180 }
2181}
2182
2183impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2184where
2185 CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2186 + TimerHandler<BC, FragmentTimerId<Ipv6>>
2187 + TimerHandler<BC, PmtuTimerId<Ipv4>>
2188 + TimerHandler<BC, PmtuTimerId<Ipv6>>
2189 + TimerHandler<BC, FilterTimerId<Ipv4>>
2190 + TimerHandler<BC, FilterTimerId<Ipv6>>
2191 + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2192 + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2193 BC: TimerBindingsTypes,
2194{
2195 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2196 match self {
2197 IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2198 core_ctx.handle_timer(bindings_ctx, id, timer)
2199 }
2200 IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2201 core_ctx.handle_timer(bindings_ctx, id, timer)
2202 }
2203 IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2204 IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2205 IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2206 IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2207 IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2208 core_ctx.handle_timer(bindings_ctx, id, timer)
2209 }
2210 IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2211 core_ctx.handle_timer(bindings_ctx, id, timer)
2212 }
2213 }
2214 }
2215}
2216
2217pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2224 err: I::IcmpError,
2226 src_ip: I::SourceAddress,
2229 dst_ip: SpecifiedAddr<I::Addr>,
2232 frame_dst: Option<FrameDestination>,
2234 device: &'a D,
2236 meta: ParseMetadata,
2239 marks: Marks,
2241}
2242
2243impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2244 fn respond_with_icmp_error<B, BC, CC>(
2251 self,
2252 core_ctx: &mut CC,
2253 bindings_ctx: &mut BC,
2254 mut body: B,
2255 ) where
2256 B: BufferMut,
2257 CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2258 {
2259 let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks } = self;
2260 body.undo_parse(meta);
2264
2265 core_ctx.send_icmp_error_message(
2266 bindings_ctx,
2267 device,
2268 frame_dst,
2269 src_ip,
2270 dst_ip,
2271 body,
2272 err,
2273 &marks,
2274 );
2275 }
2276}
2277
2278fn dispatch_receive_ipv4_packet<
2299 'a,
2300 'b,
2301 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2302 CC: IpLayerIngressContext<Ipv4, BC>,
2303>(
2304 core_ctx: &'a mut CC,
2305 bindings_ctx: &'a mut BC,
2306 device: &'b CC::DeviceId,
2307 frame_dst: Option<FrameDestination>,
2308 mut packet: Ipv4Packet<&'a mut [u8]>,
2309 mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2310 receive_meta: ReceiveIpPacketMeta<Ipv4>,
2311) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2312 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2313
2314 match frame_dst {
2315 Some(FrameDestination::Individual { local: false }) => {
2316 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2317 }
2318 Some(FrameDestination::Individual { local: true })
2319 | Some(FrameDestination::Multicast)
2320 | Some(FrameDestination::Broadcast)
2321 | None => (),
2322 }
2323
2324 let proto = packet.proto();
2325
2326 match core_ctx.filter_handler().local_ingress_hook(
2327 bindings_ctx,
2328 &mut packet,
2329 device,
2330 &mut packet_metadata,
2331 ) {
2332 filter::Verdict::Drop => {
2333 packet_metadata.acknowledge_drop();
2334 return Ok(());
2335 }
2336 filter::Verdict::Accept(()) => {}
2337 }
2338 let marks = packet_metadata.marks;
2339 packet_metadata.acknowledge_drop();
2340
2341 let Some(src_ip) = packet.src_ipv4() else {
2345 debug!(
2346 "dispatch_receive_ipv4_packet: received packet from invalid source {} after the \
2347 LOCAL_INGRESS hook; dropping",
2348 packet.src_ip()
2349 );
2350 core_ctx.increment_both(device, |c| &c.invalid_source);
2351 return Ok(());
2352 };
2353 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2354 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2355 debug!(
2356 "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2357 after the LOCAL_INGRESS hook; dropping"
2358 );
2359 return Ok(());
2360 };
2361
2362 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2363
2364 let (prefix, options, body) = packet.parts_with_body_mut();
2365 let buffer = Buf::new(body, ..);
2366 let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2367 let receive_info = LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks };
2368
2369 core_ctx
2370 .dispatch_receive_ip_packet(
2371 bindings_ctx,
2372 device,
2373 src_ip,
2374 dst_ip,
2375 proto,
2376 buffer,
2377 &receive_info,
2378 )
2379 .or_else(|err| {
2380 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
2381 let (_, _, _, meta) = packet.into_metadata();
2382 Err(IcmpErrorSender {
2383 err: err.into_icmpv4_error(meta.header_len()),
2384 src_ip,
2385 dst_ip,
2386 frame_dst,
2387 device,
2388 meta,
2389 marks,
2390 })
2391 } else {
2392 Ok(())
2393 }
2394 })
2395}
2396
2397fn dispatch_receive_ipv6_packet<
2402 'a,
2403 'b,
2404 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2405 CC: IpLayerIngressContext<Ipv6, BC>,
2406>(
2407 core_ctx: &'a mut CC,
2408 bindings_ctx: &'a mut BC,
2409 device: &'b CC::DeviceId,
2410 frame_dst: Option<FrameDestination>,
2411 mut packet: Ipv6Packet<&'a mut [u8]>,
2412 mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2413 meta: ReceiveIpPacketMeta<Ipv6>,
2414) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2415 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2422
2423 match frame_dst {
2424 Some(FrameDestination::Individual { local: false }) => {
2425 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2426 }
2427 Some(FrameDestination::Individual { local: true })
2428 | Some(FrameDestination::Multicast)
2429 | Some(FrameDestination::Broadcast)
2430 | None => (),
2431 }
2432
2433 let proto = packet.proto();
2434
2435 match core_ctx.filter_handler().local_ingress_hook(
2436 bindings_ctx,
2437 &mut packet,
2438 device,
2439 &mut packet_metadata,
2440 ) {
2441 filter::Verdict::Drop => {
2442 packet_metadata.acknowledge_drop();
2443 return Ok(());
2444 }
2445 filter::Verdict::Accept(()) => {}
2446 }
2447
2448 let Some(src_ip) = packet.src_ipv6() else {
2452 debug!(
2453 "dispatch_receive_ipv6_packet: received packet from invalid source {} after the \
2454 LOCAL_INGRESS hook; dropping",
2455 packet.src_ip()
2456 );
2457
2458 core_ctx.increment_both(device, |c| &c.invalid_source);
2459 return Ok(());
2460 };
2461 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2462 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2463 debug!(
2464 "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2465 after the LOCAL_INGRESS hook; dropping"
2466 );
2467 return Ok(());
2468 };
2469
2470 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2471
2472 let (fixed, extension, body) = packet.parts_with_body_mut();
2473 let buffer = Buf::new(body, ..);
2474 let header_info = Ipv6HeaderInfo { fixed, extension };
2475 let receive_info = LocalDeliveryPacketInfo { meta, header_info, marks: packet_metadata.marks };
2476
2477 let result = core_ctx
2478 .dispatch_receive_ip_packet(
2479 bindings_ctx,
2480 device,
2481 src_ip,
2482 dst_ip,
2483 proto,
2484 buffer,
2485 &receive_info,
2486 )
2487 .or_else(|err| {
2488 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
2489 let (_, _, _, meta) = packet.into_metadata();
2490 Err(IcmpErrorSender {
2491 err: err.into_icmpv6_error(meta.header_len()),
2492 src_ip: *src_ip,
2493 dst_ip,
2494 frame_dst,
2495 device,
2496 meta,
2497 marks: receive_info.marks,
2498 })
2499 } else {
2500 Ok(())
2501 }
2502 });
2503 packet_metadata.acknowledge_drop();
2504 result
2505}
2506
2507pub(crate) struct IpPacketForwarder<
2514 'a,
2515 I: IpLayerIpExt,
2516 D,
2517 A,
2518 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2519> {
2520 inbound_device: &'a D,
2521 outbound_device: &'a D,
2522 packet_meta: IpLayerPacketMetadata<I, A, BT>,
2523 src_ip: I::RecvSrcAddr,
2524 dst_ip: SpecifiedAddr<I::Addr>,
2525 destination: IpPacketDestination<I, &'a D>,
2526 proto: I::Proto,
2527 parse_meta: ParseMetadata,
2528 frame_dst: Option<FrameDestination>,
2529}
2530
2531impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
2532where
2533 I: IpLayerIpExt,
2534 BC: IpLayerBindingsContext<I, D>,
2535{
2536 fn forward_with_buffer<CC, B>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B)
2538 where
2539 B: BufferMut,
2540 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2541 {
2542 let Self {
2543 inbound_device,
2544 outbound_device,
2545 packet_meta,
2546 src_ip,
2547 dst_ip,
2548 destination,
2549 proto,
2550 parse_meta,
2551 frame_dst,
2552 } = self;
2553
2554 let packet = ForwardedPacket::new(src_ip.get(), dst_ip.get(), proto, parse_meta, buffer);
2555
2556 trace!("forward_with_buffer: forwarding {} packet", I::NAME);
2557
2558 let marks = packet_meta.marks;
2559 match send_ip_frame(
2560 core_ctx,
2561 bindings_ctx,
2562 outbound_device,
2563 destination,
2564 packet,
2565 packet_meta,
2566 Mtu::no_limit(),
2567 ) {
2568 Ok(()) => (),
2569 Err(IpSendFrameError { serializer, error }) => {
2570 match error {
2571 IpSendFrameErrorReason::Device(
2572 SendFrameErrorReason::SizeConstraintsViolation,
2573 ) => {
2574 debug!("failed to forward {} packet: MTU exceeded", I::NAME);
2575 core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
2576 let mtu = core_ctx.get_mtu(inbound_device);
2577 let Some(err) = I::new_mtu_exceeded(proto, parse_meta.header_len(), mtu)
2579 else {
2580 return;
2581 };
2582 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2585 return;
2586 };
2587 core_ctx.send_icmp_error_message(
2597 bindings_ctx,
2598 inbound_device,
2599 frame_dst,
2600 src_ip,
2601 dst_ip,
2602 serializer.into_buffer(),
2603 err,
2604 &marks,
2605 );
2606 }
2607 IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
2608 | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
2609 | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
2610 }
2611 debug!("failed to forward {} packet: {error:?}", I::NAME);
2612 }
2613 }
2614 }
2615}
2616
2617pub(crate) enum ForwardingAction<
2619 'a,
2620 I: IpLayerIpExt,
2621 D,
2622 A,
2623 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2624> {
2625 SilentlyDrop,
2627 Forward(IpPacketForwarder<'a, I, D, A, BT>),
2629 DropWithIcmpError(IcmpErrorSender<'a, I, D>),
2632}
2633
2634impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
2635where
2636 I: IpLayerIpExt,
2637 BC: IpLayerBindingsContext<I, D>,
2638{
2639 pub(crate) fn perform_action_with_buffer<CC, B>(
2641 self,
2642 core_ctx: &mut CC,
2643 bindings_ctx: &mut BC,
2644 buffer: B,
2645 ) where
2646 B: BufferMut,
2647 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2648 {
2649 match self {
2650 ForwardingAction::SilentlyDrop => {}
2651 ForwardingAction::Forward(forwarder) => {
2652 forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer)
2653 }
2654 ForwardingAction::DropWithIcmpError(icmp_sender) => {
2655 icmp_sender.respond_with_icmp_error(core_ctx, bindings_ctx, buffer)
2656 }
2657 }
2658 }
2659}
2660
2661pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
2663 core_ctx: &'a mut CC,
2664 mut packet: I::Packet<&'a mut [u8]>,
2665 mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2666 minimum_ttl: Option<u8>,
2667 inbound_device: &'b CC::DeviceId,
2668 outbound_device: &'b CC::DeviceId,
2669 destination: IpPacketDestination<I, &'b CC::DeviceId>,
2670 frame_dst: Option<FrameDestination>,
2671 src_ip: I::RecvSrcAddr,
2672 dst_ip: SpecifiedAddr<I::Addr>,
2673) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
2674where
2675 I: IpLayerIpExt,
2676 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2677 CC: IpLayerForwardingContext<I, BC>,
2678{
2679 const DEFAULT_MINIMUM_FORWARDING_TTL: u8 = 2;
2684 let minimum_ttl = minimum_ttl.unwrap_or(DEFAULT_MINIMUM_FORWARDING_TTL);
2685
2686 let ttl = packet.ttl();
2687 if ttl < minimum_ttl {
2688 debug!(
2689 "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
2690 I::NAME
2691 );
2692 if ttl > 1 {
2704 packet_meta.acknowledge_drop();
2705 return ForwardingAction::SilentlyDrop;
2706 }
2707
2708 core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
2709
2710 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2712 core_ctx.increment_both(inbound_device, |c| &c.unspecified_source);
2713 packet_meta.acknowledge_drop();
2714 return ForwardingAction::SilentlyDrop;
2715 };
2716
2717 let version_specific_meta = packet.version_specific_meta();
2719 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
2720 let err = I::new_ttl_expired(proto, parse_meta.header_len(), version_specific_meta);
2721 let action = ForwardingAction::DropWithIcmpError(IcmpErrorSender {
2722 err,
2723 src_ip,
2724 dst_ip,
2725 frame_dst,
2726 device: inbound_device,
2727 meta: parse_meta,
2728 marks: packet_meta.marks,
2729 });
2730 packet_meta.acknowledge_drop();
2731 return action;
2732 }
2733
2734 trace!("determine_ip_packet_forwarding_action: adequate TTL");
2735
2736 let maybe_ipv6_packet_action = I::map_ip_in(
2742 &packet,
2743 |_packet| None,
2744 |packet| {
2745 Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
2746 },
2747 );
2748 match maybe_ipv6_packet_action {
2749 None => {} Some(Ipv6PacketAction::_Discard) => {
2751 core_ctx.increment_both(inbound_device, |c| {
2752 #[derive(GenericOverIp)]
2753 #[generic_over_ip(I, Ip)]
2754 struct InCounters<'a, I: IpLayerIpExt>(&'a I::RxCounters<Counter>);
2755 I::map_ip_in::<_, _>(
2756 InCounters(&c.version_rx),
2757 |_counters| {
2758 unreachable!(
2759 "`I` must be `Ipv6` because we're handling IPv6 extension headers"
2760 )
2761 },
2762 |InCounters(counters)| &counters.extension_header_discard,
2763 )
2764 });
2765 trace!(
2766 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
2767 discarding packet"
2768 );
2769 packet_meta.acknowledge_drop();
2770 return ForwardingAction::SilentlyDrop;
2771 }
2772 Some(Ipv6PacketAction::Continue) => {
2773 trace!(
2774 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
2775 forwarding packet"
2776 );
2777 }
2778 Some(Ipv6PacketAction::ProcessFragment) => {
2779 unreachable!(
2780 "When forwarding packets, we should only ever look at the hop by hop \
2781 options extension header (if present)"
2782 )
2783 }
2784 };
2785
2786 match core_ctx.filter_handler().forwarding_hook(
2787 I::as_filter_packet(&mut packet),
2788 inbound_device,
2789 outbound_device,
2790 &mut packet_meta,
2791 ) {
2792 filter::Verdict::Drop => {
2793 packet_meta.acknowledge_drop();
2794 trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
2795 return ForwardingAction::SilentlyDrop;
2796 }
2797 filter::Verdict::Accept(()) => {}
2798 }
2799
2800 packet.set_ttl(ttl - 1);
2801 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
2802 ForwardingAction::Forward(IpPacketForwarder {
2803 inbound_device,
2804 outbound_device,
2805 packet_meta,
2806 src_ip,
2807 dst_ip,
2808 destination,
2809 proto,
2810 parse_meta,
2811 frame_dst,
2812 })
2813}
2814
2815pub(crate) fn send_ip_frame<I, CC, BC, S>(
2816 core_ctx: &mut CC,
2817 bindings_ctx: &mut BC,
2818 device: &CC::DeviceId,
2819 destination: IpPacketDestination<I, &CC::DeviceId>,
2820 mut body: S,
2821 mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2822 limit_mtu: Mtu,
2823) -> Result<(), IpSendFrameError<S>>
2824where
2825 I: IpLayerIpExt,
2826 BC: FilterBindingsContext + TxMetadataBindingsTypes,
2827 CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
2828 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>,
2829{
2830 let (verdict, proof) = core_ctx.filter_handler().egress_hook(
2831 bindings_ctx,
2832 &mut body,
2833 device,
2834 &mut packet_metadata,
2835 );
2836 match verdict {
2837 filter::Verdict::Drop => {
2838 packet_metadata.acknowledge_drop();
2839 return Ok(());
2840 }
2841 filter::Verdict::Accept(()) => {}
2842 }
2843
2844 let (conntrack_connection_and_direction, tx_metadata, marks) = packet_metadata.into_parts();
2848 let conntrack_entry = if device.is_loopback() {
2849 conntrack_connection_and_direction
2850 .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
2851 } else {
2852 None
2853 };
2854 let device_ip_layer_metadata = DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks };
2855
2856 if !device.is_loopback()
2860 && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
2861 || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
2862 {
2863 core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
2864 return Err(IpSendFrameError {
2865 serializer: body,
2866 error: IpSendFrameErrorReason::IllegalLoopbackAddress,
2867 });
2868 }
2869
2870 let mtu = limit_mtu.min(core_ctx.get_mtu(device));
2872
2873 let body = body.with_size_limit(mtu.into());
2874
2875 let fits_mtu =
2876 match body.serialize_new_buf(PacketConstraints::UNCONSTRAINED, AlwaysFailBufferAlloc) {
2877 Err(SerializeError::Alloc(())) => true,
2880 Err(SerializeError::SizeLimitExceeded) => false,
2882 };
2883
2884 if fits_mtu {
2885 return core_ctx
2886 .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
2887 .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
2888 serializer: serializer.into_inner(),
2889 error: error.into(),
2890 });
2891 }
2892
2893 core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
2896
2897 let mut device_ip_layer_metadata = Some(device_ip_layer_metadata);
2899 let body = body.into_inner();
2900 let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
2901 Ok(mut fragmenter) => loop {
2902 let (fragment, has_more) = match fragmenter.next() {
2903 None => break Ok(()),
2904 Some(f) => f,
2905 };
2906
2907 let device_ip_layer_metadata = if has_more {
2912 let device_ip_layer_metadata = device_ip_layer_metadata.as_ref().unwrap();
2914 DeviceIpLayerMetadata {
2915 conntrack_entry: device_ip_layer_metadata.conntrack_entry.clone(),
2916 tx_metadata: Default::default(),
2917 marks: device_ip_layer_metadata.marks,
2918 }
2919 } else {
2920 device_ip_layer_metadata.take().unwrap()
2922 };
2923
2924 match core_ctx.send_ip_frame(
2925 bindings_ctx,
2926 device,
2927 destination.clone(),
2928 device_ip_layer_metadata,
2929 fragment,
2930 proof.clone_for_fragmentation(),
2931 ) {
2932 Ok(()) => {
2933 core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
2934 }
2935 Err(ErrorAndSerializer { serializer: _, error }) => {
2936 core_ctx
2937 .increment_both(device, |c| &c.fragmentation.error_fragmented_serializer);
2938 break Err(error);
2939 }
2940 }
2941 },
2942 Err(e) => {
2943 core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
2944 Err(SendFrameErrorReason::SizeConstraintsViolation)
2945 }
2946 };
2947 result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
2948}
2949
2950struct AlwaysFailBufferAlloc;
2955
2956impl BufferAlloc<Never> for AlwaysFailBufferAlloc {
2957 type Error = ();
2958 fn alloc(self, _len: usize) -> Result<Never, Self::Error> {
2959 Err(())
2960 }
2961}
2962
2963macro_rules! drop_packet_and_undo_parse {
2972 ($packet:expr, $buffer:expr) => {{
2973 let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
2974 $buffer.undo_parse(meta);
2975 (src_ip, dst_ip, proto, meta)
2976 }};
2977}
2978
2979enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
2982 Done,
2985
2986 NotNeeded(I::Packet<&'a mut [u8]>),
2989
2990 Reassembled(Vec<u8>),
2993}
2994
2995fn process_fragment<'a, I, CC, BC>(
3001 core_ctx: &mut CC,
3002 bindings_ctx: &mut BC,
3003 device: &CC::DeviceId,
3004 packet: I::Packet<&'a mut [u8]>,
3005) -> ProcessFragmentResult<'a, I>
3006where
3007 I: IpLayerIpExt,
3008 for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3009 CC: IpLayerIngressContext<I, BC>,
3010 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3011{
3012 match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3013 FragmentProcessingState::NotNeeded(packet) => {
3015 trace!("receive_ip_packet: not fragmented");
3016 ProcessFragmentResult::NotNeeded(packet)
3017 }
3018 FragmentProcessingState::Ready { key, packet_len } => {
3020 trace!("receive_ip_packet: fragmented, ready for reassembly");
3021 let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3023
3024 let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3026 core_ctx,
3027 bindings_ctx,
3028 &key,
3029 buffer.buffer_view_mut(),
3030 ) {
3031 Ok(()) => ProcessFragmentResult::Reassembled(buffer.into_inner()),
3033 Err(e) => {
3034 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3035 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3036 ProcessFragmentResult::Done
3037 }
3038 };
3039 reassemble_result
3040 }
3041 FragmentProcessingState::NeedMoreFragments => {
3044 core_ctx.increment_both(device, |c| &c.need_more_fragments);
3045 trace!("receive_ip_packet: fragmented, need more before reassembly");
3046 ProcessFragmentResult::Done
3047 }
3048 FragmentProcessingState::InvalidFragment => {
3050 core_ctx.increment_both(device, |c| &c.invalid_fragment);
3051 trace!("receive_ip_packet: fragmented, invalid");
3052 ProcessFragmentResult::Done
3053 }
3054 FragmentProcessingState::OutOfMemory => {
3055 core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3056 trace!("receive_ip_packet: fragmented, dropped because OOM");
3057 ProcessFragmentResult::Done
3058 }
3059 }
3060}
3061
3062macro_rules! try_parse_ip_packet {
3072 ($buffer:expr) => {{
3073 let p_len = $buffer.prefix_len();
3074 let s_len = $buffer.suffix_len();
3075
3076 let result = $buffer.parse_mut();
3077
3078 if let Err(err) = result {
3079 let n_p_len = $buffer.prefix_len();
3081 let n_s_len = $buffer.suffix_len();
3082
3083 if p_len > n_p_len {
3084 $buffer.grow_front(p_len - n_p_len);
3085 }
3086
3087 if s_len > n_s_len {
3088 $buffer.grow_back(s_len - n_s_len);
3089 }
3090
3091 Err(err)
3092 } else {
3093 result
3094 }
3095 }};
3096}
3097
3098macro_rules! clone_packet_for_mcast_forwarding {
3116 {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3117 let mut $new_data = $packet.to_vec();
3118 let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3119 let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3120 };
3121}
3122
3123pub fn receive_ipv4_packet<
3128 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3129 B: BufferMut,
3130 CC: IpLayerIngressContext<Ipv4, BC>,
3131>(
3132 core_ctx: &mut CC,
3133 bindings_ctx: &mut BC,
3134 device: &CC::DeviceId,
3135 frame_dst: Option<FrameDestination>,
3136 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3137 buffer: B,
3138) {
3139 if !core_ctx.is_ip_device_enabled(&device) {
3140 return;
3141 }
3142
3143 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3146
3147 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3148 trace!("receive_ip_packet({device:?})");
3149
3150 let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3151 Ok(packet) => packet,
3152 Err(IpParseError::ParameterProblem {
3161 src_ip,
3162 dst_ip,
3163 code,
3164 pointer,
3165 must_send_icmp,
3166 header_len,
3167 action,
3168 }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
3169 core_ctx.increment_both(device, |c| &c.parameter_problem);
3170 assert!(!action.should_send_icmp_to_multicast());
3172 let dst_ip = match SpecifiedAddr::new(dst_ip) {
3173 Some(ip) => ip,
3174 None => {
3175 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3176 debug!("receive_ipv4_packet: Received packet with unspecified destination IP address; dropping");
3177 return;
3178 }
3179 };
3180 let src_ip = match Ipv4SourceAddr::new(src_ip) {
3181 None => {
3182 core_ctx.increment_both(device, |c| &c.invalid_source);
3183 return;
3184 }
3185 Some(Ipv4SourceAddr::Unspecified) => {
3186 core_ctx.increment_both(device, |c| &c.unspecified_source);
3187 return;
3188 }
3189 Some(Ipv4SourceAddr::Specified(src_ip)) => src_ip,
3190 };
3191 IcmpErrorHandler::<Ipv4, _>::send_icmp_error_message(
3192 core_ctx,
3193 bindings_ctx,
3194 device,
3195 frame_dst,
3196 src_ip,
3197 dst_ip,
3198 buffer,
3199 Icmpv4Error {
3200 kind: Icmpv4ErrorKind::ParameterProblem {
3201 code,
3202 pointer,
3203 fragment_type: Ipv4FragmentType::InitialFragment,
3206 },
3207 header_len,
3208 },
3209 &device_ip_layer_metadata.marks,
3210 );
3211 return;
3212 }
3213 _ => return, };
3215
3216 if packet.src_ipv4().is_none() {
3220 debug!(
3221 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3222 packet.src_ip()
3223 );
3224 core_ctx.increment_both(device, |c| &c.invalid_source);
3225 return;
3226 };
3227 if !packet.dst_ip().is_specified() {
3228 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3229 debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3230 return;
3231 };
3232
3233 let mut packet = match process_fragment(core_ctx, bindings_ctx, device, packet) {
3246 ProcessFragmentResult::Done => return,
3247 ProcessFragmentResult::NotNeeded(packet) => packet,
3248 ProcessFragmentResult::Reassembled(buf) => {
3249 let buf = Buf::new(buf, ..);
3250 buffer = packet::Either::B(buf);
3251
3252 match buffer.parse_mut() {
3253 Ok(packet) => packet,
3254 Err(err) => {
3255 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3256 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3257 return;
3258 }
3259 }
3260 }
3261 };
3262
3263 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3266 core_ctx,
3267 device,
3268 device_ip_layer_metadata,
3269 );
3270 let mut filter = core_ctx.filter_handler();
3271 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3272 IngressVerdict::Verdict(filter::Verdict::Accept(())) => {}
3273 IngressVerdict::Verdict(filter::Verdict::Drop) => {
3274 packet_metadata.acknowledge_drop();
3275 return;
3276 }
3277 IngressVerdict::TransparentLocalDelivery { addr, port } => {
3278 drop(filter);
3281
3282 let Some(addr) = SpecifiedAddr::new(addr) else {
3283 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3284 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3285 return;
3286 };
3287
3288 let receive_meta = ReceiveIpPacketMeta {
3289 broadcast: None,
3293 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3294 };
3295
3296 dispatch_receive_ipv4_packet(
3300 core_ctx,
3301 bindings_ctx,
3302 device,
3303 frame_dst,
3304 packet,
3305 packet_metadata,
3306 receive_meta,
3307 )
3308 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3309 return;
3310 }
3311 }
3312 drop(filter);
3315
3316 let Some(src_ip) = packet.src_ipv4() else {
3317 core_ctx.increment_both(device, |c| &c.invalid_source);
3318 debug!(
3319 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3320 packet.src_ip()
3321 );
3322 return;
3323 };
3324
3325 let action = receive_ipv4_packet_action(
3326 core_ctx,
3327 bindings_ctx,
3328 device,
3329 &packet,
3330 frame_dst,
3331 &packet_metadata.marks,
3332 );
3333 match action {
3334 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3335 let mut packet_metadata = Some(packet_metadata);
3342 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3343 clone_packet_for_mcast_forwarding! {
3344 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3345 };
3346 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3347 core_ctx,
3348 copy_of_packet,
3349 packet_metadata.take().unwrap_or_default(),
3350 Some(*min_ttl),
3351 device,
3352 &output_interface,
3353 IpPacketDestination::from_addr(dst_ip),
3354 frame_dst,
3355 src_ip,
3356 dst_ip,
3357 )
3358 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3359 }
3360
3361 if let Some(address_status) = address_status {
3363 let receive_meta = ReceiveIpPacketMeta {
3364 broadcast: address_status.to_broadcast_marker(),
3365 transparent_override: None,
3366 };
3367 dispatch_receive_ipv4_packet(
3368 core_ctx,
3369 bindings_ctx,
3370 device,
3371 frame_dst,
3372 packet,
3373 packet_metadata.take().unwrap_or_default(),
3374 receive_meta,
3375 )
3376 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3377 }
3378 }
3379 ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
3380 match internal_forwarding {
3383 InternalForwarding::Used(outbound_device) => {
3384 core_ctx.increment_both(device, |c| &c.forward);
3385 match core_ctx.filter_handler().forwarding_hook(
3386 &mut packet,
3387 device,
3388 &outbound_device,
3389 &mut packet_metadata,
3390 ) {
3391 filter::Verdict::Drop => {
3392 packet_metadata.acknowledge_drop();
3393 return;
3394 }
3395 filter::Verdict::Accept(()) => {}
3396 }
3397 }
3398 InternalForwarding::NotUsed => {}
3399 }
3400
3401 let receive_meta = ReceiveIpPacketMeta {
3402 broadcast: address_status.to_broadcast_marker(),
3403 transparent_override: None,
3404 };
3405 dispatch_receive_ipv4_packet(
3406 core_ctx,
3407 bindings_ctx,
3408 device,
3409 frame_dst,
3410 packet,
3411 packet_metadata,
3412 receive_meta,
3413 )
3414 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3415 }
3416 ReceivePacketAction::Forward {
3417 original_dst,
3418 dst: Destination { device: dst_device, next_hop },
3419 } => {
3420 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3421 core_ctx,
3422 packet,
3423 packet_metadata,
3424 None,
3425 device,
3426 &dst_device,
3427 IpPacketDestination::from_next_hop(next_hop, original_dst),
3428 frame_dst,
3429 src_ip,
3430 original_dst,
3431 )
3432 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3433 }
3434 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3435 use packet_formats::ipv4::Ipv4Header as _;
3436 core_ctx.increment_both(device, |c| &c.no_route_to_host);
3437 debug!("received IPv4 packet with no known route to destination {}", dst_ip);
3438 let fragment_type = packet.fragment_type();
3439 let (_, _, proto, meta): (Ipv4Addr, Ipv4Addr, _, _) =
3440 drop_packet_and_undo_parse!(packet, buffer);
3441 let marks = packet_metadata.marks;
3442 packet_metadata.acknowledge_drop();
3443 let src_ip = match src_ip {
3444 Ipv4SourceAddr::Unspecified => {
3445 core_ctx.increment_both(device, |c| &c.unspecified_source);
3446 return;
3447 }
3448 Ipv4SourceAddr::Specified(src_ip) => src_ip,
3449 };
3450 IcmpErrorHandler::<Ipv4, _>::send_icmp_error_message(
3451 core_ctx,
3452 bindings_ctx,
3453 device,
3454 frame_dst,
3455 src_ip,
3456 dst_ip,
3457 buffer,
3458 Icmpv4Error {
3459 kind: Icmpv4ErrorKind::NetUnreachable { proto, fragment_type },
3460 header_len: meta.header_len(),
3461 },
3462 &marks,
3463 );
3464 }
3465 ReceivePacketAction::Drop { reason } => {
3466 let src_ip = packet.src_ip();
3467 let dst_ip = packet.dst_ip();
3468 packet_metadata.acknowledge_drop();
3469 core_ctx.increment_both(device, |c| &c.dropped);
3470 debug!(
3471 "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
3472 {device:?}: {reason:?}",
3473 );
3474 }
3475 }
3476}
3477
3478pub fn receive_ipv6_packet<
3483 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3484 B: BufferMut,
3485 CC: IpLayerIngressContext<Ipv6, BC>,
3486>(
3487 core_ctx: &mut CC,
3488 bindings_ctx: &mut BC,
3489 device: &CC::DeviceId,
3490 frame_dst: Option<FrameDestination>,
3491 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3492 buffer: B,
3493) {
3494 if !core_ctx.is_ip_device_enabled(&device) {
3495 return;
3496 }
3497
3498 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3501
3502 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3503 trace!("receive_ipv6_packet({:?})", device);
3504
3505 let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
3506 Ok(packet) => packet,
3507 Err(IpParseError::ParameterProblem {
3513 src_ip,
3514 dst_ip,
3515 code,
3516 pointer,
3517 must_send_icmp,
3518 header_len: _,
3519 action,
3520 }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
3521 core_ctx.increment_both(device, |c| &c.parameter_problem);
3522 let dst_ip = match SpecifiedAddr::new(dst_ip) {
3523 Some(ip) => ip,
3524 None => {
3525 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3526 debug!("receive_ipv6_packet: Received packet with unspecified destination IP address; dropping");
3527 return;
3528 }
3529 };
3530 let src_ip = match Ipv6SourceAddr::new(src_ip) {
3531 None => {
3532 core_ctx.increment_both(device, |c| &c.invalid_source);
3533 return;
3534 }
3535 Some(Ipv6SourceAddr::Unspecified) => {
3536 core_ctx.increment_both(device, |c| &c.unspecified_source);
3537 return;
3538 }
3539 Some(Ipv6SourceAddr::Unicast(src_ip)) => src_ip,
3540 };
3541 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3542 core_ctx,
3543 bindings_ctx,
3544 device,
3545 frame_dst,
3546 *src_ip,
3547 dst_ip,
3548 buffer,
3549 Icmpv6ErrorKind::ParameterProblem {
3550 code,
3551 pointer,
3552 allow_dst_multicast: action.should_send_icmp_to_multicast(),
3553 },
3554 &device_ip_layer_metadata.marks,
3555 );
3556 return;
3557 }
3558 _ => return, };
3560
3561 trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
3562
3563 if packet.src_ipv6().is_none() {
3569 debug!(
3570 "receive_ipv6_packet: received packet from invalid source {}; dropping",
3571 packet.src_ip()
3572 );
3573 core_ctx.increment_both(device, |c| &c.invalid_source);
3574 return;
3575 };
3576 if !packet.dst_ip().is_specified() {
3577 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3578 debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
3579 return;
3580 };
3581
3582 let (mut packet, delivery_extension_header_action) =
3593 match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
3594 Ipv6PacketAction::_Discard => {
3595 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3596 trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
3597 return;
3598 }
3599 Ipv6PacketAction::Continue => {
3600 trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
3601 (packet, Some(Ipv6PacketAction::Continue))
3602 }
3603 Ipv6PacketAction::ProcessFragment => {
3604 trace!(
3605 "receive_ipv6_packet: handled IPv6 extension headers: handling \
3606 fragmented packet"
3607 );
3608
3609 match process_fragment(core_ctx, bindings_ctx, device, packet) {
3621 ProcessFragmentResult::Done => return,
3622 ProcessFragmentResult::NotNeeded(packet) => {
3623 (packet, Some(Ipv6PacketAction::Continue))
3638 }
3639 ProcessFragmentResult::Reassembled(buf) => {
3640 let buf = Buf::new(buf, ..);
3641 buffer = packet::Either::B(buf);
3642
3643 match buffer.parse_mut() {
3644 Ok(packet) => (packet, None),
3645 Err(err) => {
3646 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3647 debug!(
3648 "receive_ip_packet: fragmented, failed to reassemble: {:?}",
3649 err
3650 );
3651 return;
3652 }
3653 }
3654 }
3655 }
3656 }
3657 };
3658
3659 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3660 core_ctx,
3661 device,
3662 device_ip_layer_metadata,
3663 );
3664 let mut filter = core_ctx.filter_handler();
3665
3666 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3667 IngressVerdict::Verdict(filter::Verdict::Accept(())) => {}
3668 IngressVerdict::Verdict(filter::Verdict::Drop) => {
3669 packet_metadata.acknowledge_drop();
3670 return;
3671 }
3672 IngressVerdict::TransparentLocalDelivery { addr, port } => {
3673 drop(filter);
3676
3677 let Some(addr) = SpecifiedAddr::new(addr) else {
3678 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3679 debug!("cannot perform transparent delivery to unspecified destination; dropping");
3680 return;
3681 };
3682
3683 let receive_meta = ReceiveIpPacketMeta {
3684 broadcast: None,
3685 transparent_override: Some(TransparentLocalDelivery { addr, port }),
3686 };
3687
3688 dispatch_receive_ipv6_packet(
3692 core_ctx,
3693 bindings_ctx,
3694 device,
3695 frame_dst,
3696 packet,
3697 packet_metadata,
3698 receive_meta,
3699 )
3700 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3701 return;
3702 }
3703 }
3704 drop(filter);
3707
3708 let Some(src_ip) = packet.src_ipv6() else {
3709 debug!(
3710 "receive_ipv6_packet: received packet from invalid source {}; dropping",
3711 packet.src_ip()
3712 );
3713 core_ctx.increment_both(device, |c| &c.invalid_source);
3714 return;
3715 };
3716
3717 match receive_ipv6_packet_action(
3718 core_ctx,
3719 bindings_ctx,
3720 device,
3721 &packet,
3722 frame_dst,
3723 &packet_metadata.marks,
3724 ) {
3725 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3726 let mut packet_metadata = Some(packet_metadata);
3733 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3734 clone_packet_for_mcast_forwarding! {
3735 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3736 };
3737 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
3738 core_ctx,
3739 copy_of_packet,
3740 packet_metadata.take().unwrap_or_default(),
3741 Some(*min_ttl),
3742 device,
3743 &output_interface,
3744 IpPacketDestination::from_addr(dst_ip),
3745 frame_dst,
3746 src_ip,
3747 dst_ip,
3748 )
3749 .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3750 }
3751
3752 if let Some(_) = address_status {
3754 let receive_meta =
3755 ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
3756
3757 dispatch_receive_ipv6_packet(
3758 core_ctx,
3759 bindings_ctx,
3760 device,
3761 frame_dst,
3762 packet,
3763 packet_metadata.take().unwrap_or_default(),
3764 receive_meta,
3765 )
3766 .unwrap_or_else(|err| err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer));
3767 }
3768 }
3769 ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
3770 trace!("receive_ipv6_packet: delivering locally");
3771
3772 let action = if let Some(action) = delivery_extension_header_action {
3773 action
3774 } else {
3775 ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
3776 };
3777 match action {
3778 Ipv6PacketAction::_Discard => {
3779 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3780 trace!(
3781 "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
3782 );
3783 packet_metadata.acknowledge_drop();
3784 }
3785 Ipv6PacketAction::Continue => {
3786 trace!(
3787 "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
3788 );
3789
3790 match internal_forwarding {
3793 InternalForwarding::Used(outbound_device) => {
3794 core_ctx.increment_both(device, |c| &c.forward);
3795 match core_ctx.filter_handler().forwarding_hook(
3796 &mut packet,
3797 device,
3798 &outbound_device,
3799 &mut packet_metadata,
3800 ) {
3801 filter::Verdict::Drop => {
3802 packet_metadata.acknowledge_drop();
3803 return;
3804 }
3805 filter::Verdict::Accept(()) => {}
3806 }
3807 }
3808 InternalForwarding::NotUsed => {}
3809 }
3810
3811 let meta = ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
3812
3813 dispatch_receive_ipv6_packet(
3818 core_ctx,
3819 bindings_ctx,
3820 device,
3821 frame_dst,
3822 packet,
3823 packet_metadata,
3824 meta,
3825 )
3826 .unwrap_or_else(|err| {
3827 err.respond_with_icmp_error(core_ctx, bindings_ctx, buffer)
3828 });
3829 }
3830 Ipv6PacketAction::ProcessFragment => {
3831 debug!("receive_ipv6_packet: found fragment header after reassembly; dropping");
3832 packet_metadata.acknowledge_drop();
3833 }
3834 }
3835 }
3836 ReceivePacketAction::Forward {
3837 original_dst,
3838 dst: Destination { device: dst_device, next_hop },
3839 } => {
3840 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
3841 core_ctx,
3842 packet,
3843 packet_metadata,
3844 None,
3845 device,
3846 &dst_device,
3847 IpPacketDestination::from_next_hop(next_hop, original_dst),
3848 frame_dst,
3849 src_ip,
3850 original_dst,
3851 )
3852 .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3853 }
3854 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3855 core_ctx.increment_both(device, |c| &c.no_route_to_host);
3856 let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
3857 drop_packet_and_undo_parse!(packet, buffer);
3858 debug!("received IPv6 packet with no known route to destination {}", dst_ip);
3859 let marks = packet_metadata.marks;
3860 packet_metadata.acknowledge_drop();
3861
3862 let src_ip = match src_ip {
3863 Ipv6SourceAddr::Unspecified => {
3864 core_ctx.increment_both(device, |c| &c.unspecified_source);
3865 return;
3866 }
3867 Ipv6SourceAddr::Unicast(src_ip) => src_ip,
3868 };
3869 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3870 core_ctx,
3871 bindings_ctx,
3872 device,
3873 frame_dst,
3874 *src_ip,
3875 dst_ip,
3876 buffer,
3877 Icmpv6ErrorKind::NetUnreachable { proto, header_len: meta.header_len() },
3878 &marks,
3879 );
3880 }
3881 ReceivePacketAction::Drop { reason } => {
3882 core_ctx.increment_both(device, |c| &c.dropped);
3883 let src_ip = packet.src_ip();
3884 let dst_ip = packet.dst_ip();
3885 packet_metadata.acknowledge_drop();
3886 debug!(
3887 "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
3888 {device:?}: {reason:?}",
3889 );
3890 }
3891 }
3892}
3893
3894#[derive(Debug, PartialEq)]
3896pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
3897 Deliver {
3899 address_status: I::AddressStatus,
3901 internal_forwarding: InternalForwarding<DeviceId>,
3904 },
3905
3906 Forward {
3908 original_dst: SpecifiedAddr<I::Addr>,
3910 dst: Destination<I::Addr, DeviceId>,
3912 },
3913
3914 MulticastForward {
3922 targets: MulticastRouteTargets<DeviceId>,
3924 address_status: Option<I::AddressStatus>,
3927 dst_ip: SpecifiedAddr<I::Addr>,
3929 },
3930
3931 SendNoRouteToDest {
3937 dst: SpecifiedAddr<I::Addr>,
3939 },
3940
3941 #[allow(missing_docs)]
3945 Drop { reason: DropReason },
3946}
3947
3948#[derive(Debug, PartialEq)]
3950pub enum DropReason {
3951 Tentative,
3953 UnspecifiedDestination,
3955 ForwardUnspecifiedSource,
3957 ForwardingDisabledInboundIface,
3960 MulticastNoInterest,
3966}
3967
3968pub fn receive_ipv4_packet_action<BC, CC, B>(
3970 core_ctx: &mut CC,
3971 bindings_ctx: &mut BC,
3972 device: &CC::DeviceId,
3973 packet: &Ipv4Packet<B>,
3974 frame_dst: Option<FrameDestination>,
3975 marks: &Marks,
3976) -> ReceivePacketAction<Ipv4, CC::DeviceId>
3977where
3978 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3979 CC: IpLayerContext<Ipv4, BC>,
3980 B: SplitByteSlice,
3981{
3982 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
3983 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3984 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
3985 };
3986
3987 let first_status = if device.is_loopback() {
4003 core_ctx.with_address_statuses(dst_ip, |it| it.map(|(_device, status)| status).next())
4004 } else {
4005 core_ctx.address_status_for_device(dst_ip, device).into_present()
4006 };
4007 match first_status {
4008 Some(
4009 address_status @ (Ipv4PresentAddressStatus::Unicast
4010 | Ipv4PresentAddressStatus::LoopbackSubnet),
4011 ) => {
4012 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4013 ReceivePacketAction::Deliver {
4014 address_status,
4015 internal_forwarding: InternalForwarding::NotUsed,
4016 }
4017 }
4018 Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4019 receive_ip_multicast_packet_action(
4020 core_ctx,
4021 bindings_ctx,
4022 device,
4023 packet,
4024 Some(address_status),
4025 dst_ip,
4026 frame_dst,
4027 )
4028 }
4029 Some(
4030 address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4031 | Ipv4PresentAddressStatus::SubnetBroadcast),
4032 ) => {
4033 core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
4034 ReceivePacketAction::Deliver {
4035 address_status,
4036 internal_forwarding: InternalForwarding::NotUsed,
4037 }
4038 }
4039 None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4040 core_ctx,
4041 bindings_ctx,
4042 dst_ip,
4043 device,
4044 packet,
4045 frame_dst,
4046 marks,
4047 ),
4048 }
4049}
4050
4051pub fn receive_ipv6_packet_action<BC, CC, B>(
4053 core_ctx: &mut CC,
4054 bindings_ctx: &mut BC,
4055 device: &CC::DeviceId,
4056 packet: &Ipv6Packet<B>,
4057 frame_dst: Option<FrameDestination>,
4058 marks: &Marks,
4059) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4060where
4061 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4062 CC: IpLayerContext<Ipv6, BC>,
4063 B: SplitByteSlice,
4064{
4065 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4066 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4067 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4068 };
4069
4070 fn choose_highest_priority(
4089 address_statuses: impl Iterator<Item = Ipv6PresentAddressStatus>,
4090 dst_ip: SpecifiedAddr<Ipv6Addr>,
4091 ) -> Option<Ipv6PresentAddressStatus> {
4092 address_statuses.max_by(|lhs, rhs| {
4093 use Ipv6PresentAddressStatus::*;
4094 match (lhs, rhs) {
4095 (UnicastAssigned | UnicastTentative, Multicast)
4096 | (Multicast, UnicastAssigned | UnicastTentative) => {
4097 unreachable!("the IPv6 address {:?} is not both unicast and multicast", dst_ip)
4098 }
4099 (UnicastAssigned, UnicastTentative) => Ordering::Greater,
4100 (UnicastTentative, UnicastAssigned) => Ordering::Less,
4101 (UnicastTentative, UnicastTentative)
4102 | (UnicastAssigned, UnicastAssigned)
4103 | (Multicast, Multicast) => Ordering::Equal,
4104 }
4105 })
4106 }
4107
4108 let highest_priority = if device.is_loopback() {
4109 core_ctx.with_address_statuses(dst_ip, |it| {
4110 let it = it.map(|(_device, status)| status);
4111 choose_highest_priority(it, dst_ip)
4112 })
4113 } else {
4114 core_ctx.address_status_for_device(dst_ip, device).into_present()
4115 };
4116 match highest_priority {
4117 Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
4118 receive_ip_multicast_packet_action(
4119 core_ctx,
4120 bindings_ctx,
4121 device,
4122 packet,
4123 Some(address_status),
4124 dst_ip,
4125 frame_dst,
4126 )
4127 }
4128 Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
4129 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4130 ReceivePacketAction::Deliver {
4131 address_status,
4132 internal_forwarding: InternalForwarding::NotUsed,
4133 }
4134 }
4135 Some(Ipv6PresentAddressStatus::UnicastTentative) => {
4136 core_ctx.increment_both(device, |c| &c.version_rx.drop_for_tentative);
4167 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4168 }
4169 None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
4170 core_ctx,
4171 bindings_ctx,
4172 dst_ip,
4173 device,
4174 packet,
4175 frame_dst,
4176 marks,
4177 ),
4178 }
4179}
4180
4181fn receive_ip_multicast_packet_action<
4184 I: IpLayerIpExt,
4185 B: SplitByteSlice,
4186 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4187 CC: IpLayerContext<I, BC>,
4188>(
4189 core_ctx: &mut CC,
4190 bindings_ctx: &mut BC,
4191 device: &CC::DeviceId,
4192 packet: &I::Packet<B>,
4193 address_status: Option<I::AddressStatus>,
4194 dst_ip: SpecifiedAddr<I::Addr>,
4195 frame_dst: Option<FrameDestination>,
4196) -> ReceivePacketAction<I, CC::DeviceId> {
4197 let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
4198 core_ctx,
4199 bindings_ctx,
4200 packet,
4201 device,
4202 frame_dst,
4203 );
4204 match (targets, address_status) {
4205 (Some(targets), address_status) => {
4206 if address_status.is_some() {
4207 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4208 }
4209 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
4210 }
4211 (None, Some(address_status)) => {
4212 core_ctx.increment_both(device, |c| &c.deliver_multicast);
4215 ReceivePacketAction::Deliver {
4216 address_status,
4217 internal_forwarding: InternalForwarding::NotUsed,
4218 }
4219 }
4220 (None, None) => {
4221 core_ctx.increment_both(device, |c| &c.multicast_no_interest);
4230 ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
4231 }
4232 }
4233}
4234
4235fn receive_ip_packet_action_common<
4238 I: IpLayerIpExt,
4239 B: SplitByteSlice,
4240 BC: IpLayerBindingsContext<I, CC::DeviceId>,
4241 CC: IpLayerContext<I, BC>,
4242>(
4243 core_ctx: &mut CC,
4244 bindings_ctx: &mut BC,
4245 dst_ip: SpecifiedAddr<I::Addr>,
4246 device_id: &CC::DeviceId,
4247 packet: &I::Packet<B>,
4248 frame_dst: Option<FrameDestination>,
4249 marks: &Marks,
4250) -> ReceivePacketAction<I, CC::DeviceId> {
4251 if dst_ip.is_multicast() {
4252 return receive_ip_multicast_packet_action(
4253 core_ctx,
4254 bindings_ctx,
4255 device_id,
4256 packet,
4257 None,
4258 dst_ip,
4259 frame_dst,
4260 );
4261 }
4262
4263 if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
4265 core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
4278 return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
4279 }
4280 let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
4287 return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
4288 };
4289
4290 if let Some(dst_ip) = NonMappedAddr::new(dst_ip).and_then(NonMulticastAddr::new) {
4297 if let Some((outbound_device, address_status)) =
4298 get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
4299 {
4300 return ReceivePacketAction::Deliver {
4301 address_status,
4302 internal_forwarding: InternalForwarding::Used(outbound_device),
4303 };
4304 }
4305 }
4306
4307 match lookup_route_table(
4308 core_ctx,
4309 *dst_ip,
4310 RuleInput {
4311 packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
4312 marks,
4313 },
4314 ) {
4315 Some(dst) => {
4316 core_ctx.increment_both(device_id, |c| &c.forward);
4317 ReceivePacketAction::Forward { original_dst: dst_ip, dst }
4318 }
4319 None => {
4320 core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
4321 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
4322 }
4323 }
4324}
4325
4326fn lookup_route_table<I: IpLayerIpExt, CC: IpStateContext<I>>(
4328 core_ctx: &mut CC,
4329 dst_ip: I::Addr,
4330 rule_input: RuleInput<'_, I, CC::DeviceId>,
4331) -> Option<Destination<I::Addr, CC::DeviceId>> {
4332 let bound_device = match rule_input.packet_origin {
4333 PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
4334 PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
4335 };
4336 core_ctx.with_rules_table(|core_ctx, rules| {
4337 match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
4338 match table.lookup(core_ctx, bound_device, dst_ip) {
4339 Some(dst) => ControlFlow::Break(Some(dst)),
4340 None => ControlFlow::Continue(()),
4341 }
4342 }) {
4343 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
4344 inner: dst,
4345 observed_source_address_matcher: _,
4346 })) => dst,
4347 ControlFlow::Break(RuleAction::Unreachable) => None,
4348 ControlFlow::Continue(RuleWalkInfo {
4349 inner: (),
4350 observed_source_address_matcher: _,
4351 }) => None,
4352 }
4353 })
4354}
4355
4356#[derive(Debug, Derivative, Clone)]
4358#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
4359pub enum IpPacketDestination<I: BroadcastIpExt, D> {
4360 Broadcast(I::BroadcastMarker),
4362
4363 Multicast(MulticastAddr<I::Addr>),
4365
4366 Neighbor(SpecifiedAddr<I::Addr>),
4369
4370 Loopback(D),
4373}
4374
4375impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
4376 pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
4378 match MulticastAddr::new(addr.into_addr()) {
4379 Some(mc_addr) => Self::Multicast(mc_addr),
4380 None => Self::Neighbor(addr),
4381 }
4382 }
4383
4384 pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
4386 match next_hop {
4387 NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
4388 NextHop::Gateway(gateway) => Self::Neighbor(gateway),
4389 NextHop::Broadcast(marker) => Self::Broadcast(marker),
4390 }
4391 }
4392}
4393
4394#[derive(Debug, Clone)]
4396pub struct SendIpPacketMeta<I: IpExt, D, Src> {
4397 pub device: D,
4399
4400 pub src_ip: Src,
4402
4403 pub dst_ip: SpecifiedAddr<I::Addr>,
4405
4406 pub destination: IpPacketDestination<I, D>,
4408
4409 pub proto: I::Proto,
4411
4412 pub ttl: Option<NonZeroU8>,
4416
4417 pub mtu: Mtu,
4422
4423 pub dscp_and_ecn: DscpAndEcn,
4425}
4426
4427impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4428 for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
4429{
4430 fn from(
4431 SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
4432 I,
4433 D,
4434 SpecifiedAddr<I::Addr>,
4435 >,
4436 ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
4437 SendIpPacketMeta {
4438 device,
4439 src_ip: Some(src_ip),
4440 dst_ip,
4441 destination,
4442 proto,
4443 ttl,
4444 mtu,
4445 dscp_and_ecn,
4446 }
4447 }
4448}
4449
4450pub trait IpLayerHandler<I: IpExt + FragmentationIpExt + FilterIpExt, BC>:
4456 DeviceIdContext<AnyDevice>
4457{
4458 fn send_ip_packet_from_device<S>(
4461 &mut self,
4462 bindings_ctx: &mut BC,
4463 meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4464 body: S,
4465 ) -> Result<(), IpSendFrameError<S>>
4466 where
4467 S: TransportPacketSerializer<I>,
4468 S::Buffer: BufferMut;
4469
4470 fn send_ip_frame<S>(
4477 &mut self,
4478 bindings_ctx: &mut BC,
4479 device: &Self::DeviceId,
4480 destination: IpPacketDestination<I, &Self::DeviceId>,
4481 body: S,
4482 ) -> Result<(), IpSendFrameError<S>>
4483 where
4484 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>;
4485}
4486
4487impl<
4488 I: IpLayerIpExt,
4489 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
4490 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4491 > IpLayerHandler<I, BC> for CC
4492{
4493 fn send_ip_packet_from_device<S>(
4494 &mut self,
4495 bindings_ctx: &mut BC,
4496 meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4497 body: S,
4498 ) -> Result<(), IpSendFrameError<S>>
4499 where
4500 S: TransportPacketSerializer<I>,
4501 S::Buffer: BufferMut,
4502 {
4503 send_ip_packet_from_device(self, bindings_ctx, meta, body, IpLayerPacketMetadata::default())
4504 }
4505
4506 fn send_ip_frame<S>(
4507 &mut self,
4508 bindings_ctx: &mut BC,
4509 device: &Self::DeviceId,
4510 destination: IpPacketDestination<I, &Self::DeviceId>,
4511 body: S,
4512 ) -> Result<(), IpSendFrameError<S>>
4513 where
4514 S: FragmentableIpSerializer<I, Buffer: BufferMut> + IpPacket<I>,
4515 {
4516 send_ip_frame(
4517 self,
4518 bindings_ctx,
4519 device,
4520 destination,
4521 body,
4522 IpLayerPacketMetadata::default(),
4523 Mtu::no_limit(),
4524 )
4525 }
4526}
4527
4528pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
4535 core_ctx: &mut CC,
4536 bindings_ctx: &mut BC,
4537 meta: SendIpPacketMeta<
4538 I,
4539 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
4540 Option<SpecifiedAddr<I::Addr>>,
4541 >,
4542 body: S,
4543 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
4544) -> Result<(), IpSendFrameError<S>>
4545where
4546 I: IpLayerIpExt,
4547 BC: FilterBindingsContext + TxMetadataBindingsTypes,
4548 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4549 S: TransportPacketSerializer<I>,
4550 S::Buffer: BufferMut,
4551{
4552 let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
4553 meta;
4554 core_ctx.increment_both(device, |c| &c.send_ip_packet);
4555 let next_packet_id = gen_ip_packet_id(core_ctx);
4556 let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
4557 let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
4558 let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
4559
4560 #[derive(GenericOverIp)]
4561 #[generic_over_ip(I, Ip)]
4562 struct Wrap<'a, I: IpLayerIpExt> {
4563 builder: &'a mut I::PacketBuilder,
4564 next_packet_id: I::PacketId,
4565 }
4566
4567 I::map_ip::<_, ()>(
4568 Wrap { builder: &mut builder, next_packet_id },
4569 |Wrap { builder, next_packet_id }| {
4570 builder.id(next_packet_id);
4571 },
4572 |Wrap { builder: _, next_packet_id: () }| {
4573 },
4575 );
4576
4577 builder.set_dscp_and_ecn(dscp_and_ecn);
4578
4579 let ip_frame = body.encapsulate(builder);
4580 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
4581 .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
4582}
4583
4584pub trait FilterHandlerProvider<I: FilterIpExt, BT: FilterBindingsTypes>:
4586 IpDeviceAddressIdContext<I, DeviceId: filter::InterfaceProperties<BT::DeviceClass>>
4587{
4588 type Handler<'a>: filter::FilterHandler<
4590 I,
4591 BT,
4592 DeviceId = Self::DeviceId,
4593 WeakAddressId = Self::WeakAddressId,
4594 >
4595 where
4596 Self: 'a;
4597
4598 fn filter_handler(&mut self) -> Self::Handler<'_>;
4600}
4601
4602#[cfg(any(test, feature = "testutils"))]
4603pub(crate) mod testutil {
4604 use super::*;
4605
4606 use netstack3_base::testutil::{FakeCoreCtx, FakeStrongDeviceId};
4607 use netstack3_base::{AssignedAddrIpExt, SendFrameContext, SendFrameError, SendableFrameMeta};
4608 use packet::Serializer;
4609
4610 #[derive(Debug, GenericOverIp)]
4612 #[generic_over_ip()]
4613 #[allow(missing_docs)]
4614 pub enum DualStackSendIpPacketMeta<D> {
4615 V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
4616 V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
4617 }
4618
4619 impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4620 for DualStackSendIpPacketMeta<D>
4621 {
4622 fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
4623 #[derive(GenericOverIp)]
4624 #[generic_over_ip(I, Ip)]
4625 struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
4626 use DualStackSendIpPacketMeta::*;
4627 I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
4628 }
4629 }
4630
4631 impl<I: IpExt, S, DeviceId, BC>
4632 SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
4633 for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
4634 {
4635 fn send_meta<SS>(
4636 self,
4637 core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
4638 bindings_ctx: &mut BC,
4639 frame: SS,
4640 ) -> Result<(), SendFrameError<SS>>
4641 where
4642 SS: Serializer,
4643 SS::Buffer: BufferMut,
4644 {
4645 SendFrameContext::send_frame(
4646 &mut core_ctx.frames,
4647 bindings_ctx,
4648 DualStackSendIpPacketMeta::from(self),
4649 frame,
4650 )
4651 }
4652 }
4653
4654 #[derive(Debug)]
4656 pub struct WrongIpVersion;
4657
4658 impl<D> DualStackSendIpPacketMeta<D> {
4659 pub fn try_as<I: IpExt>(
4662 &self,
4663 ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
4664 #[derive(GenericOverIp)]
4665 #[generic_over_ip(I, Ip)]
4666 struct Wrap<'a, I: IpExt, D>(
4667 Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
4668 );
4669 use DualStackSendIpPacketMeta::*;
4670 let Wrap(dual_stack) = I::map_ip(
4671 self,
4672 |value| {
4673 Wrap(match value {
4674 V4(meta) => Some(meta),
4675 V6(_) => None,
4676 })
4677 },
4678 |value| {
4679 Wrap(match value {
4680 V4(_) => None,
4681 V6(meta) => Some(meta),
4682 })
4683 },
4684 );
4685 dual_stack.ok_or(WrongIpVersion)
4686 }
4687 }
4688
4689 impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
4690 where
4691 I: AssignedAddrIpExt + FilterIpExt,
4692 BC: FilterBindingsContext,
4693 DeviceId: FakeStrongDeviceId + filter::InterfaceProperties<BC::DeviceClass>,
4694 {
4695 type Handler<'a>
4696 = filter::testutil::NoopImpl<DeviceId>
4697 where
4698 Self: 'a;
4699
4700 fn filter_handler(&mut self) -> Self::Handler<'_> {
4701 filter::testutil::NoopImpl::default()
4702 }
4703 }
4704}