1use alloc::boxed::Box;
6use alloc::vec::Vec;
7use core::fmt::Debug;
8use core::hash::Hash;
9use core::marker::PhantomData;
10use core::num::NonZeroU8;
11use core::ops::ControlFlow;
12#[cfg(test)]
13use core::ops::DerefMut;
14use core::sync::atomic::{self, AtomicU16};
15
16use derivative::Derivative;
17use explicit::ResultExt as _;
18use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
19use log::{debug, error, trace};
20use net_types::ip::{
21 GenericOverIp, Ip, IpVersion, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu, Subnet,
22};
23use net_types::{
24 LinkLocalAddress, MulticastAddr, MulticastAddress, NonMappedAddr, NonMulticastAddr,
25 SpecifiedAddr, SpecifiedAddress as _, Witness,
26};
27use netstack3_base::socket::{EitherStack, SocketIpAddr, SocketIpAddrExt as _};
28use netstack3_base::sync::{Mutex, PrimaryRc, RwLock, StrongRc, WeakRc};
29use netstack3_base::{
30 AnyDevice, BroadcastIpExt, CoreTimerContext, Counter, CounterCollectionSpec, CounterContext,
31 DeviceIdContext, DeviceIdentifier as _, ErrorAndSerializer, EventContext, GsoInfo,
32 HandleableTimer, InstantContext, InterfaceProperties, IpAddressId, IpDeviceAddr,
33 IpDeviceAddressIdContext, IpExt, LocalFrameDestination, MarkDomain, Marks, Matcher as _,
34 MatcherBindingsTypes, NestedIntoCoreTimerCtx, NetworkParsingContext,
35 NetworkSerializationContext, NotFoundError, PacketType, ResourceCounterContext, RngContext,
36 SendFrameErrorReason, StrongDeviceIdentifier, TimerBindingsTypes, TimerContext, TimerHandler,
37 TxMetadata as _, TxMetadataBindingsTypes, WeakIpAddressId, WrapBroadcastMarker,
38};
39use netstack3_filter::{
40 self as filter, ConnectionDirection, ConntrackConnection, FilterBindingsContext,
41 FilterBindingsTypes, FilterHandler as _, FilterIpContext, FilterIpExt, FilterIpMetadata,
42 FilterIpPacket, FilterPacketMetadata, FilterTimerId, ForwardedPacket, IpPacket, MarkAction,
43 MaybeTransportPacket as _, ProofOfEgressCheck, RejectType, SocketInfo,
44 TransportPacketSerializer, Tuple, WeakConnectionError, WeakConntrackConnection,
45};
46use netstack3_hashmap::HashMap;
47use packet::{
48 Buf, BufferMut, GrowBuffer, LayoutBufferAlloc, NestablePacketBuilder as _, PacketConstraints,
49 ParsablePacket as _, ParseBuffer, ParseBufferMut, ParseMetadata, SerializeError,
50 Serializer as _,
51};
52use packet_formats::error::{Ipv6ParseError, ParseError};
53use packet_formats::ip::{DscpAndEcn, IpPacket as _, IpPacketBuilder as _};
54use packet_formats::ipv4::{Ipv4FragmentType, Ipv4Packet};
55use packet_formats::ipv6::ext_hdrs::Ipv6ExtensionHeader;
56use packet_formats::ipv6::{Ipv6Packet, Ipv6PacketRaw};
57use thiserror::Error;
58use zerocopy::SplitByteSlice;
59
60use crate::internal::counters::{IpCounters, IpCountersIpExt};
61use crate::internal::device::opaque_iid::IidSecret;
62use crate::internal::device::slaac::SlaacCounters;
63use crate::internal::device::state::{
64 IpAddressData, IpAddressFlags, IpDeviceStateBindingsTypes, IpDeviceStateIpExt, WeakAddressId,
65};
66use crate::internal::device::{
67 self, IpDeviceAddressContext, IpDeviceBindingsContext, IpDeviceIpExt, IpDeviceSendContext,
68};
69use crate::internal::fragmentation::{FragmentableIpSerializer, FragmentationIpExt, IpFragmenter};
70use crate::internal::gmp::GmpQueryHandler;
71use crate::internal::gmp::igmp::IgmpCounters;
72use crate::internal::gmp::mld::MldCounters;
73use crate::internal::gso::{
74 GsoError, GsoIpExt, MaybeSegmentableIpSerializer, MaybeSegmentableTransportSerializer,
75};
76use crate::internal::icmp::counters::IcmpCountersIpExt;
77use crate::internal::icmp::{
78 IcmpBindingsTypes, IcmpError, IcmpErrorHandler, IcmpHandlerIpExt, Icmpv4Error, Icmpv4State,
79 Icmpv4StateBuilder, Icmpv6Error, Icmpv6State, Icmpv6StateBuilder,
80};
81use crate::internal::ipv6::Ipv6PacketAction;
82use crate::internal::local_delivery::{
83 IpHeaderInfo, Ipv4HeaderInfo, Ipv6HeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta,
84 TransparentLocalDelivery,
85};
86use crate::internal::multicast_forwarding::counters::MulticastForwardingCounters;
87use crate::internal::multicast_forwarding::route::{
88 MulticastRouteIpExt, MulticastRouteTarget, MulticastRouteTargets,
89};
90use crate::internal::multicast_forwarding::state::{
91 MulticastForwardingState, MulticastForwardingStateContext,
92};
93use crate::internal::multicast_forwarding::{
94 MulticastForwardingBindingsTypes, MulticastForwardingDeviceContext, MulticastForwardingEvent,
95 MulticastForwardingTimerId,
96};
97use crate::internal::path_mtu::{PmtuBindingsTypes, PmtuCache, PmtuTimerId};
98use crate::internal::raw::counters::RawIpSocketCounters;
99use crate::internal::raw::{RawIpSocketHandler, RawIpSocketMap, RawIpSocketsBindingsTypes};
100use crate::internal::reassembly::{
101 FragmentBindingsTypes, FragmentHandler, FragmentProcessingState, FragmentTimerId,
102 FragmentablePacket, IpPacketFragmentCache, ReassemblyIpExt,
103};
104use crate::internal::routing::rules::{Rule, RuleAction, RuleInput, RulesTable};
105use crate::internal::routing::{
106 IpRoutingBindingsTypes, IpRoutingDeviceContext, NonLocalSrcAddrPolicy, PacketOrigin,
107 RoutingTable,
108};
109use crate::internal::socket::{IpSocketBindingsContext, IpSocketContext, IpSocketHandler};
110use crate::internal::types::{
111 self, Destination, InternalForwarding, NextHop, ResolvedRoute, RoutableIpAddr,
112};
113use crate::internal::{ipv6, multicast_forwarding};
114
115#[cfg(test)]
116mod tests;
117
118pub const DEFAULT_TTL: NonZeroU8 = NonZeroU8::new(64).unwrap();
120
121#[derive(Copy, Clone, Debug, Eq, PartialEq)]
123#[allow(missing_docs)]
124pub struct HopLimits {
125 pub unicast: NonZeroU8,
126 pub multicast: NonZeroU8,
127}
128
129pub const DEFAULT_HOP_LIMITS: HopLimits =
131 HopLimits { unicast: DEFAULT_TTL, multicast: NonZeroU8::new(1).unwrap() };
132
133pub const IPV6_DEFAULT_SUBNET: Subnet<Ipv6Addr> = Ipv6::ALL_ADDRS_SUBNET;
135
136pub struct IpLayerPacketMetadata<
142 I: packet_formats::ip::IpExt,
143 A,
144 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
145> {
146 conntrack_connection_and_direction:
147 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
148
149 tx_metadata: BT::TxMetadata,
154
155 marks: Marks,
157
158 socket_info: Option<SocketInfo>,
160
161 gso_info: Option<GsoInfo>,
168
169 packet_type: PacketType,
171
172 #[cfg(debug_assertions)]
173 drop_check: IpLayerPacketMetadataDropCheck,
174}
175
176#[cfg(debug_assertions)]
183#[derive(Default)]
184struct IpLayerPacketMetadataDropCheck {
185 okay_to_drop: bool,
186}
187
188#[derive(Derivative)]
191#[derivative(Debug(bound = ""))]
192pub struct DeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
193 conntrack_entry: Option<(WeakConntrackConnection, ConnectionDirection)>,
201 tx_metadata: BT::TxMetadata,
206 marks: Marks,
213 packet_type: PacketType,
217}
218
219pub(crate) struct SplitDeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
222 pub(crate) primary: DeviceIpLayerMetadata<BT>,
223 pub(crate) secondary: DeviceIpLayerMetadata<BT>,
224}
225
226impl<BT: TxMetadataBindingsTypes> DeviceIpLayerMetadata<BT> {
227 pub fn from_tx_metadata_and_marks(tx_metadata: BT::TxMetadata, marks: Marks) -> Self {
229 Self { conntrack_entry: None, tx_metadata, marks, packet_type: PacketType::Outgoing }
230 }
231
232 pub fn new_for_rx_packet(packet_type: PacketType) -> Self {
234 Self {
235 conntrack_entry: None,
236 tx_metadata: Default::default(),
237 marks: Default::default(),
238 packet_type,
239 }
240 }
241
242 #[cfg(any(test, feature = "testutils"))]
244 pub fn empty() -> Self {
245 Self {
246 conntrack_entry: None,
247 tx_metadata: Default::default(),
248 marks: Default::default(),
249 packet_type: PacketType::Host,
250 }
251 }
252
253 pub fn into_tx_metadata(self) -> BT::TxMetadata {
256 self.tx_metadata
257 }
258
259 #[cfg(any(test, feature = "testutils"))]
261 pub fn with_marks_and_packet_type(marks: Marks, packet_type: PacketType) -> Self {
262 Self { conntrack_entry: None, tx_metadata: Default::default(), marks, packet_type }
263 }
264
265 pub(crate) fn split_for_multiple_frames(self) -> SplitDeviceIpLayerMetadata<BT> {
273 let secondary = Self {
274 conntrack_entry: self.conntrack_entry.clone(),
275 tx_metadata: Default::default(),
280 marks: self.marks,
281 packet_type: self.packet_type,
282 };
283 SplitDeviceIpLayerMetadata { primary: self, secondary }
284 }
285
286 pub fn set_packet_type(&mut self, packet_type: PacketType) {
288 self.packet_type = packet_type;
289 }
290
291 pub fn packet_type(&self) -> PacketType {
293 self.packet_type
294 }
295}
296
297impl<
298 I: IpLayerIpExt,
299 A: WeakIpAddressId<I::Addr>,
300 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
301> IpLayerPacketMetadata<I, A, BT>
302{
303 pub(crate) fn from_device_ip_layer_metadata<CC, D>(
304 core_ctx: &mut CC,
305 device: &D,
306 metadata: DeviceIpLayerMetadata<BT>,
307 gso_info: Option<GsoInfo>,
308 ) -> Self
309 where
310 CC: ResourceCounterContext<D, IpCounters<I>>,
311 {
312 let DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks, packet_type } = metadata;
313 let conntrack_connection_and_direction = match conntrack_entry
314 .map(|(conn, dir)| conn.into_inner().map(|conn| (conn, dir)))
315 .transpose()
316 {
317 Ok(conn_and_dir) => conn_and_dir,
320 Err(WeakConnectionError::EntryRemoved) => None,
322 Err(WeakConnectionError::InvalidEntry) => {
326 core_ctx.increment_both(device, |c| &c.invalid_cached_conntrack_entry);
327 None
328 }
329 };
330
331 Self {
332 conntrack_connection_and_direction,
333 tx_metadata,
334 marks,
335 socket_info: None,
339 gso_info,
340 packet_type,
341 #[cfg(debug_assertions)]
342 drop_check: Default::default(),
343 }
344 }
345}
346
347pub(crate) struct SplitMulticastPacketMetadata<I, A, BT>
350where
351 I: packet_formats::ip::IpExt,
352 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
353{
354 pub(crate) primary: IpLayerPacketMetadata<I, A, BT>,
355 pub(crate) secondary: IpLayerPacketMetadata<I, A, BT>,
356}
357
358impl<I: IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
359 IpLayerPacketMetadata<I, A, BT>
360{
361 pub(crate) fn split_for_multicast(self) -> SplitMulticastPacketMetadata<I, A, BT> {
369 let secondary = Self {
370 conntrack_connection_and_direction: None,
371 tx_metadata: Default::default(),
372 marks: self.marks,
373 socket_info: self.socket_info.clone(),
374 gso_info: self.gso_info,
375 packet_type: self.packet_type,
376 #[cfg(debug_assertions)]
377 drop_check: Default::default(),
378 };
379 SplitMulticastPacketMetadata { primary: self, secondary }
380 }
381
382 pub(crate) fn new_local_tx(
383 tx_metadata: BT::TxMetadata,
384 marks: Marks,
385 gso_info: Option<GsoInfo>,
386 ) -> Self {
387 let socket_info = tx_metadata.socket_info();
388 Self {
389 conntrack_connection_and_direction: None,
390 tx_metadata,
391 marks,
392 socket_info,
393 gso_info,
394 packet_type: PacketType::Outgoing,
395 #[cfg(debug_assertions)]
396 drop_check: Default::default(),
397 }
398 }
399
400 #[cfg(any(test, feature = "testutils"))]
402 pub fn new_empty() -> Self {
403 Self::new_local_tx(Default::default(), Default::default(), None)
404 }
405
406 pub(crate) fn into_parts(
407 self,
408 ) -> (
409 Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
410 BT::TxMetadata,
411 Marks,
412 Option<SocketInfo>,
413 Option<GsoInfo>,
414 PacketType,
415 ) {
416 let Self {
417 tx_metadata,
418 marks,
419 conntrack_connection_and_direction,
420 socket_info,
421 gso_info,
422 packet_type,
423 #[cfg(debug_assertions)]
424 mut drop_check,
425 } = self;
426 #[cfg(debug_assertions)]
427 {
428 drop_check.okay_to_drop = true;
429 }
430 (conntrack_connection_and_direction, tx_metadata, marks, socket_info, gso_info, packet_type)
431 }
432
433 pub(crate) fn acknowledge_drop(self) {
438 #[cfg(debug_assertions)]
439 {
440 let mut this = self;
441 this.drop_check.okay_to_drop = true;
442 }
443 }
444
445 pub(crate) fn tx_metadata(&self) -> &BT::TxMetadata {
447 &self.tx_metadata
448 }
449
450 pub(crate) fn marks(&self) -> &Marks {
452 &self.marks
453 }
454
455 pub(crate) fn gso_info(&self) -> Option<GsoInfo> {
457 self.gso_info
458 }
459
460 pub fn set_packet_type(&mut self, packet_type: PacketType) {
462 self.packet_type = packet_type;
463 }
464}
465
466#[cfg(debug_assertions)]
467impl Drop for IpLayerPacketMetadataDropCheck {
468 fn drop(&mut self) {
469 if !self.okay_to_drop {
470 panic!(
471 "IpLayerPacketMetadata dropped without acknowledgement. https://fxbug.dev/334127474"
472 );
473 }
474 }
475}
476
477impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
478 FilterIpMetadata<I, A, BT> for IpLayerPacketMetadata<I, A, BT>
479{
480 fn take_connection_and_direction(
481 &mut self,
482 ) -> Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)> {
483 self.conntrack_connection_and_direction.take()
484 }
485
486 fn replace_connection_and_direction(
487 &mut self,
488 conn: ConntrackConnection<I, A, BT>,
489 direction: ConnectionDirection,
490 ) -> Option<ConntrackConnection<I, A, BT>> {
491 self.conntrack_connection_and_direction.replace((conn, direction)).map(|(conn, _dir)| conn)
492 }
493}
494
495impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
496 FilterPacketMetadata for IpLayerPacketMetadata<I, A, BT>
497{
498 fn apply_mark_action(&mut self, domain: MarkDomain, action: MarkAction) {
499 action.apply(self.marks.get_mut(domain))
500 }
501
502 fn socket_info(&self) -> Option<SocketInfo> {
503 self.socket_info.clone()
504 }
505
506 fn marks(&self) -> &Marks {
507 &self.marks
508 }
509
510 fn packet_type(&self) -> PacketType {
511 self.packet_type
512 }
513
514 fn gso_info(&self) -> Option<GsoInfo> {
515 self.gso_info
516 }
517}
518
519pub type IpSendFrameError<S> = ErrorAndSerializer<IpSendFrameErrorReason, S>;
521
522#[derive(Debug, PartialEq)]
524pub enum IpSendFrameErrorReason {
525 Device(SendFrameErrorReason),
527 IllegalLoopbackAddress,
530}
531
532impl From<SendFrameErrorReason> for IpSendFrameErrorReason {
533 fn from(value: SendFrameErrorReason) -> Self {
534 Self::Device(value)
535 }
536}
537
538pub trait IpTransportContext<I, BC, CC>
544where
545 I: IpLayerIpExt,
546 CC: DeviceIdContext<AnyDevice> + ?Sized,
547{
548 type EarlyDemuxSocket;
550
551 fn early_demux<B: ParseBuffer>(
562 core_ctx: &mut CC,
563 device: &CC::DeviceId,
564 src_ip: I::Addr,
565 dst_ip: I::Addr,
566 buffer: B,
567 ) -> Option<Self::EarlyDemuxSocket>;
568
569 fn receive_icmp_error(
583 core_ctx: &mut CC,
584 bindings_ctx: &mut BC,
585 device: &CC::DeviceId,
586 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
587 original_dst_ip: SpecifiedAddr<I::Addr>,
588 original_body: &[u8],
589 err: I::ErrorCode,
590 );
591
592 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
598 core_ctx: &mut CC,
599 bindings_ctx: &mut BC,
600 device: &CC::DeviceId,
601 src_ip: I::RecvSrcAddr,
602 dst_ip: SpecifiedAddr<I::Addr>,
603 buffer: B,
604 info: &mut LocalDeliveryPacketInfo<I, H>,
605 early_demux_socket: Option<Self::EarlyDemuxSocket>,
606 ) -> Result<(), (B, I::IcmpError)>;
607}
608
609pub trait BaseTransportIpContext<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
612 type DevicesWithAddrIter<'s>: Iterator<Item = Self::DeviceId>;
615
616 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
622 &mut self,
623 addr: SpecifiedAddr<I::Addr>,
624 cb: F,
625 ) -> O;
626
627 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits;
632
633 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)>;
637}
638
639pub trait TransportIpContext<I: IpExt + FilterIpExt, BC: TxMetadataBindingsTypes>:
642 BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>
643{
644}
645
646impl<I, CC, BC> TransportIpContext<I, BC> for CC
647where
648 I: IpExt + FilterIpExt,
649 CC: BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>,
650 BC: TxMetadataBindingsTypes,
651{
652}
653
654pub trait MulticastMembershipHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
656 fn join_multicast_group(
663 &mut self,
664 bindings_ctx: &mut BC,
665 device: &Self::DeviceId,
666 addr: MulticastAddr<I::Addr>,
667 );
668
669 fn leave_multicast_group(
677 &mut self,
678 bindings_ctx: &mut BC,
679 device: &Self::DeviceId,
680 addr: MulticastAddr<I::Addr>,
681 );
682
683 fn select_device_for_multicast_group(
688 &mut self,
689 addr: MulticastAddr<I::Addr>,
690 marks: &Marks,
691 ) -> Result<Self::DeviceId, ResolveRouteError>;
692}
693
694pub trait UseTransportIpContextBlanket {}
706
707pub struct AssignedAddressDeviceIterator<Iter, I, D>(Iter, PhantomData<(I, D)>);
710
711impl<Iter, I, D> Iterator for AssignedAddressDeviceIterator<Iter, I, D>
712where
713 Iter: Iterator<Item = (D, I::AddressStatus)>,
714 I: IpLayerIpExt,
715{
716 type Item = D;
717 fn next(&mut self) -> Option<D> {
718 let Self(iter, PhantomData) = self;
719 iter.by_ref().find_map(|(device, state)| is_unicast_assigned::<I>(&state).then_some(device))
720 }
721}
722
723impl<
724 I: IpLayerIpExt,
725 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + IpRoutingBindingsTypes,
726 CC: IpDeviceContext<I>
727 + IpSocketHandler<I, BC>
728 + IpStateContext<I, BC>
729 + FilterIpContext<I, BC>
730 + UseTransportIpContextBlanket,
731> BaseTransportIpContext<I, BC> for CC
732{
733 type DevicesWithAddrIter<'s> =
734 AssignedAddressDeviceIterator<CC::DeviceAndAddressStatusIter<'s>, I, CC::DeviceId>;
735
736 fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
737 &mut self,
738 addr: SpecifiedAddr<I::Addr>,
739 cb: F,
740 ) -> O {
741 self.with_address_statuses(addr, |it| cb(AssignedAddressDeviceIterator(it, PhantomData)))
742 }
743
744 fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
745 match device {
746 Some(device) => HopLimits {
747 unicast: IpDeviceEgressStateContext::<I>::get_hop_limit(self, device),
748 ..DEFAULT_HOP_LIMITS
749 },
750 None => DEFAULT_HOP_LIMITS,
751 }
752 }
753
754 fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)> {
755 self.with_filter_state(|state| {
756 let conn = state.conntrack.get_connection(&tuple)?;
757
758 if !conn.destination_nat() {
759 return None;
760 }
761
762 let original = conn.original_tuple();
766 Some((original.dst_addr, original.transport.dst_port_or_id()))
767 })
768 }
769}
770
771#[derive(Debug, PartialEq)]
773#[allow(missing_docs)]
774pub enum AddressStatus<S> {
775 Present(S),
776 Unassigned,
777}
778
779impl<S> AddressStatus<S> {
780 fn into_present(self) -> Option<S> {
781 match self {
782 Self::Present(s) => Some(s),
783 Self::Unassigned => None,
784 }
785 }
786}
787
788impl AddressStatus<Ipv4PresentAddressStatus> {
789 pub fn from_context_addr_v4<
791 BC: IpDeviceStateBindingsTypes,
792 CC: device::IpDeviceStateContext<Ipv4, BC> + GmpQueryHandler<Ipv4, BC>,
793 >(
794 core_ctx: &mut CC,
795 device: &CC::DeviceId,
796 addr: SpecifiedAddr<Ipv4Addr>,
797 ) -> AddressStatus<Ipv4PresentAddressStatus> {
798 if addr.is_limited_broadcast() {
799 return AddressStatus::Present(Ipv4PresentAddressStatus::LimitedBroadcast);
800 }
801
802 if MulticastAddr::new(addr.get())
803 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
804 {
805 return AddressStatus::Present(Ipv4PresentAddressStatus::Multicast);
806 }
807
808 core_ctx.with_address_ids(device, |mut addrs, core_ctx| {
809 addrs
810 .find_map(|addr_id| {
811 let dev_addr = addr_id.addr_sub();
812 let (dev_addr, subnet) = dev_addr.addr_subnet();
813
814 if **dev_addr == addr {
815 let assigned = core_ctx.with_ip_address_data(
816 device,
817 &addr_id,
818 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| {
819 *assigned
820 },
821 );
822
823 if assigned {
824 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastAssigned))
825 } else {
826 Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastTentative))
827 }
828 } else if addr.get() == subnet.broadcast() {
829 Some(AddressStatus::Present(Ipv4PresentAddressStatus::SubnetBroadcast))
830 } else if device.is_loopback() && subnet.contains(addr.as_ref()) {
831 Some(AddressStatus::Present(Ipv4PresentAddressStatus::LoopbackSubnet))
832 } else {
833 None
834 }
835 })
836 .unwrap_or(AddressStatus::Unassigned)
837 })
838 }
839}
840
841impl AddressStatus<Ipv6PresentAddressStatus> {
842 pub fn from_context_addr_v6<
844 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
845 CC: device::Ipv6DeviceContext<BC> + GmpQueryHandler<Ipv6, BC>,
846 >(
847 core_ctx: &mut CC,
848 device: &CC::DeviceId,
849 addr: SpecifiedAddr<Ipv6Addr>,
850 ) -> AddressStatus<Ipv6PresentAddressStatus> {
851 if MulticastAddr::new(addr.get())
852 .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
853 {
854 return AddressStatus::Present(Ipv6PresentAddressStatus::Multicast);
855 }
856
857 let addr_id = match core_ctx.get_address_id(device, addr) {
858 Ok(o) => o,
859 Err(NotFoundError) => return AddressStatus::Unassigned,
860 };
861
862 let assigned = core_ctx.with_ip_address_data(
863 device,
864 &addr_id,
865 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
866 );
867
868 if assigned {
869 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned)
870 } else {
871 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastTentative)
872 }
873 }
874}
875
876impl<S: GenericOverIp<I>, I: Ip> GenericOverIp<I> for AddressStatus<S> {
877 type Type = AddressStatus<S::Type>;
878}
879
880#[derive(Debug, PartialEq)]
882#[allow(missing_docs)]
883pub enum Ipv4PresentAddressStatus {
884 LimitedBroadcast,
885 SubnetBroadcast,
886 Multicast,
887 UnicastAssigned,
888 UnicastTentative,
889 LoopbackSubnet,
900}
901
902impl Ipv4PresentAddressStatus {
903 fn to_broadcast_marker(&self) -> Option<<Ipv4 as BroadcastIpExt>::BroadcastMarker> {
904 match self {
905 Self::LimitedBroadcast | Self::SubnetBroadcast => Some(()),
906 Self::Multicast
907 | Self::UnicastAssigned
908 | Self::UnicastTentative
909 | Self::LoopbackSubnet => None,
910 }
911 }
912}
913
914#[derive(Debug, PartialEq)]
916#[allow(missing_docs)]
917pub enum Ipv6PresentAddressStatus {
918 Multicast,
919 UnicastAssigned,
920 UnicastTentative,
921}
922
923pub trait IpLayerIpExt:
925 IpExt
926 + MulticastRouteIpExt
927 + IcmpHandlerIpExt
928 + FilterIpExt
929 + FragmentationIpExt
930 + GsoIpExt
931 + IpDeviceIpExt
932 + IpCountersIpExt
933 + IcmpCountersIpExt
934 + ReassemblyIpExt
935{
936 type AddressStatus: Debug;
938 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>: AsRef<
940 IpStateInner<Self, StrongDeviceId, BT>,
941 >;
942 type PacketIdState;
944 type PacketId;
946 fn next_packet_id_from_state(state: &Self::PacketIdState) -> Self::PacketId;
948}
949
950impl IpLayerIpExt for Ipv4 {
951 type AddressStatus = Ipv4PresentAddressStatus;
952 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
953 Ipv4State<StrongDeviceId, BT>;
954 type PacketIdState = AtomicU16;
955 type PacketId = u16;
956 fn next_packet_id_from_state(next_packet_id: &Self::PacketIdState) -> Self::PacketId {
957 next_packet_id.fetch_add(1, atomic::Ordering::Relaxed)
961 }
962}
963
964impl IpLayerIpExt for Ipv6 {
965 type AddressStatus = Ipv6PresentAddressStatus;
966 type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
967 Ipv6State<StrongDeviceId, BT>;
968 type PacketIdState = ();
969 type PacketId = ();
970 fn next_packet_id_from_state((): &Self::PacketIdState) -> Self::PacketId {
971 ()
972 }
973}
974
975pub trait IpStateContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes + MatcherBindingsTypes>:
977 IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>
978{
979 type IpRouteTablesCtx<'a>: IpRouteTablesContext<I, BT, DeviceId = Self::DeviceId>;
981
982 fn with_rules_table<
984 O,
985 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId, BT>) -> O,
986 >(
987 &mut self,
988 cb: F,
989 ) -> O;
990
991 fn with_rules_table_mut<
993 O,
994 F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId, BT>) -> O,
995 >(
996 &mut self,
997 cb: F,
998 ) -> O;
999}
1000
1001pub trait IpRouteTablesContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
1003 IpRouteTableContext<I, BT> + IpDeviceContext<I>
1004{
1005 type Ctx<'a>: IpRouteTableContext<I, BT, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>;
1007
1008 fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId, BT>;
1010
1011 fn with_ip_routing_tables<
1013 O,
1014 F: FnOnce(
1015 &mut Self::Ctx<'_>,
1016 &HashMap<
1017 RoutingTableId<I, Self::DeviceId, BT>,
1018 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
1019 >,
1020 ) -> O,
1021 >(
1022 &mut self,
1023 cb: F,
1024 ) -> O;
1025
1026 fn with_ip_routing_tables_mut<
1028 O,
1029 F: FnOnce(
1030 &mut HashMap<
1031 RoutingTableId<I, Self::DeviceId, BT>,
1032 PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
1033 >,
1034 ) -> O,
1035 >(
1036 &mut self,
1037 cb: F,
1038 ) -> O;
1039
1040 fn with_main_ip_routing_table<
1044 O,
1045 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
1046 >(
1047 &mut self,
1048 cb: F,
1049 ) -> O {
1050 let main_table_id = self.main_table_id();
1051 self.with_ip_routing_table(&main_table_id, cb)
1052 }
1053
1054 fn with_main_ip_routing_table_mut<
1058 O,
1059 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
1060 >(
1061 &mut self,
1062 cb: F,
1063 ) -> O {
1064 let main_table_id = self.main_table_id();
1065 self.with_ip_routing_table_mut(&main_table_id, cb)
1066 }
1067}
1068
1069pub trait IpRouteTableContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
1071 IpDeviceContext<I>
1072{
1073 type IpDeviceIdCtx<'a>: DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
1075 + IpRoutingDeviceContext<I>
1076 + IpDeviceContext<I>;
1077
1078 fn with_ip_routing_table<
1080 O,
1081 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
1082 >(
1083 &mut self,
1084 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
1085 cb: F,
1086 ) -> O;
1087
1088 fn with_ip_routing_table_mut<
1090 O,
1091 F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
1092 >(
1093 &mut self,
1094 table_id: &RoutingTableId<I, Self::DeviceId, BT>,
1095 cb: F,
1096 ) -> O;
1097}
1098
1099pub trait IpDeviceEgressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
1101 fn with_next_packet_id<O, F: FnOnce(&I::PacketIdState) -> O>(&self, cb: F) -> O;
1103
1104 fn get_local_addr_for_remote(
1106 &mut self,
1107 device_id: &Self::DeviceId,
1108 remote: Option<SpecifiedAddr<I::Addr>>,
1109 ) -> Option<IpDeviceAddr<I::Addr>>;
1110
1111 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8;
1113}
1114
1115pub trait IpDeviceIngressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
1117 fn address_status_for_device(
1123 &mut self,
1124 addr: SpecifiedAddr<I::Addr>,
1125 device_id: &Self::DeviceId,
1126 ) -> AddressStatus<I::AddressStatus>;
1127}
1128
1129pub trait IpDeviceContext<I: IpLayerIpExt>:
1131 IpDeviceEgressStateContext<I> + IpDeviceIngressStateContext<I>
1132{
1133 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
1135
1136 type DeviceAndAddressStatusIter<'a>: Iterator<Item = (Self::DeviceId, I::AddressStatus)>;
1138
1139 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
1145 &mut self,
1146 addr: SpecifiedAddr<I::Addr>,
1147 cb: F,
1148 ) -> R;
1149
1150 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
1152}
1153
1154pub trait IpDeviceConfirmReachableContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1156 fn confirm_reachable(
1159 &mut self,
1160 bindings_ctx: &mut BC,
1161 device: &Self::DeviceId,
1162 neighbor: SpecifiedAddr<I::Addr>,
1163 );
1164}
1165
1166pub trait IpDeviceMtuContext<I: Ip>: DeviceIdContext<AnyDevice> {
1168 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu;
1172}
1173
1174#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
1176#[generic_over_ip(I, Ip)]
1177pub enum IpLayerEvent<DeviceId, I: IpLayerIpExt> {
1178 AddRoute(types::AddableEntry<I::Addr, DeviceId>),
1180 RemoveRoutes {
1182 subnet: Subnet<I::Addr>,
1184 device: DeviceId,
1186 gateway: Option<SpecifiedAddr<I::Addr>>,
1188 },
1189 MulticastForwarding(MulticastForwardingEvent<I, DeviceId>),
1191}
1192
1193impl<DeviceId, I: IpLayerIpExt> From<MulticastForwardingEvent<I, DeviceId>>
1194 for IpLayerEvent<DeviceId, I>
1195{
1196 fn from(event: MulticastForwardingEvent<I, DeviceId>) -> IpLayerEvent<DeviceId, I> {
1197 IpLayerEvent::MulticastForwarding(event)
1198 }
1199}
1200
1201impl<DeviceId, I: IpLayerIpExt> IpLayerEvent<DeviceId, I> {
1202 pub fn map_device<N, F: Fn(DeviceId) -> N>(self, map: F) -> IpLayerEvent<N, I> {
1204 match self {
1205 IpLayerEvent::AddRoute(types::AddableEntry {
1206 subnet,
1207 device,
1208 gateway,
1209 metric,
1210 route_preference,
1211 }) => IpLayerEvent::AddRoute(types::AddableEntry {
1212 subnet,
1213 device: map(device),
1214 gateway,
1215 metric,
1216 route_preference,
1217 }),
1218 IpLayerEvent::RemoveRoutes { subnet, device, gateway } => {
1219 IpLayerEvent::RemoveRoutes { subnet, device: map(device), gateway }
1220 }
1221 IpLayerEvent::MulticastForwarding(e) => {
1222 IpLayerEvent::MulticastForwarding(e.map_device(map))
1223 }
1224 }
1225 }
1226}
1227
1228#[derive(Derivative, PartialEq, Eq, Clone, Hash)]
1230#[derivative(Debug)]
1231pub struct RouterAdvertisementEvent<D> {
1232 #[derivative(Debug = "ignore")]
1235 pub options_bytes: Box<[u8]>,
1236 pub source: net_types::ip::Ipv6Addr,
1238 pub device: D,
1240}
1241
1242impl<D> RouterAdvertisementEvent<D> {
1243 pub fn map_device<N, F: Fn(D) -> N>(self, map: F) -> RouterAdvertisementEvent<N> {
1245 let Self { options_bytes, source, device } = self;
1246 RouterAdvertisementEvent { options_bytes, source, device: map(device) }
1247 }
1248}
1249
1250pub trait NdpBindingsContext<DeviceId>: EventContext<RouterAdvertisementEvent<DeviceId>> {}
1252impl<DeviceId, BC: EventContext<RouterAdvertisementEvent<DeviceId>>> NdpBindingsContext<DeviceId>
1253 for BC
1254{
1255}
1256
1257pub trait MarksBindingsContext {
1259 fn marks_to_keep_on_egress() -> &'static [MarkDomain];
1264
1265 fn marks_to_set_on_ingress() -> &'static [MarkDomain];
1270
1271 fn update_ingress_marks(mut packet_marks: Marks, socket_marks: &Marks) -> Marks {
1274 for mark in Self::marks_to_set_on_ingress() {
1275 *packet_marks.get_mut(*mark) = *socket_marks.get(*mark);
1276 }
1277 packet_marks
1278 }
1279}
1280
1281pub trait IpLayerBindingsContext<I: IpLayerIpExt, DeviceId>:
1283 InstantContext
1284 + EventContext<IpLayerEvent<DeviceId, I>>
1285 + FilterBindingsContext<DeviceId>
1286 + TxMetadataBindingsTypes
1287 + IpRoutingBindingsTypes
1288 + MarksBindingsContext
1289{
1290}
1291impl<
1292 I: IpLayerIpExt,
1293 DeviceId,
1294 BC: InstantContext
1295 + EventContext<IpLayerEvent<DeviceId, I>>
1296 + FilterBindingsContext<DeviceId>
1297 + TxMetadataBindingsTypes
1298 + IpRoutingBindingsTypes
1299 + MarksBindingsContext,
1300> IpLayerBindingsContext<I, DeviceId> for BC
1301{
1302}
1303
1304pub trait IpLayerBindingsTypes:
1306 IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes
1307{
1308}
1309impl<BT: IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes> IpLayerBindingsTypes
1310 for BT
1311{
1312}
1313
1314pub trait IpLayerContext<
1316 I: IpLayerIpExt,
1317 BC: IpLayerBindingsContext<I, <Self as DeviceIdContext<AnyDevice>>::DeviceId>,
1318>:
1319 IpStateContext<I, BC>
1320 + IpDeviceContext<I>
1321 + IpDeviceMtuContext<I>
1322 + IpDeviceSendContext<I, BC>
1323 + IcmpErrorHandler<I, BC>
1324 + MulticastForwardingStateContext<I, BC>
1325 + MulticastForwardingDeviceContext<I>
1326 + CounterContext<MulticastForwardingCounters<I>>
1327 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>
1328{
1329}
1330
1331impl<
1332 I: IpLayerIpExt,
1333 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
1334 CC: IpStateContext<I, BC>
1335 + IpDeviceContext<I>
1336 + IpDeviceMtuContext<I>
1337 + IpDeviceSendContext<I, BC>
1338 + IcmpErrorHandler<I, BC>
1339 + MulticastForwardingStateContext<I, BC>
1340 + MulticastForwardingDeviceContext<I>
1341 + CounterContext<MulticastForwardingCounters<I>>
1342 + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>,
1343> IpLayerContext<I, BC> for CC
1344{
1345}
1346
1347fn is_unicast_assigned<I: IpLayerIpExt>(status: &I::AddressStatus) -> bool {
1348 #[derive(GenericOverIp)]
1349 #[generic_over_ip(I, Ip)]
1350 struct WrapAddressStatus<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
1351
1352 I::map_ip(
1353 WrapAddressStatus(status),
1354 |WrapAddressStatus(status)| match status {
1355 Ipv4PresentAddressStatus::UnicastAssigned
1356 | Ipv4PresentAddressStatus::LoopbackSubnet => true,
1357 Ipv4PresentAddressStatus::UnicastTentative
1358 | Ipv4PresentAddressStatus::LimitedBroadcast
1359 | Ipv4PresentAddressStatus::SubnetBroadcast
1360 | Ipv4PresentAddressStatus::Multicast => false,
1361 },
1362 |WrapAddressStatus(status)| match status {
1363 Ipv6PresentAddressStatus::UnicastAssigned => true,
1364 Ipv6PresentAddressStatus::Multicast | Ipv6PresentAddressStatus::UnicastTentative => {
1365 false
1366 }
1367 },
1368 )
1369}
1370
1371fn is_local_assigned_address<I: Ip + IpLayerIpExt, CC: IpDeviceIngressStateContext<I>>(
1372 core_ctx: &mut CC,
1373 device: &CC::DeviceId,
1374 addr: IpDeviceAddr<I::Addr>,
1375) -> bool {
1376 match core_ctx.address_status_for_device(addr.into(), device) {
1377 AddressStatus::Present(status) => is_unicast_assigned::<I>(&status),
1378 AddressStatus::Unassigned => false,
1379 }
1380}
1381
1382fn get_device_with_assigned_address<I, CC>(
1383 core_ctx: &mut CC,
1384 addr: IpDeviceAddr<I::Addr>,
1385) -> Option<(CC::DeviceId, I::AddressStatus)>
1386where
1387 I: IpLayerIpExt,
1388 CC: IpDeviceContext<I>,
1389{
1390 core_ctx.with_address_statuses(addr.into(), |mut it| {
1391 it.find_map(|(device, status)| {
1392 is_unicast_assigned::<I>(&status).then_some((device, status))
1393 })
1394 })
1395}
1396
1397fn get_local_addr<I: Ip + IpLayerIpExt, CC: IpDeviceContext<I>>(
1401 core_ctx: &mut CC,
1402 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1403 device: &CC::DeviceId,
1404 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1405) -> Result<IpDeviceAddr<I::Addr>, ResolveRouteError> {
1406 match local_ip_and_policy {
1407 Some((local_ip, NonLocalSrcAddrPolicy::Allow)) => Ok(local_ip),
1408 Some((local_ip, NonLocalSrcAddrPolicy::Deny)) => {
1409 is_local_assigned_address(core_ctx, device, local_ip)
1410 .then_some(local_ip)
1411 .ok_or(ResolveRouteError::NoSrcAddr)
1412 }
1413 None => core_ctx
1414 .get_local_addr_for_remote(device, remote_addr.map(Into::into))
1415 .ok_or(ResolveRouteError::NoSrcAddr),
1416 }
1417}
1418
1419#[derive(Error, Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
1421#[generic_over_ip()]
1422pub enum ResolveRouteError {
1423 #[error("a source address could not be selected")]
1425 NoSrcAddr,
1426 #[error("no route exists to the destination IP address")]
1428 Unreachable,
1429}
1430
1431fn get_local_addr_with_internal_forwarding<I, CC>(
1433 core_ctx: &mut CC,
1434 local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1435 device: &CC::DeviceId,
1436 remote_addr: Option<RoutableIpAddr<I::Addr>>,
1437) -> Result<(IpDeviceAddr<I::Addr>, InternalForwarding<CC::DeviceId>), ResolveRouteError>
1438where
1439 I: IpLayerIpExt,
1440 CC: IpDeviceContext<I>,
1441{
1442 match get_local_addr(core_ctx, local_ip_and_policy, device, remote_addr) {
1443 Ok(src_addr) => Ok((src_addr, InternalForwarding::NotUsed)),
1444 Err(e) => {
1445 if let Some((local_ip, _policy)) = local_ip_and_policy {
1453 if let Some((device, _addr_status)) =
1454 get_device_with_assigned_address(core_ctx, local_ip)
1455 {
1456 if core_ctx.is_device_unicast_forwarding_enabled(&device) {
1457 return Ok((local_ip, InternalForwarding::Used(device)));
1458 }
1459 }
1460 }
1461 Err(e)
1462 }
1463 }
1464}
1465
1466#[derive(Debug, PartialEq, Eq)]
1469struct RuleWalkInfo<O> {
1470 observed_source_address_matcher: bool,
1472 inner: O,
1475}
1476
1477fn walk_rules<
1491 I: IpLayerIpExt,
1492 BT: IpRoutingBindingsTypes + MatcherBindingsTypes,
1493 CC: IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>,
1494 O,
1495 State,
1496 F: FnMut(
1497 State,
1498 &mut CC::IpDeviceIdCtx<'_>,
1499 &RoutingTable<I, CC::DeviceId>,
1500 ) -> ControlFlow<O, State>,
1501>(
1502 core_ctx: &mut CC,
1503 rules: &RulesTable<I, CC::DeviceId, BT>,
1504 init: State,
1505 rule_input: &RuleInput<'_, I, CC::DeviceId>,
1506 mut lookup_table: F,
1507) -> ControlFlow<RuleAction<RuleWalkInfo<O>>, RuleWalkInfo<State>> {
1508 rules.iter().try_fold(
1509 RuleWalkInfo { inner: init, observed_source_address_matcher: false },
1510 |RuleWalkInfo { inner: state, observed_source_address_matcher },
1511 Rule { action, matcher }| {
1512 let observed_source_address_matcher =
1513 observed_source_address_matcher || matcher.source_address_matcher.is_some();
1514 if !matcher.matches(rule_input) {
1515 return ControlFlow::Continue(RuleWalkInfo {
1516 inner: state,
1517 observed_source_address_matcher,
1518 });
1519 }
1520 match action {
1521 RuleAction::Unreachable => return ControlFlow::Break(RuleAction::Unreachable),
1522 RuleAction::Lookup(table_id) => core_ctx.with_ip_routing_table(
1523 &table_id,
1524 |core_ctx, table| match lookup_table(state, core_ctx, table) {
1525 ControlFlow::Break(out) => {
1526 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1527 inner: out,
1528 observed_source_address_matcher,
1529 }))
1530 }
1531 ControlFlow::Continue(state) => ControlFlow::Continue(RuleWalkInfo {
1532 inner: state,
1533 observed_source_address_matcher,
1534 }),
1535 },
1536 ),
1537 }
1538 },
1539 )
1540}
1541
1542pub fn resolve_output_route_to_destination<
1553 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1554 BC: IpDeviceBindingsContext<I, CC::DeviceId> + IpLayerBindingsContext<I, CC::DeviceId>,
1555 CC: IpStateContext<I, BC> + IpDeviceContext<I> + device::IpDeviceConfigurationContext<I, BC>,
1556>(
1557 core_ctx: &mut CC,
1558 device: Option<&CC::DeviceId>,
1559 src_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1560 dst_ip: Option<RoutableIpAddr<I::Addr>>,
1561 marks: &Marks,
1562) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1563 enum LocalDelivery<A, D> {
1564 WeakLoopback { dst_ip: A, device: D },
1565 StrongForDevice(D),
1566 }
1567
1568 let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1585 let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1586 match (device, dst_ip) {
1587 (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1588 .then_some(LocalDelivery::StrongForDevice(device.clone())),
1589 (None, Some(dst_ip)) => {
1590 get_device_with_assigned_address(core_ctx, dst_ip).map(
1591 |(dst_device, _addr_status)| {
1592 if src_ip_and_policy
1597 .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1598 || dst_ip.as_ref().must_have_zone()
1599 {
1600 LocalDelivery::StrongForDevice(dst_device)
1601 } else {
1602 LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1603 }
1604 },
1605 )
1606 }
1607 (_, None) => None,
1608 }
1609 };
1610
1611 if let Some(local_delivery) = local_delivery_instructions {
1612 let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1613
1614 let (src_addr, dest_device) = match local_delivery {
1615 LocalDelivery::WeakLoopback { dst_ip, device } => {
1616 let src_ip = match src_ip_and_policy {
1617 Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1618 let _device = get_device_with_assigned_address(core_ctx, src_ip)
1619 .ok_or(ResolveRouteError::NoSrcAddr)?;
1620 src_ip
1621 }
1622 Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1623 None => dst_ip,
1624 };
1625 (src_ip, device)
1626 }
1627 LocalDelivery::StrongForDevice(device) => {
1628 (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1629 }
1630 };
1631 return Ok(ResolvedRoute {
1632 src_addr,
1633 local_delivery_device: Some(dest_device),
1634 device: loopback,
1635 next_hop: NextHop::RemoteAsNeighbor,
1636 internal_forwarding: InternalForwarding::NotUsed,
1637 });
1638 }
1639 let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1640 let rule_input = RuleInput {
1641 packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1642 marks,
1643 };
1644 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
1645 let mut walk_rules = |rule_input, src_ip_and_policy| {
1646 walk_rules(
1647 core_ctx,
1648 rules,
1649 None, rule_input,
1651 |first_error, core_ctx, table| {
1652 let mut matching_with_addr = table.lookup_filter_map(
1653 core_ctx,
1654 device,
1655 dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1656 |core_ctx, d| {
1657 Some(get_local_addr_with_internal_forwarding(
1658 core_ctx,
1659 src_ip_and_policy,
1660 d,
1661 dst_ip,
1662 ))
1663 },
1664 );
1665
1666 let first_error_in_this_table = match matching_with_addr.next() {
1667 Some((
1668 Destination { device, next_hop },
1669 Ok((local_addr, internal_forwarding)),
1670 )) => {
1671 return ControlFlow::Break(Ok((
1672 Destination { device: device.clone(), next_hop },
1673 local_addr,
1674 internal_forwarding,
1675 )));
1676 }
1677 Some((_, Err(e))) => e,
1678 None => return ControlFlow::Continue(first_error),
1682 };
1683
1684 matching_with_addr
1685 .filter_map(|(destination, local_addr)| {
1686 local_addr.ok_checked::<ResolveRouteError>().map(
1689 |(local_addr, internal_forwarding)| {
1690 (destination, local_addr, internal_forwarding)
1691 },
1692 )
1693 })
1694 .next()
1695 .map_or(
1696 ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1697 |(
1698 Destination { device, next_hop },
1699 local_addr,
1700 internal_forwarding,
1701 )| {
1702 ControlFlow::Break(Ok((
1703 Destination { device: device.clone(), next_hop },
1704 local_addr,
1705 internal_forwarding,
1706 )))
1707 },
1708 )
1709 },
1710 )
1711 };
1712
1713 let result = match walk_rules(&rule_input, src_ip_and_policy) {
1714 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1721 inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1722 observed_source_address_matcher: true,
1723 })) if src_ip_and_policy.is_none() => walk_rules(
1724 &RuleInput {
1725 packet_origin: PacketOrigin::Local {
1726 bound_address: Some(selected_src_addr.into()),
1727 bound_device: device,
1728 },
1729 marks,
1730 },
1731 Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1732 ),
1733 result => result,
1734 };
1735
1736 match result {
1737 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1738 inner: result,
1739 observed_source_address_matcher: _,
1740 })) => {
1741 result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1742 ResolvedRoute {
1743 src_addr,
1744 device,
1745 local_delivery_device: None,
1746 next_hop,
1747 internal_forwarding,
1748 }
1749 })
1750 }
1751 ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1752 ControlFlow::Continue(RuleWalkInfo {
1753 inner: first_error,
1754 observed_source_address_matcher: _,
1755 }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1756 }
1757 })
1758}
1759
1760pub trait UseIpSocketContextBlanket {}
1765
1766impl<I, BC, CC> IpSocketContext<I, BC> for CC
1767where
1768 I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1769 BC: IpDeviceBindingsContext<I, CC::DeviceId>
1770 + IpLayerBindingsContext<I, CC::DeviceId>
1771 + IpSocketBindingsContext<CC::DeviceId>,
1772 CC: IpLayerEgressContext<I, BC>
1773 + IpStateContext<I, BC>
1774 + IpDeviceContext<I>
1775 + IpDeviceConfirmReachableContext<I, BC>
1776 + IpDeviceMtuContext<I>
1777 + device::IpDeviceConfigurationContext<I, BC>
1778 + IcmpErrorHandler<I, BC>
1779 + UseIpSocketContextBlanket,
1780{
1781 fn lookup_route(
1782 &mut self,
1783 _bindings_ctx: &mut BC,
1784 device: Option<&CC::DeviceId>,
1785 local_ip: Option<IpDeviceAddr<I::Addr>>,
1786 addr: RoutableIpAddr<I::Addr>,
1787 transparent: bool,
1788 marks: &Marks,
1789 ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1790 let src_ip_and_policy = local_ip.map(|local_ip| {
1791 (
1792 local_ip,
1793 if transparent {
1794 NonLocalSrcAddrPolicy::Allow
1795 } else {
1796 NonLocalSrcAddrPolicy::Deny
1797 },
1798 )
1799 });
1800 let res =
1801 resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1802 trace!(
1803 "lookup_route(\
1804 device={device:?}, \
1805 local_ip={local_ip:?}, \
1806 addr={addr:?}, \
1807 transparent={transparent:?}, \
1808 marks={marks:?}) => {res:?}"
1809 );
1810 res
1811 }
1812
1813 fn send_ip_packet<S>(
1814 &mut self,
1815 bindings_ctx: &mut BC,
1816 meta: SendIpPacketMeta<
1817 I,
1818 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1819 SpecifiedAddr<I::Addr>,
1820 >,
1821 body: S,
1822 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1823 ) -> Result<(), IpSendFrameError<S>>
1824 where
1825 S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
1826 S::Buffer: BufferMut,
1827 {
1828 send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1829 }
1830
1831 fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1832 device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1833 }
1834
1835 fn confirm_reachable(
1836 &mut self,
1837 bindings_ctx: &mut BC,
1838 dst: SpecifiedAddr<I::Addr>,
1839 input: RuleInput<'_, I, Self::DeviceId>,
1840 ) {
1841 match lookup_route_table(self, dst.get(), input) {
1842 Some(Destination { next_hop, device }) => {
1843 let neighbor = match next_hop {
1844 NextHop::RemoteAsNeighbor => dst,
1845 NextHop::Gateway(gateway) => gateway,
1846 NextHop::Broadcast(marker) => {
1847 I::map_ip::<_, ()>(
1848 WrapBroadcastMarker(marker),
1849 |WrapBroadcastMarker(())| {
1850 debug!(
1851 "can't confirm {dst:?}@{device:?} as reachable: \
1852 dst is a broadcast address"
1853 );
1854 },
1855 |WrapBroadcastMarker(never)| match never {},
1856 );
1857 return;
1858 }
1859 };
1860 IpDeviceConfirmReachableContext::confirm_reachable(
1861 self,
1862 bindings_ctx,
1863 &device,
1864 neighbor,
1865 );
1866 }
1867 None => {
1868 debug!("can't confirm {dst:?} as reachable: no route");
1869 }
1870 }
1871 }
1872}
1873
1874pub trait SocketMetadata<CC>
1877where
1878 CC: ?Sized,
1879{
1880 fn socket_info(&self, core_ctx: &mut CC) -> SocketInfo;
1882 fn marks(&self, _core_ctx: &mut CC) -> Marks;
1884}
1885
1886impl<T, O, CC> SocketMetadata<CC> for EitherStack<T, O>
1887where
1888 CC: ?Sized,
1889 T: SocketMetadata<CC>,
1890 O: SocketMetadata<CC>,
1891{
1892 fn socket_info(&self, core_ctx: &mut CC) -> SocketInfo {
1893 match self {
1894 Self::ThisStack(t) => t.socket_info(core_ctx),
1895 Self::OtherStack(o) => o.socket_info(core_ctx),
1896 }
1897 }
1898
1899 fn marks(&self, core_ctx: &mut CC) -> Marks {
1900 match self {
1901 Self::ThisStack(t) => t.marks(core_ctx),
1902 Self::OtherStack(o) => o.marks(core_ctx),
1903 }
1904 }
1905}
1906
1907pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1912 type EarlyDemuxSocket: SocketMetadata<Self>;
1914
1915 fn early_demux<B: ParseBuffer>(
1917 &mut self,
1918 device: &Self::DeviceId,
1919 frame_dst: Option<LocalFrameDestination>,
1920 src_ip: I::Addr,
1921 dst_ip: I::Addr,
1922 proto: I::Proto,
1923 body: B,
1924 ) -> Option<Self::EarlyDemuxSocket>;
1925
1926 fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1930 &mut self,
1931 bindings_ctx: &mut BC,
1932 device: &Self::DeviceId,
1933 src_ip: I::RecvSrcAddr,
1934 dst_ip: SpecifiedAddr<I::Addr>,
1935 proto: I::Proto,
1936 body: B,
1937 info: &mut LocalDeliveryPacketInfo<I, H>,
1938 early_demux_socket: Option<Self::EarlyDemuxSocket>,
1939 ) -> Result<(), I::IcmpError>;
1940}
1941
1942pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1944 IpTransportDispatchContext<
1945 I,
1946 BC,
1947 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1948 > + IpDeviceIngressStateContext<I>
1949 + IpDeviceMtuContext<I>
1950 + IpDeviceSendContext<I, BC>
1951 + IcmpErrorHandler<I, BC>
1952 + IpLayerContext<I, BC>
1953 + FragmentHandler<I, BC>
1954 + FilterHandlerProvider<I, BC>
1955 + RawIpSocketHandler<I, BC>
1956{
1957}
1958
1959impl<
1960 I: IpLayerIpExt,
1961 BC: IpLayerBindingsContext<I, CC::DeviceId>,
1962 CC: IpTransportDispatchContext<
1963 I,
1964 BC,
1965 DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1966 > + IpDeviceIngressStateContext<I>
1967 + IpDeviceMtuContext<I>
1968 + IpDeviceSendContext<I, BC>
1969 + IcmpErrorHandler<I, BC>
1970 + IpLayerContext<I, BC>
1971 + FragmentHandler<I, BC>
1972 + FilterHandlerProvider<I, BC>
1973 + RawIpSocketHandler<I, BC>,
1974> IpLayerIngressContext<I, BC> for CC
1975{
1976}
1977
1978pub trait IpLayerEgressContext<I, BC>:
1980 IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1981 + FilterHandlerProvider<I, BC>
1982 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1983where
1984 I: IpLayerIpExt,
1985 BC: FilterBindingsContext<Self::DeviceId> + TxMetadataBindingsTypes,
1986{
1987}
1988
1989impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1990where
1991 I: IpLayerIpExt,
1992 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes,
1993 CC: IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1994 + FilterHandlerProvider<I, BC>
1995 + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
1996{
1997}
1998
1999pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
2001 IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
2002{
2003}
2004
2005impl<
2006 I: IpLayerIpExt,
2007 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2008 CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
2009> IpLayerForwardingContext<I, BC> for CC
2010{
2011}
2012
2013#[derive(Copy, Clone, Default)]
2015pub struct Ipv4StateBuilder {
2016 icmp: Icmpv4StateBuilder,
2017}
2018
2019impl Ipv4StateBuilder {
2020 #[cfg(any(test, feature = "testutils"))]
2022 pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
2023 &mut self.icmp
2024 }
2025
2026 pub fn build<
2028 CC: CoreTimerContext<IpLayerTimerId, BC>,
2029 StrongDeviceId: StrongDeviceIdentifier,
2030 BC: TimerContext + RngContext + IpLayerBindingsTypes,
2031 >(
2032 self,
2033 bindings_ctx: &mut BC,
2034 ) -> Ipv4State<StrongDeviceId, BC> {
2035 let Ipv4StateBuilder { icmp } = self;
2036
2037 Ipv4State {
2038 inner: IpStateInner::new::<CC>(bindings_ctx),
2039 icmp: icmp.build(),
2040 next_packet_id: Default::default(),
2041 }
2042 }
2043}
2044
2045#[derive(Copy, Clone)]
2049pub struct Ipv6StateBuilder {
2050 icmp: Icmpv6StateBuilder,
2051 slaac_stable_secret_key: Option<IidSecret>,
2052}
2053
2054impl Ipv6StateBuilder {
2055 pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
2060 self.slaac_stable_secret_key = Some(secret_key);
2061 self
2062 }
2063
2064 pub fn build<
2070 CC: CoreTimerContext<IpLayerTimerId, BC>,
2071 StrongDeviceId: StrongDeviceIdentifier,
2072 BC: TimerContext + RngContext + IpLayerBindingsTypes,
2073 >(
2074 self,
2075 bindings_ctx: &mut BC,
2076 ) -> Ipv6State<StrongDeviceId, BC> {
2077 let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
2078
2079 let slaac_stable_secret_key = slaac_stable_secret_key
2080 .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
2081
2082 Ipv6State {
2083 inner: IpStateInner::new::<CC>(bindings_ctx),
2084 icmp: icmp.build(),
2085 slaac_counters: Default::default(),
2086 slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
2087 slaac_stable_secret_key,
2088 }
2089 }
2090}
2091
2092impl Default for Ipv6StateBuilder {
2093 fn default() -> Self {
2094 #[cfg(any(test, feature = "testutils"))]
2095 let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
2096
2097 #[cfg(not(any(test, feature = "testutils")))]
2098 let slaac_stable_secret_key = None;
2099
2100 Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
2101 }
2102}
2103
2104pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
2106 pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
2108 pub icmp: Icmpv4State<BT>,
2110 pub next_packet_id: AtomicU16,
2112}
2113
2114impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2115 AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
2116{
2117 fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
2118 &self.inner
2119 }
2120}
2121
2122pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
2126 core_ctx: &mut CC,
2127) -> I::PacketId {
2128 core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
2129}
2130
2131pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
2133 pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
2135 pub icmp: Icmpv6State<BT>,
2137 pub slaac_counters: SlaacCounters,
2139 pub slaac_temp_secret_key: IidSecret,
2141 pub slaac_stable_secret_key: IidSecret,
2146}
2147
2148impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2149 AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
2150{
2151 fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
2152 &self.inner
2153 }
2154}
2155
2156impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2157 OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
2158{
2159 type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
2160 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2161 OrderedLockRef::new(&self.fragment_cache)
2162 }
2163}
2164
2165impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2166 OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
2167{
2168 type Lock = Mutex<PmtuCache<I, BT>>;
2169 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2170 OrderedLockRef::new(&self.pmtu_cache)
2171 }
2172}
2173
2174impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2175 OrderedLockAccess<RulesTable<I, D, BT>> for IpStateInner<I, D, BT>
2176{
2177 type Lock = RwLock<RulesTable<I, D, BT>>;
2178 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2179 OrderedLockRef::new(&self.rules_table)
2180 }
2181}
2182
2183impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2184 OrderedLockAccess<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>
2185 for IpStateInner<I, D, BT>
2186{
2187 type Lock =
2188 Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>;
2189 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2190 OrderedLockRef::new(&self.tables)
2191 }
2192}
2193
2194impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpRoutingBindingsTypes>
2195 OrderedLockAccess<RoutingTable<I, D>> for RoutingTableId<I, D, BT>
2196{
2197 type Lock = RwLock<RoutingTable<I, D>>;
2198 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2199 let Self(inner) = self;
2200 OrderedLockRef::new(&inner.routing_table)
2201 }
2202}
2203
2204impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2205 OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
2206{
2207 type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
2208 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2209 OrderedLockRef::new(&self.multicast_forwarding)
2210 }
2211}
2212
2213impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2214 OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
2215{
2216 type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
2217 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2218 OrderedLockRef::new(&self.raw_sockets)
2219 }
2220}
2221
2222impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2223 OrderedLockAccess<filter::State<I, WeakAddressId<I, BT>, BT>> for IpStateInner<I, D, BT>
2224{
2225 type Lock = RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>;
2226 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2227 OrderedLockRef::new(&self.filter)
2228 }
2229}
2230
2231pub trait IpStateBindingsTypes:
2233 PmtuBindingsTypes
2234 + FragmentBindingsTypes
2235 + RawIpSocketsBindingsTypes
2236 + FilterBindingsTypes
2237 + MulticastForwardingBindingsTypes
2238 + IpDeviceStateBindingsTypes
2239 + IpRoutingBindingsTypes
2240{
2241}
2242impl<BT> IpStateBindingsTypes for BT where
2243 BT: PmtuBindingsTypes
2244 + FragmentBindingsTypes
2245 + RawIpSocketsBindingsTypes
2246 + FilterBindingsTypes
2247 + MulticastForwardingBindingsTypes
2248 + IpDeviceStateBindingsTypes
2249 + IpRoutingBindingsTypes
2250{
2251}
2252
2253#[derive(Derivative)]
2255#[derivative(Debug(bound = ""))]
2256#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2257pub enum RoutingTableCookie<BT: IpRoutingBindingsTypes> {
2258 Main,
2260 BindingsId(BT::RoutingTableId),
2262}
2263
2264#[derive(Derivative)]
2266#[derivative(Debug(bound = "D: Debug"))]
2267pub struct BaseRoutingTableState<I: Ip, D, BT: IpRoutingBindingsTypes> {
2268 routing_table: RwLock<RoutingTable<I, D>>,
2269 bindings_id: RoutingTableCookie<BT>,
2270}
2271
2272impl<I: Ip, D, BT: IpRoutingBindingsTypes> BaseRoutingTableState<I, D, BT> {
2273 pub(crate) fn with_bindings_id(bindings_id: RoutingTableCookie<BT>) -> Self {
2274 Self { bindings_id, routing_table: Default::default() }
2275 }
2276}
2277
2278#[derive(Derivative)]
2280#[derivative(PartialEq(bound = ""))]
2281#[derivative(Eq(bound = ""))]
2282#[derivative(Hash(bound = ""))]
2283#[derivative(Clone(bound = ""))]
2284pub struct RoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes>(
2285 StrongRc<BaseRoutingTableState<I, D, BT>>,
2286);
2287
2288impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for RoutingTableId<I, D, BT> {
2289 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2290 let Self(rc) = self;
2291 f.debug_tuple("RoutingTableId").field(&I::NAME).field(&rc.bindings_id).finish()
2292 }
2293}
2294
2295impl<I: Ip, D, BT: IpRoutingBindingsTypes> RoutingTableId<I, D, BT> {
2296 pub(crate) fn new(rc: StrongRc<BaseRoutingTableState<I, D, BT>>) -> Self {
2298 Self(rc)
2299 }
2300
2301 #[cfg(any(test, feature = "testutils"))]
2303 pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
2304 let Self(inner) = self;
2305 &inner.routing_table
2306 }
2307
2308 pub fn downgrade(&self) -> WeakRoutingTableId<I, D, BT>
2310 where
2311 BT::RoutingTableId: Clone,
2312 {
2313 let Self(rc) = self;
2314 WeakRoutingTableId { rc: StrongRc::downgrade(rc), bindings_id: rc.bindings_id.clone() }
2315 }
2316
2317 #[cfg(test)]
2318 fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2319 let Self(rc) = self;
2320 rc.routing_table.write()
2321 }
2322
2323 pub fn bindings_id(&self) -> &RoutingTableCookie<BT> {
2325 let Self(rc) = self;
2326 &rc.bindings_id
2327 }
2328}
2329
2330#[derive(Derivative)]
2332#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2333#[derivative(PartialEq, Eq, Hash)]
2334pub struct WeakRoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes> {
2335 rc: WeakRc<BaseRoutingTableState<I, D, BT>>,
2336 #[derivative(PartialEq = "ignore")]
2337 #[derivative(Hash = "ignore")]
2338 bindings_id: RoutingTableCookie<BT>,
2339}
2340
2341impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for WeakRoutingTableId<I, D, BT> {
2342 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2343 let Self { bindings_id, .. } = self;
2344 f.debug_tuple("WeakRoutingTableId").field(&I::NAME).field(bindings_id).finish()
2345 }
2346}
2347
2348#[derive(GenericOverIp)]
2350#[generic_over_ip(I, Ip)]
2351pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2352 rules_table: RwLock<RulesTable<I, D, BT>>,
2353 main_table_id: RoutingTableId<I, D, BT>,
2355 multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2356 multicast_forwarding_counters: MulticastForwardingCounters<I>,
2357 fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2358 pmtu_cache: Mutex<PmtuCache<I, BT>>,
2359 counters: IpCounters<I>,
2360 raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2361 raw_socket_counters: RawIpSocketCounters<I>,
2362 filter: RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>,
2363 tables: Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>,
2369 igmp_counters: IgmpCounters,
2370 mld_counters: MldCounters,
2371}
2372
2373impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2374 pub fn counters(&self) -> &IpCounters<I> {
2376 &self.counters
2377 }
2378
2379 pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2381 &self.multicast_forwarding_counters
2382 }
2383
2384 pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2386 &self.raw_socket_counters
2387 }
2388
2389 pub fn main_table_id(&self) -> &RoutingTableId<I, D, BT> {
2391 &self.main_table_id
2392 }
2393
2394 #[cfg(any(test, feature = "testutils"))]
2396 pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2397 &self.pmtu_cache
2398 }
2399
2400 #[cfg(any(test, feature = "testutils"))]
2402 pub fn filter(&self) -> &RwLock<filter::State<I, WeakAddressId<I, BT>, BT>> {
2403 &self.filter
2404 }
2405
2406 pub fn igmp_counters(&self) -> &IgmpCounters {
2408 &self.igmp_counters
2409 }
2410
2411 pub fn mld_counters(&self) -> &MldCounters {
2413 &self.mld_counters
2414 }
2415}
2416
2417impl<
2418 I: IpLayerIpExt,
2419 D: StrongDeviceIdentifier,
2420 BC: TimerContext + RngContext + IpStateBindingsTypes + IpRoutingBindingsTypes,
2421> IpStateInner<I, D, BC>
2422{
2423 fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2425 let main_table: PrimaryRc<BaseRoutingTableState<I, D, BC>> =
2426 PrimaryRc::new(BaseRoutingTableState::with_bindings_id(RoutingTableCookie::Main));
2427 let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2428 Self {
2429 rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2430 tables: Mutex::new(HashMap::from_iter(core::iter::once((
2431 main_table_id.clone(),
2432 main_table,
2433 )))),
2434 main_table_id,
2435 multicast_forwarding: Default::default(),
2436 multicast_forwarding_counters: Default::default(),
2437 fragment_cache: Mutex::new(
2438 IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2439 ),
2440 pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2441 counters: Default::default(),
2442 raw_sockets: Default::default(),
2443 raw_socket_counters: Default::default(),
2444 filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2445 igmp_counters: Default::default(),
2446 mld_counters: Default::default(),
2447 }
2448 }
2449}
2450
2451#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2453#[generic_over_ip()]
2454pub enum IpLayerTimerId {
2455 ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2457 ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2459 PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2461 PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2463 FilterTimerv4(FilterTimerId<Ipv4>),
2465 FilterTimerv6(FilterTimerId<Ipv6>),
2467 MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2469 MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2471}
2472
2473impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2474 fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2475 I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2476 }
2477}
2478
2479impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2480 fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2481 I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2482 }
2483}
2484
2485impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2486 fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2487 I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2488 }
2489}
2490
2491impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2492 fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2493 I::map_ip(
2494 timer,
2495 IpLayerTimerId::MulticastForwardingTimerv4,
2496 IpLayerTimerId::MulticastForwardingTimerv6,
2497 )
2498 }
2499}
2500
2501impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2502where
2503 CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2504 + TimerHandler<BC, FragmentTimerId<Ipv6>>
2505 + TimerHandler<BC, PmtuTimerId<Ipv4>>
2506 + TimerHandler<BC, PmtuTimerId<Ipv6>>
2507 + TimerHandler<BC, FilterTimerId<Ipv4>>
2508 + TimerHandler<BC, FilterTimerId<Ipv6>>
2509 + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2510 + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2511 BC: TimerBindingsTypes,
2512{
2513 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2514 match self {
2515 IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2516 core_ctx.handle_timer(bindings_ctx, id, timer)
2517 }
2518 IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2519 core_ctx.handle_timer(bindings_ctx, id, timer)
2520 }
2521 IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2522 IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2523 IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2524 IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2525 IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2526 core_ctx.handle_timer(bindings_ctx, id, timer)
2527 }
2528 IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2529 core_ctx.handle_timer(bindings_ctx, id, timer)
2530 }
2531 }
2532 }
2533}
2534
2535pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2542 err: I::IcmpError,
2544 src_ip: SocketIpAddr<I::Addr>,
2547 dst_ip: SocketIpAddr<I::Addr>,
2550 frame_dst: Option<LocalFrameDestination>,
2552 device: &'a D,
2554 meta: ParseMetadata,
2557 marks: Marks,
2559 proto: I::Proto,
2561}
2562
2563impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2564 pub fn new<CC, B>(
2565 core_ctx: &mut CC,
2566 err: I::IcmpError,
2567 packet: &I::Packet<B>,
2568 frame_dst: Option<LocalFrameDestination>,
2569 device: &'a D,
2570 marks: Marks,
2571 ) -> Option<Self>
2572 where
2573 I: IpCountersIpExt,
2574 CC: ResourceCounterContext<D, IpCounters<I>>,
2575 B: SplitByteSlice,
2576 {
2577 let Some(src_ip) = SocketIpAddr::new(packet.src_ip()) else {
2578 core_ctx.increment_both(device, |c| &c.unspecified_source);
2579 return None;
2580 };
2581 let Some(dst_ip) = SocketIpAddr::new(packet.dst_ip()) else {
2582 return None;
2583 };
2584
2585 let is_ipv4_fragment = I::map_ip_in(
2587 packet,
2588 |p| {
2589 packet_formats::ipv4::Ipv4Header::fragment_type(p)
2590 == Ipv4FragmentType::NonInitialFragment
2591 },
2592 |_| false,
2593 );
2594 if is_ipv4_fragment {
2595 return None;
2596 }
2597
2598 let meta = packet.parse_metadata();
2599 let proto = packet.proto();
2600 Some(Self { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto })
2601 }
2602
2603 pub fn send<B, BC, CC>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, mut body: B)
2610 where
2611 B: BufferMut,
2612 CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2613 {
2614 let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto } = self;
2615 let header_len = meta.header_len();
2616
2617 body.undo_parse(meta);
2621
2622 core_ctx.send_icmp_error_message(
2623 bindings_ctx,
2624 Some(device),
2625 frame_dst,
2626 src_ip,
2627 dst_ip,
2628 body,
2629 err,
2630 header_len,
2631 proto,
2632 &marks,
2633 );
2634 }
2635}
2636
2637#[derive(PartialEq, Eq)]
2643struct EarlyDemuxResult<I: Ip, S> {
2644 socket: S,
2645 src_addr: I::Addr,
2646 src_port: Option<u16>,
2647}
2648
2649impl<I: FilterIpExt, S> EarlyDemuxResult<I, S> {
2650 fn new<P: IpPacket<I>>(socket: S, packet: &P) -> Self {
2651 let src_port =
2652 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port_or_id());
2653 Self { socket, src_addr: packet.src_addr(), src_port }
2654 }
2655
2656 fn take_socket<P: IpPacket<I>>(self, packet: &P) -> Option<S> {
2658 let src_port =
2659 packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port_or_id());
2660 (self.src_addr == packet.src_addr() && self.src_port == src_port).then_some(self.socket)
2661 }
2662
2663 fn update_packet_metadata<CC, BC>(
2664 &self,
2665 core_ctx: &mut CC,
2666 packet_metadata: &mut IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2667 ) where
2668 I: IpLayerIpExt,
2669 S: SocketMetadata<CC>,
2670 BC: IpLayerBindingsContext<I, CC::DeviceId>,
2671 CC: IpLayerIngressContext<I, BC>,
2672 {
2673 packet_metadata.socket_info = Some(self.socket.socket_info(core_ctx));
2674 packet_metadata.marks =
2675 BC::update_ingress_marks(packet_metadata.marks, &self.socket.marks(core_ctx));
2676 }
2677}
2678
2679pub(crate) fn reject_type_to_icmpv4_error(reject_type: RejectType) -> Option<Icmpv4Error> {
2680 let error = match reject_type {
2681 RejectType::NetUnreachable => Icmpv4Error::NetUnreachable,
2682 RejectType::ProtoUnreachable => Icmpv4Error::ProtocolUnreachable,
2683 RejectType::PortUnreachable => Icmpv4Error::PortUnreachable,
2684 RejectType::HostUnreachable => Icmpv4Error::HostUnreachable,
2685 RejectType::RoutePolicyFail => Icmpv4Error::NetworkProhibited,
2686 RejectType::RejectRoute => Icmpv4Error::HostProhibited,
2687 RejectType::AdminProhibited => Icmpv4Error::AdminProhibited,
2688 RejectType::TcpReset => return None,
2690 };
2691 Some(error)
2692}
2693
2694pub(crate) fn reject_type_to_icmpv6_error(reject_type: RejectType) -> Option<Icmpv6Error> {
2695 let error = match reject_type {
2696 RejectType::NetUnreachable => Icmpv6Error::NetUnreachable,
2697 RejectType::PortUnreachable => Icmpv6Error::PortUnreachable,
2698 RejectType::HostUnreachable => Icmpv6Error::AddressUnreachable,
2699 RejectType::AdminProhibited => Icmpv6Error::AdminProhibited,
2700 RejectType::RoutePolicyFail => Icmpv6Error::SourceAddressPolicyFailed,
2701 RejectType::RejectRoute => Icmpv6Error::RejectRoute,
2702 RejectType::TcpReset | RejectType::ProtoUnreachable => return None,
2704 };
2705 Some(error)
2706}
2707fn dispatch_receive_ipv4_packet<
2728 'a,
2729 'b,
2730 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2731 CC: IpLayerIngressContext<Ipv4, BC>,
2732>(
2733 core_ctx: &'a mut CC,
2734 bindings_ctx: &'a mut BC,
2735 device: &'b CC::DeviceId,
2736 frame_dst: Option<LocalFrameDestination>,
2737 mut packet: Ipv4Packet<&'a mut [u8]>,
2738 mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2739 receive_meta: ReceiveIpPacketMeta<Ipv4>,
2740) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2741 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2742
2743 let early_demux_result = receive_meta
2746 .transparent_override
2747 .is_none()
2748 .then(|| {
2749 core_ctx.early_demux(
2750 device,
2751 frame_dst,
2752 packet.src_ip(),
2753 packet.dst_ip(),
2754 packet.proto(),
2755 packet.body(),
2756 )
2757 })
2758 .flatten()
2759 .map(|socket| {
2760 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2761 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2762 early_demux_result
2763 });
2764
2765 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2766 bindings_ctx,
2767 &mut packet,
2768 device,
2769 &mut packet_metadata,
2770 );
2771
2772 let marks = packet_metadata.marks;
2773 let packet_type = packet_metadata.packet_type;
2774 let gso_info = packet_metadata.gso_info;
2775 packet_metadata.acknowledge_drop();
2776
2777 match filter_verdict {
2778 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2779 return Ok(());
2780 }
2781 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2782 return match reject_type_to_icmpv4_error(reject_type) {
2783 Some(icmp_error) => {
2784 match IcmpErrorSender::new(
2785 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2786 ) {
2787 Some(icmp_sender) => Err(icmp_sender),
2788 None => Ok(()),
2789 }
2790 }
2791 None => {
2792 debug!("Unsupported reject type: {:?}", reject_type);
2793 return Ok(());
2794 }
2795 };
2796 }
2797 filter::Verdict::Proceed(filter::Accept) => (),
2798 };
2799
2800 let Some(src_ip) = packet.src_ipv4() else {
2804 debug!(
2805 "dispatch_receive_ipv4_packet: received packet from invalid source {} after the \
2806 LOCAL_INGRESS hook; dropping",
2807 packet.src_ip()
2808 );
2809 core_ctx.increment_both(device, |c| &c.invalid_source);
2810 return Ok(());
2811 };
2812 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2813 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2814 debug!(
2815 "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2816 after the LOCAL_INGRESS hook; dropping"
2817 );
2818 return Ok(());
2819 };
2820
2821 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2822
2823 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2825
2826 let proto = packet.proto();
2827 let (prefix, options, body) = packet.parts_with_body_mut();
2828 let buffer = Buf::new(body, ..);
2829 let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2830 let mut receive_info =
2831 LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks, packet_type, gso_info };
2832
2833 core_ctx
2834 .dispatch_receive_ip_packet(
2835 bindings_ctx,
2836 device,
2837 src_ip,
2838 dst_ip,
2839 proto,
2840 buffer,
2841 &mut receive_info,
2842 early_demux_socket,
2843 )
2844 .or_else(|icmp_error| {
2845 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2846 Some(icmp_sender) => Err(icmp_sender),
2847 None => Ok(()),
2848 }
2849 })
2850}
2851
2852fn dispatch_receive_ipv6_packet<
2857 'a,
2858 'b,
2859 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2860 CC: IpLayerIngressContext<Ipv6, BC>,
2861>(
2862 core_ctx: &'a mut CC,
2863 bindings_ctx: &'a mut BC,
2864 device: &'b CC::DeviceId,
2865 frame_dst: Option<LocalFrameDestination>,
2866 mut packet: Ipv6Packet<&'a mut [u8]>,
2867 mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2868 meta: ReceiveIpPacketMeta<Ipv6>,
2869) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2870 core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2877
2878 let early_demux_result = meta
2881 .transparent_override
2882 .is_none()
2883 .then(|| {
2884 core_ctx.early_demux(
2885 device,
2886 frame_dst,
2887 packet.src_ip(),
2888 packet.dst_ip(),
2889 packet.proto(),
2890 packet.body(),
2891 )
2892 })
2893 .flatten()
2894 .map(|socket| {
2895 let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2896 early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2897 early_demux_result
2898 });
2899
2900 let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2901 bindings_ctx,
2902 &mut packet,
2903 device,
2904 &mut packet_metadata,
2905 );
2906
2907 let marks = packet_metadata.marks;
2908 let packet_type = packet_metadata.packet_type;
2909 let gso_info = packet_metadata.gso_info;
2910 packet_metadata.acknowledge_drop();
2911
2912 match filter_verdict {
2913 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2914 return Ok(());
2915 }
2916 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2917 return match reject_type_to_icmpv6_error(reject_type) {
2918 Some(icmp_error) => {
2919 match IcmpErrorSender::new(
2920 core_ctx, icmp_error, &packet, frame_dst, device, marks,
2921 ) {
2922 Some(icmp_sender) => Err(icmp_sender),
2923 None => Ok(()),
2924 }
2925 }
2926 None => {
2927 debug!("Unsupported reject type: {:?}", reject_type);
2928 return Ok(());
2929 }
2930 };
2931 }
2932 filter::Verdict::Proceed(filter::Accept) => {}
2933 }
2934
2935 let Some(src_ip) = packet.src_ipv6() else {
2939 debug!(
2940 "dispatch_receive_ipv6_packet: received packet from invalid source {} after the \
2941 LOCAL_INGRESS hook; dropping",
2942 packet.src_ip()
2943 );
2944
2945 core_ctx.increment_both(device, |c| &c.invalid_source);
2946 return Ok(());
2947 };
2948 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2949 core_ctx.increment_both(device, |c| &c.unspecified_destination);
2950 debug!(
2951 "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2952 after the LOCAL_INGRESS hook; dropping"
2953 );
2954 return Ok(());
2955 };
2956
2957 core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2958
2959 let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2961
2962 let proto = packet.proto();
2963 let (fixed, extension, body) = packet.parts_with_body_mut();
2964 let buffer = Buf::new(body, ..);
2965 let header_info = Ipv6HeaderInfo { fixed, extension };
2966 let mut receive_info =
2967 LocalDeliveryPacketInfo { meta, header_info, marks, packet_type, gso_info };
2968
2969 core_ctx
2970 .dispatch_receive_ip_packet(
2971 bindings_ctx,
2972 device,
2973 src_ip,
2974 dst_ip,
2975 proto,
2976 buffer,
2977 &mut receive_info,
2978 early_demux_socket,
2979 )
2980 .or_else(|icmp_error| {
2981 let marks = receive_info.marks;
2982 match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2983 Some(icmp_sender) => Err(icmp_sender),
2984 None => Ok(()),
2985 }
2986 })
2987}
2988
2989pub(crate) struct IpPacketForwarder<
2996 'a,
2997 I: IpLayerIpExt,
2998 D,
2999 A,
3000 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
3001> {
3002 inbound_device: &'a D,
3003 outbound_device: &'a D,
3004 packet_meta: IpLayerPacketMetadata<I, A, BT>,
3005 src_ip: I::RecvSrcAddr,
3006 dst_ip: SpecifiedAddr<I::Addr>,
3007 destination: IpPacketDestination<I, &'a D>,
3008 proto: I::Proto,
3009 parse_meta: ParseMetadata,
3010 frame_dst: Option<LocalFrameDestination>,
3011}
3012
3013impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
3014where
3015 I: IpLayerIpExt,
3016 BC: IpLayerBindingsContext<I, D>,
3017{
3018 fn forward_with_buffer<CC, B>(
3020 self,
3021 core_ctx: &mut CC,
3022 bindings_ctx: &mut BC,
3023 buffer: B,
3024 max_fragment_len: Option<usize>,
3025 ) where
3026 B: BufferMut,
3027 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
3028 {
3029 let Self {
3030 inbound_device,
3031 outbound_device,
3032 packet_meta,
3033 src_ip,
3034 dst_ip,
3035 destination,
3036 proto,
3037 parse_meta,
3038 frame_dst,
3039 } = self;
3040
3041 let outbound_mtu = core_ctx.get_mtu(outbound_device);
3042 let marks = packet_meta.marks;
3043
3044 let send_icmp_packet_too_big = |core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B| {
3045 debug!("failed to forward {} packet: MTU exceeded", I::NAME);
3046 core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
3047 let Some(err) = I::IcmpError::mtu_exceeded(outbound_mtu) else {
3049 return;
3050 };
3051 let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
3054 return;
3055 };
3056
3057 let Some(dst_ip) = SocketIpAddr::new(dst_ip.get()) else {
3058 return;
3059 };
3060
3061 core_ctx.send_icmp_error_message(
3071 bindings_ctx,
3072 Some(inbound_device),
3073 frame_dst,
3074 src_ip,
3075 dst_ip,
3076 buffer,
3077 err,
3078 parse_meta.header_len(),
3079 proto,
3080 &marks,
3081 );
3082 };
3083
3084 let max_fragment_len = max_fragment_len
3090 .map(|l| Mtu::new(u32::try_from(l).expect("fragment size must fit in u32")));
3091 if I::VERSION == IpVersion::V6
3092 && max_fragment_len.is_some_and(|max_fragment_len| max_fragment_len > outbound_mtu)
3093 {
3094 packet_meta.acknowledge_drop();
3095 send_icmp_packet_too_big(core_ctx, bindings_ctx, buffer);
3096 return;
3097 }
3098 let (was_reassembled, limit_mtu) = match max_fragment_len {
3099 None => (false, Mtu::no_limit()),
3100 Some(max_fragment_len) => (true, max_fragment_len),
3101 };
3102
3103 let packet = ForwardedPacket::new(
3104 src_ip.get(),
3105 dst_ip.get(),
3106 proto,
3107 parse_meta,
3108 buffer,
3109 was_reassembled,
3110 );
3111
3112 trace!("forward_with_buffer: forwarding {} packet", I::NAME);
3113
3114 match send_ip_frame(
3115 core_ctx,
3116 bindings_ctx,
3117 outbound_device,
3118 destination,
3119 packet,
3120 packet_meta,
3121 limit_mtu,
3122 ) {
3123 Ok(()) => (),
3124 Err(IpSendFrameError { serializer, error }) => {
3125 match error {
3126 IpSendFrameErrorReason::Device(
3127 SendFrameErrorReason::SizeConstraintsViolation,
3128 ) => {
3129 send_icmp_packet_too_big(core_ctx, bindings_ctx, serializer.into_buffer());
3130 }
3131 IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
3132 | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
3133 | IpSendFrameErrorReason::Device(
3134 SendFrameErrorReason::AddressResolutionFailed,
3135 )
3136 | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
3137 }
3138 debug!("failed to forward {} packet: {error:?}", I::NAME);
3139 }
3140 }
3141 }
3142}
3143
3144pub(crate) enum ForwardingAction<
3146 'a,
3147 I: IpLayerIpExt,
3148 D,
3149 A,
3150 BT: FilterBindingsTypes + TxMetadataBindingsTypes,
3151> {
3152 SilentlyDrop,
3154 Forward(IpPacketForwarder<'a, I, D, A, BT>),
3156 DropWithIcmpError(IcmpErrorSender<'a, I, D>),
3159}
3160
3161impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
3162where
3163 I: IpLayerIpExt,
3164 BC: IpLayerBindingsContext<I, D>,
3165{
3166 pub(crate) fn perform_action_with_buffer<CC, B>(
3168 self,
3169 core_ctx: &mut CC,
3170 bindings_ctx: &mut BC,
3171 buffer: B,
3172 max_fragment_len: Option<usize>,
3173 ) where
3174 B: BufferMut,
3175 CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
3176 {
3177 match self {
3178 ForwardingAction::SilentlyDrop => {}
3179 ForwardingAction::Forward(forwarder) => {
3180 forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer, max_fragment_len)
3181 }
3182 ForwardingAction::DropWithIcmpError(icmp_sender) => {
3183 icmp_sender.send(core_ctx, bindings_ctx, buffer)
3184 }
3185 }
3186 }
3187}
3188
3189pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
3191 core_ctx: &'a mut CC,
3192 mut packet: I::Packet<&'a mut [u8]>,
3193 mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3194 minimum_ttl: Option<NonZeroU8>,
3195 inbound_device: &'b CC::DeviceId,
3196 outbound_device: &'b CC::DeviceId,
3197 destination: IpPacketDestination<I, &'b CC::DeviceId>,
3198 frame_dst: Option<LocalFrameDestination>,
3199 src_ip: I::RecvSrcAddr,
3200 dst_ip: SpecifiedAddr<I::Addr>,
3201) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
3202where
3203 I: IpLayerIpExt,
3204 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3205 CC: IpLayerForwardingContext<I, BC>,
3206{
3207 const DEFAULT_MIN_TTL: u8 = 1;
3212 let minimum_ttl = minimum_ttl.map(NonZeroU8::get).unwrap_or(DEFAULT_MIN_TTL);
3213 let ttl = packet.ttl();
3214 if ttl <= minimum_ttl {
3215 debug!(
3216 "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
3217 I::NAME
3218 );
3219 if ttl > 1 {
3231 packet_meta.acknowledge_drop();
3232 return ForwardingAction::SilentlyDrop;
3233 }
3234
3235 core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
3236
3237 let marks = packet_meta.marks;
3238 packet_meta.acknowledge_drop();
3239
3240 match IcmpErrorSender::new(
3242 core_ctx,
3243 I::IcmpError::ttl_expired(),
3244 &packet,
3245 frame_dst,
3246 inbound_device,
3247 marks,
3248 ) {
3249 Some(icmp_sender) => return ForwardingAction::DropWithIcmpError(icmp_sender),
3250 None => return ForwardingAction::SilentlyDrop,
3251 }
3252 }
3253
3254 trace!("determine_ip_packet_forwarding_action: adequate TTL");
3255
3256 let maybe_ipv6_packet_action = I::map_ip_in(
3262 &packet,
3263 |_packet| None,
3264 |packet| {
3265 Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
3266 },
3267 );
3268 match maybe_ipv6_packet_action {
3269 None => {} Some(Ipv6PacketAction::_Discard) => {
3271 core_ctx.increment_both(inbound_device, |c| {
3272 #[derive(GenericOverIp)]
3273 #[generic_over_ip(I, Ip)]
3274 struct InCounters<'a, I: IpLayerIpExt>(
3275 &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<Counter>,
3276 );
3277 I::map_ip_in::<_, _>(
3278 InCounters(&c.version_rx),
3279 |_counters| {
3280 unreachable!(
3281 "`I` must be `Ipv6` because we're handling IPv6 extension headers"
3282 )
3283 },
3284 |InCounters(counters)| &counters.extension_header_discard,
3285 )
3286 });
3287 trace!(
3288 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3289 discarding packet"
3290 );
3291 packet_meta.acknowledge_drop();
3292 return ForwardingAction::SilentlyDrop;
3293 }
3294 Some(Ipv6PacketAction::Continue) => {
3295 trace!(
3296 "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3297 forwarding packet"
3298 );
3299 }
3300 Some(Ipv6PacketAction::ProcessFragment) => {
3301 unreachable!(
3302 "When forwarding packets, we should only ever look at the hop by hop \
3303 options extension header (if present)"
3304 )
3305 }
3306 };
3307
3308 match core_ctx.filter_handler().forwarding_hook(
3309 I::as_filter_packet(&mut packet),
3310 inbound_device,
3311 outbound_device,
3312 &mut packet_meta,
3313 ) {
3314 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3315 packet_meta.acknowledge_drop();
3316 trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
3317 return ForwardingAction::SilentlyDrop;
3318 }
3319 filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
3320 packet_meta.acknowledge_drop();
3322 trace!(
3323 "determine_ip_packet_forwarding_action: filter verdict: Reject({:?})",
3324 reject_type
3325 );
3326 return ForwardingAction::SilentlyDrop;
3327 }
3328 filter::Verdict::Proceed(filter::Accept) => {}
3329 }
3330
3331 packet.set_ttl(ttl - 1);
3332 let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
3333 ForwardingAction::Forward(IpPacketForwarder {
3334 inbound_device,
3335 outbound_device,
3336 packet_meta,
3337 src_ip,
3338 dst_ip,
3339 destination,
3340 proto,
3341 parse_meta,
3342 frame_dst,
3343 })
3344}
3345
3346pub(crate) fn send_ip_frame<I, CC, BC, S>(
3347 core_ctx: &mut CC,
3348 bindings_ctx: &mut BC,
3349 device: &CC::DeviceId,
3350 destination: IpPacketDestination<I, &CC::DeviceId>,
3351 mut body: S,
3352 mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3353 limit_mtu: Mtu,
3354) -> Result<(), IpSendFrameError<S>>
3355where
3356 I: IpLayerIpExt,
3357 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3358 CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
3359 S: FragmentableIpSerializer<I, Buffer: BufferMut>
3360 + MaybeSegmentableIpSerializer<I>
3361 + FilterIpPacket<I>,
3362{
3363 let (verdict, proof) = core_ctx.filter_handler().egress_hook(
3364 bindings_ctx,
3365 &mut body,
3366 device,
3367 &mut packet_metadata,
3368 );
3369 match verdict {
3370 filter::Verdict::Stop(filter::DropPacket) => {
3371 packet_metadata.acknowledge_drop();
3372 return Ok(());
3373 }
3374 filter::Verdict::Proceed(filter::Accept) => {}
3375 }
3376
3377 let (
3381 conntrack_connection_and_direction,
3382 tx_metadata,
3383 marks,
3384 _socket_cookie,
3385 gso_info,
3386 packet_type,
3387 ) = packet_metadata.into_parts();
3388 let conntrack_entry = if device.is_loopback() {
3389 conntrack_connection_and_direction
3390 .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
3391 } else {
3392 None
3393 };
3394
3395 let mut device_layer_marks = Marks::default();
3396 for mark in BC::marks_to_keep_on_egress() {
3397 *device_layer_marks.get_mut(*mark) = *marks.get(*mark);
3398 }
3399
3400 let device_ip_layer_metadata = DeviceIpLayerMetadata {
3401 conntrack_entry,
3402 tx_metadata,
3403 marks: device_layer_marks,
3404 packet_type,
3405 };
3406
3407 if !device.is_loopback()
3411 && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
3412 || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
3413 {
3414 core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
3415 return Err(IpSendFrameError {
3416 serializer: body,
3417 error: IpSendFrameErrorReason::IllegalLoopbackAddress,
3418 });
3419 }
3420
3421 let mtu = limit_mtu.min(core_ctx.get_mtu(device));
3423
3424 let Some(gso_info) = gso_info else {
3425 return send_ip_frame_possibly_fragmented(
3428 core_ctx,
3429 bindings_ctx,
3430 device,
3431 destination,
3432 body,
3433 device_ip_layer_metadata,
3434 mtu,
3435 proof,
3436 );
3437 };
3438
3439 match send_ip_frame_segmented(
3440 core_ctx,
3441 bindings_ctx,
3442 device,
3443 destination.clone(),
3444 &body,
3445 gso_info,
3446 device_ip_layer_metadata,
3447 mtu,
3448 proof,
3449 ) {
3450 Ok(()) => Ok(()),
3451 Err(SendIpFrameSegmentedError::NotSegmentable(error, device_ip_layer_metadata, proof)) => {
3452 debug_assert!(
3457 false,
3458 "GRO or GSO produced a packet that can't be resegmented: {error:?}"
3459 );
3460 error!("GRO or GSO produced a packet that can't be resegmented: {error:?}");
3461 send_ip_frame_possibly_fragmented(
3462 core_ctx,
3463 bindings_ctx,
3464 device,
3465 destination,
3466 body,
3467 device_ip_layer_metadata,
3468 mtu,
3469 proof,
3470 )
3471 }
3472 Err(SendIpFrameSegmentedError::Send(error)) => {
3473 Err(IpSendFrameError { serializer: body, error })
3474 }
3475 }
3476}
3477
3478enum SendIpFrameSegmentedError<BT: TxMetadataBindingsTypes> {
3480 NotSegmentable(GsoError, DeviceIpLayerMetadata<BT>, ProofOfEgressCheck),
3485 Send(IpSendFrameErrorReason),
3487}
3488
3489fn send_ip_frame_segmented<I, CC, BC, S>(
3496 core_ctx: &mut CC,
3497 bindings_ctx: &mut BC,
3498 device: &CC::DeviceId,
3499 destination: IpPacketDestination<I, &CC::DeviceId>,
3500 body: &S,
3501 gso_info: GsoInfo,
3502 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3503 mtu: Mtu,
3504 proof: ProofOfEgressCheck,
3505) -> Result<(), SendIpFrameSegmentedError<BC>>
3506where
3507 I: IpLayerIpExt,
3508 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3509 CC: IpLayerEgressContext<I, BC>,
3510 S: FragmentableIpSerializer<I, Buffer: BufferMut> + MaybeSegmentableIpSerializer<I>,
3511{
3512 core_ctx.increment_both(device, |c| &c.gso.for_source(S::SOURCE).segmentation_required);
3513
3514 let segmenter = match body.try_segmenter(gso_info) {
3515 Ok(segmenter) => segmenter,
3516 Err(error) => {
3517 core_ctx.increment_both(device, |c| c.gso.for_source(S::SOURCE).error_counter(&error));
3518 return Err(SendIpFrameSegmentedError::NotSegmentable(
3519 error,
3520 device_ip_layer_metadata,
3521 proof,
3522 ));
3523 }
3524 };
3525
3526 let mut device_ip_layer_metadata = device_ip_layer_metadata;
3527 let mut proof = proof;
3528
3529 for (segment, has_more) in segmenter {
3530 let (segment_metadata, segment_proof, remaining) = if has_more {
3531 let SplitDeviceIpLayerMetadata { primary, secondary } =
3532 device_ip_layer_metadata.split_for_multiple_frames();
3533 (secondary, proof.clone_for_multiple_frames(), Some((primary, proof)))
3534 } else {
3535 (device_ip_layer_metadata, proof, None)
3536 };
3537
3538 send_ip_frame_possibly_fragmented(
3539 core_ctx,
3540 bindings_ctx,
3541 device,
3542 destination.clone(),
3543 segment,
3544 segment_metadata,
3545 mtu,
3546 segment_proof,
3547 )
3548 .map_err(|IpSendFrameError { serializer: _, error }| {
3549 SendIpFrameSegmentedError::Send(error)
3550 })?;
3551
3552 core_ctx.increment_both(device, |c| &c.gso.for_source(S::SOURCE).segments);
3553
3554 match remaining {
3555 Some((m, p)) => {
3556 device_ip_layer_metadata = m;
3557 proof = p;
3558 }
3559 None => break,
3560 }
3561 }
3562
3563 Ok(())
3564}
3565
3566fn send_ip_frame_possibly_fragmented<I, CC, BC, S>(
3568 core_ctx: &mut CC,
3569 bindings_ctx: &mut BC,
3570 device: &CC::DeviceId,
3571 destination: IpPacketDestination<I, &CC::DeviceId>,
3572 body: S,
3573 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3574 mtu: Mtu,
3575 proof: ProofOfEgressCheck,
3576) -> Result<(), IpSendFrameError<S>>
3577where
3578 I: IpLayerIpExt,
3579 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3580 CC: IpLayerEgressContext<I, BC>,
3581 S: FragmentableIpSerializer<I, Buffer: BufferMut>,
3582{
3583 let body = body.with_size_limit(mtu.into());
3584
3585 let fits_mtu = match body.serialize_new_buf(
3586 &mut NetworkSerializationContext::default(),
3587 PacketConstraints::UNCONSTRAINED,
3588 AlwaysFailBufferAlloc,
3589 ) {
3590 Err(SerializeError::Alloc(())) => true,
3593 Err(SerializeError::SizeLimitExceeded) => false,
3595 };
3596
3597 if fits_mtu {
3598 return core_ctx
3599 .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
3600 .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
3601 serializer: serializer.into_inner(),
3602 error: error.into(),
3603 });
3604 }
3605
3606 core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
3609
3610 let body = body.into_inner();
3611 let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
3612 Ok(mut fragmenter) => {
3613 let mut device_ip_layer_metadata = device_ip_layer_metadata;
3614 loop {
3615 let Some((fragment, has_more)) = fragmenter.next() else {
3616 break Ok(());
3617 };
3618
3619 let (fragment_metadata, remaining_metadata) = if has_more {
3620 let SplitDeviceIpLayerMetadata { primary, secondary } =
3621 device_ip_layer_metadata.split_for_multiple_frames();
3622 (secondary, Some(primary))
3623 } else {
3624 (device_ip_layer_metadata, None)
3625 };
3626
3627 match core_ctx.send_ip_frame(
3628 bindings_ctx,
3629 device,
3630 destination.clone(),
3631 fragment_metadata,
3632 fragment,
3633 proof.clone_for_multiple_frames(),
3634 ) {
3635 Ok(()) => {
3636 core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
3637 }
3638 Err(ErrorAndSerializer { serializer: _, error }) => {
3639 core_ctx.increment_both(device, |c| {
3640 &c.fragmentation.error_fragmented_serializer
3641 });
3642 break Err(error);
3643 }
3644 }
3645
3646 match remaining_metadata {
3647 Some(m) => device_ip_layer_metadata = m,
3648 None => break Ok(()),
3649 }
3650 }
3651 }
3652 Err(e) => {
3653 core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
3654 Err(SendFrameErrorReason::SizeConstraintsViolation)
3655 }
3656 };
3657 result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
3658}
3659
3660struct AlwaysFailBufferAlloc;
3665
3666impl LayoutBufferAlloc<!> for AlwaysFailBufferAlloc {
3667 type Error = ();
3668 fn layout_alloc(self, _prefix: usize, _body: usize, _suffix: usize) -> Result<!, Self::Error> {
3669 Err(())
3670 }
3671}
3672
3673macro_rules! drop_packet_and_undo_parse {
3682 ($packet:expr, $buffer:expr) => {{
3683 let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
3684 $buffer.undo_parse(meta);
3685 (src_ip, dst_ip, proto, meta)
3686 }};
3687}
3688
3689enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
3692 Done,
3695
3696 NotNeeded(I::Packet<&'a mut [u8]>),
3699
3700 Reassembled { buffer: Vec<u8>, max_fragment_len: usize },
3703}
3704
3705fn process_fragment<'a, I, CC, BC>(
3711 core_ctx: &mut CC,
3712 bindings_ctx: &mut BC,
3713 device: &CC::DeviceId,
3714 packet: I::Packet<&'a mut [u8]>,
3715) -> ProcessFragmentResult<'a, I>
3716where
3717 I: IpLayerIpExt,
3718 for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3719 CC: IpLayerIngressContext<I, BC>,
3720 BC: IpLayerBindingsContext<I, CC::DeviceId>,
3721{
3722 match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3723 FragmentProcessingState::NotNeeded(packet) => {
3725 trace!("receive_ip_packet: not fragmented");
3726 ProcessFragmentResult::NotNeeded(packet)
3727 }
3728 FragmentProcessingState::Ready { key, packet_len } => {
3730 trace!("receive_ip_packet: fragmented, ready for reassembly");
3731 let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3733
3734 let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3736 core_ctx,
3737 bindings_ctx,
3738 &key,
3739 buffer.buffer_view_mut(),
3740 ) {
3741 Ok(max_fragment_len) => ProcessFragmentResult::Reassembled {
3743 buffer: buffer.into_inner(),
3744 max_fragment_len,
3745 },
3746 Err(e) => {
3747 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3748 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3749 ProcessFragmentResult::Done
3750 }
3751 };
3752 reassemble_result
3753 }
3754 FragmentProcessingState::NeedMoreFragments => {
3757 core_ctx.increment_both(device, |c| &c.need_more_fragments);
3758 trace!("receive_ip_packet: fragmented, need more before reassembly");
3759 ProcessFragmentResult::Done
3760 }
3761 FragmentProcessingState::InvalidFragment => {
3763 core_ctx.increment_both(device, |c| &c.invalid_fragment);
3764 trace!("receive_ip_packet: fragmented, invalid");
3765 ProcessFragmentResult::Done
3766 }
3767 FragmentProcessingState::OutOfMemory => {
3768 core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3769 trace!("receive_ip_packet: fragmented, dropped because OOM");
3770 ProcessFragmentResult::Done
3771 }
3772 }
3773}
3774
3775fn reassemble_ipv6_atomic_fragment<B: SplitByteSlice>(
3794 packet: &Ipv6Packet<B>,
3795) -> Result<(Vec<u8>, usize), Ipv6ParseError> {
3796 let body = packet.body();
3797 let max_fragment_len = packet.header_len() + body.len();
3798 let header = packet.copy_header_bytes_for_fragment();
3799 let mut buffer = Buf::new(alloc::vec![0; header.len() + body.len()], ..);
3800 Ipv6Packet::reassemble_fragmented_packet(
3801 buffer.buffer_view_mut(),
3802 &header,
3803 core::iter::once(body),
3804 )?;
3805 Ok((buffer.into_inner(), max_fragment_len))
3806}
3807
3808macro_rules! try_parse_ip_packet {
3818 ($buffer:expr) => {{
3819 let p_len = $buffer.prefix_len();
3820 let s_len = $buffer.suffix_len();
3821
3822 let result = $buffer.parse_mut();
3823
3824 if let Err(err) = result {
3825 let n_p_len = $buffer.prefix_len();
3827 let n_s_len = $buffer.suffix_len();
3828
3829 if n_p_len > p_len {
3830 $buffer.grow_front(n_p_len - p_len);
3831 }
3832
3833 if n_s_len > s_len {
3834 $buffer.grow_back(n_s_len - s_len);
3835 }
3836
3837 Err(err)
3838 } else {
3839 result
3840 }
3841 }};
3842}
3843
3844macro_rules! clone_packet_for_mcast_forwarding {
3862 {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3863 let mut $new_data = $packet.to_vec();
3864 let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3865 let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3866 };
3867}
3868
3869pub fn receive_ipv4_packet<
3874 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3875 B: BufferMut,
3876 CC: IpLayerIngressContext<Ipv4, BC>,
3877>(
3878 core_ctx: &mut CC,
3879 bindings_ctx: &mut BC,
3880 device: &CC::DeviceId,
3881 frame_dst: Option<LocalFrameDestination>,
3882 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3883 parsing_context: NetworkParsingContext,
3884 gso_info: Option<GsoInfo>,
3885 buffer: B,
3886) {
3887 if !core_ctx.is_ip_device_enabled(&device) {
3888 return;
3889 }
3890
3891 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3894
3895 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3896 trace!("receive_ip_packet({device:?})");
3897
3898 let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3899 Ok(packet) => packet,
3900 Err(ParseError::Format)
3901 | Err(ParseError::Checksum)
3902 | Err(ParseError::NotSupported)
3903 | Err(ParseError::NotExpected) => {
3904 core_ctx.increment_both(device, |c| &c.unparsable_packet);
3905 return;
3906 }
3907 };
3908
3909 if packet.src_ipv4().is_none() {
3913 debug!(
3914 "receive_ipv4_packet: received packet from invalid source {}; dropping",
3915 packet.src_ip()
3916 );
3917 core_ctx.increment_both(device, |c| &c.invalid_source);
3918 return;
3919 };
3920 if !packet.dst_ip().is_specified() {
3921 core_ctx.increment_both(device, |c| &c.unspecified_destination);
3922 debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3923 return;
3924 };
3925
3926 if !device.is_loopback()
3930 && (Ipv4::LOOPBACK_SUBNET.contains(&packet.src_ip())
3931 || Ipv4::LOOPBACK_SUBNET.contains(&packet.dst_ip()))
3932 {
3933 debug!(
3934 "receive_ipv4_packet: received loopback packet (src={}, dst={}) \
3935 on non-loopback interface; dropping",
3936 packet.src_ip(),
3937 packet.dst_ip(),
3938 );
3939 return;
3940 }
3941
3942 if let Some(src_ip) = SpecifiedAddr::new(packet.src_ip()) {
3945 let is_broadcast = core_ctx
3948 .address_status_for_device(src_ip, device)
3949 .into_present()
3950 .and_then(|status| status.to_broadcast_marker())
3951 .is_some();
3952
3953 if is_broadcast {
3954 debug!(
3955 "receive_ipv4_packet: received packet from broadcast source {}; dropping",
3956 packet.src_ip()
3957 );
3958 core_ctx.increment_both(device, |c| &c.invalid_source);
3959 return;
3960 }
3961 }
3962
3963 let (mut packet, max_fragment_len) =
3976 match process_fragment(core_ctx, bindings_ctx, device, packet) {
3977 ProcessFragmentResult::Done => return,
3978 ProcessFragmentResult::NotNeeded(packet) => (packet, None),
3979 ProcessFragmentResult::Reassembled { buffer: buf, max_fragment_len } => {
3980 let buf = Buf::new(buf, ..);
3981 buffer = packet::Either::B(buf);
3982
3983 match buffer.parse_mut() {
3984 Ok(packet) => (packet, Some(max_fragment_len)),
3985 Err(err) => {
3986 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3987 debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3988 return;
3989 }
3990 }
3991 }
3992 };
3993
3994 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3997 core_ctx,
3998 device,
3999 device_ip_layer_metadata,
4000 gso_info,
4001 );
4002 let mut filter = core_ctx.filter_handler();
4003 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
4004 filter::Verdict::Proceed(filter::Accept) => {}
4005 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
4006 packet_metadata.acknowledge_drop();
4007 return;
4008 }
4009 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
4010 addr,
4011 port,
4012 }) => {
4013 drop(filter);
4016
4017 let Some(addr) = SpecifiedAddr::new(addr) else {
4018 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4019 debug!("cannot perform transparent delivery to unspecified destination; dropping");
4020 packet_metadata.acknowledge_drop();
4021 return;
4022 };
4023
4024 let receive_meta = ReceiveIpPacketMeta {
4025 broadcast: None,
4029 transparent_override: Some(TransparentLocalDelivery { addr, port }),
4030 parsing_context,
4031 };
4032
4033 dispatch_receive_ipv4_packet(
4037 core_ctx,
4038 bindings_ctx,
4039 device,
4040 frame_dst,
4041 packet,
4042 packet_metadata,
4043 receive_meta,
4044 )
4045 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4046 return;
4047 }
4048 }
4049 drop(filter);
4052
4053 let Some(src_ip) = packet.src_ipv4() else {
4054 core_ctx.increment_both(device, |c| &c.invalid_source);
4055 debug!(
4056 "receive_ipv4_packet: received packet from invalid source {}; dropping",
4057 packet.src_ip()
4058 );
4059 packet_metadata.acknowledge_drop();
4060 return;
4061 };
4062
4063 let action = receive_ipv4_packet_action(
4064 core_ctx,
4065 bindings_ctx,
4066 device,
4067 &packet,
4068 frame_dst,
4069 &packet_metadata.marks,
4070 max_fragment_len,
4071 );
4072 match action {
4073 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
4074 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
4080 clone_packet_for_mcast_forwarding! {
4081 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
4082 };
4083 let SplitMulticastPacketMetadata { primary: this_packet_metadata, secondary } =
4084 packet_metadata.split_for_multicast();
4085 packet_metadata = secondary;
4086 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
4087 core_ctx,
4088 copy_of_packet,
4089 this_packet_metadata,
4090 Some(*min_ttl),
4091 device,
4092 &output_interface,
4093 IpPacketDestination::from_addr(dst_ip),
4094 frame_dst,
4095 src_ip,
4096 dst_ip,
4097 )
4098 .perform_action_with_buffer(
4099 core_ctx,
4100 bindings_ctx,
4101 copy_of_buffer,
4102 max_fragment_len,
4103 );
4104 }
4105
4106 if let Some(address_status) = address_status {
4108 let receive_meta = ReceiveIpPacketMeta {
4109 broadcast: address_status.to_broadcast_marker(),
4110 transparent_override: None,
4111 parsing_context,
4112 };
4113 dispatch_receive_ipv4_packet(
4114 core_ctx,
4115 bindings_ctx,
4116 device,
4117 frame_dst,
4118 packet,
4119 packet_metadata,
4120 receive_meta,
4121 )
4122 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4123 } else {
4124 packet_metadata.acknowledge_drop();
4125 }
4126 }
4127 ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
4128 match internal_forwarding {
4131 InternalForwarding::Used(outbound_device) => {
4132 core_ctx.increment_both(device, |c| &c.forward);
4133 match core_ctx.filter_handler().forwarding_hook(
4134 &mut packet,
4135 device,
4136 &outbound_device,
4137 &mut packet_metadata,
4138 ) {
4139 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
4140 packet_metadata.acknowledge_drop();
4141 return;
4142 }
4143 filter::Verdict::Stop(filter::DropOrReject::Reject(_reject_type)) => {
4144 packet_metadata.acknowledge_drop();
4146 return;
4147 }
4148 filter::Verdict::Proceed(filter::Accept) => {}
4149 }
4150 }
4151 InternalForwarding::NotUsed => {}
4152 }
4153
4154 let receive_meta = ReceiveIpPacketMeta {
4155 broadcast: address_status.to_broadcast_marker(),
4156 transparent_override: None,
4157 parsing_context,
4158 };
4159 dispatch_receive_ipv4_packet(
4160 core_ctx,
4161 bindings_ctx,
4162 device,
4163 frame_dst,
4164 packet,
4165 packet_metadata,
4166 receive_meta,
4167 )
4168 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4169 }
4170 ReceivePacketAction::Forward {
4171 original_dst,
4172 dst: Destination { device: dst_device, next_hop },
4173 } => {
4174 determine_ip_packet_forwarding_action::<Ipv4, _, _>(
4175 core_ctx,
4176 packet,
4177 packet_metadata,
4178 None,
4179 device,
4180 &dst_device,
4181 IpPacketDestination::from_next_hop(next_hop, original_dst),
4182 frame_dst,
4183 src_ip,
4184 original_dst,
4185 )
4186 .perform_action_with_buffer(
4187 core_ctx,
4188 bindings_ctx,
4189 buffer,
4190 max_fragment_len,
4191 );
4192 }
4193 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
4194 debug!("received IPv4 packet with no known route to destination {}", dst_ip);
4195
4196 let marks = packet_metadata.marks;
4197 packet_metadata.acknowledge_drop();
4198
4199 if let Some(sender) = IcmpErrorSender::new(
4200 core_ctx,
4201 Icmpv4Error::NetUnreachable,
4202 &packet,
4203 frame_dst,
4204 device,
4205 marks,
4206 ) {
4207 sender.send(core_ctx, bindings_ctx, buffer);
4208 }
4209 }
4210 ReceivePacketAction::Drop { reason } => {
4211 let src_ip = packet.src_ip();
4212 let dst_ip = packet.dst_ip();
4213 packet_metadata.acknowledge_drop();
4214 core_ctx.increment_both(device, |c| &c.dropped);
4215 debug!(
4216 "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
4217 {device:?}: {reason:?}",
4218 );
4219 }
4220 }
4221}
4222
4223fn handle_ipv6_parse_error<BC, B, CC>(
4224 core_ctx: &mut CC,
4225 bindings_ctx: &mut BC,
4226 device: &CC::DeviceId,
4227 frame_dst: Option<LocalFrameDestination>,
4228 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
4229 mut buffer: B,
4230 error: Ipv6ParseError,
4231) where
4232 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4233 B: BufferMut,
4234 CC: IpLayerIngressContext<Ipv6, BC>,
4235{
4236 let Ipv6ParseError::ParameterProblem { src_ip, dst_ip, code, pointer, must_send_icmp, action } =
4242 error
4243 else {
4244 core_ctx.increment_both(device, |c| &c.unparsable_packet);
4245 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
4246 return;
4247 };
4248 if !must_send_icmp || !action.should_send_icmp(&dst_ip) {
4249 return;
4250 }
4251 core_ctx.increment_both(device, |c| &c.parameter_problem);
4252 let dst_ip = match SocketIpAddr::new(dst_ip) {
4253 Some(ip) => ip,
4254 None => {
4255 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4256 debug!("receive_ipv6_packet: Dropping packet with unspecified destination IP");
4257 return;
4258 }
4259 };
4260
4261 let src_ip = match Ipv6SourceAddr::new(src_ip) {
4262 None => {
4263 core_ctx.increment_both(device, |c| &c.invalid_source);
4264 return;
4265 }
4266 Some(Ipv6SourceAddr::Unspecified) => {
4267 core_ctx.increment_both(device, |c| &c.unspecified_source);
4268 return;
4269 }
4270 Some(Ipv6SourceAddr::Unicast(src_ip)) => {
4271 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
4272 }
4273 };
4274
4275 let raw_packet: Ipv6PacketRaw<_> = match try_parse_ip_packet!(buffer) {
4278 Ok(packet) => packet,
4279 Err(error) => {
4280 core_ctx.increment_both(device, |c| &c.unparsable_packet);
4281 debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
4282 return;
4283 }
4284 };
4285 let proto = match raw_packet.proto() {
4286 Ok(proto) => proto,
4287 Err(error) => {
4288 core_ctx.increment_both(device, |c| &c.unparsable_packet);
4289 debug!("receive_ipv6_packet: Failed to get protocol from IPv6 packet: {:?}", error);
4290 return;
4291 }
4292 };
4293 let parse_metadata = raw_packet.parse_metadata();
4294 let header_len = parse_metadata.header_len();
4295 buffer.undo_parse(parse_metadata);
4296
4297 let err = Icmpv6Error::ParameterProblem {
4298 code,
4299 pointer,
4300 allow_dst_multicast: action.should_send_icmp_to_multicast(),
4301 };
4302
4303 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
4304 core_ctx,
4305 bindings_ctx,
4306 Some(device),
4307 frame_dst,
4308 src_ip,
4309 dst_ip,
4310 buffer,
4311 err,
4312 header_len,
4313 proto,
4314 &device_ip_layer_metadata.marks,
4315 );
4316}
4317
4318pub fn receive_ipv6_packet<
4323 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4324 B: BufferMut,
4325 CC: IpLayerIngressContext<Ipv6, BC>,
4326>(
4327 core_ctx: &mut CC,
4328 bindings_ctx: &mut BC,
4329 device: &CC::DeviceId,
4330 frame_dst: Option<LocalFrameDestination>,
4331 device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
4332 parsing_context: NetworkParsingContext,
4333 gso_info: Option<GsoInfo>,
4334 buffer: B,
4335) {
4336 if !core_ctx.is_ip_device_enabled(&device) {
4337 return;
4338 }
4339
4340 let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
4343
4344 core_ctx.increment_both(device, |c| &c.receive_ip_packet);
4345 trace!("receive_ipv6_packet({:?})", device);
4346
4347 let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
4348 Ok(packet) => packet,
4349 Err(error) => {
4350 handle_ipv6_parse_error(
4351 core_ctx,
4352 bindings_ctx,
4353 device,
4354 frame_dst,
4355 device_ip_layer_metadata,
4356 buffer,
4357 error,
4358 );
4359 return;
4360 }
4361 };
4362
4363 trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
4364
4365 if packet.src_ipv6().is_none() {
4371 debug!(
4372 "receive_ipv6_packet: received packet from invalid source {}; dropping",
4373 packet.src_ip()
4374 );
4375 core_ctx.increment_both(device, |c| &c.invalid_source);
4376 return;
4377 };
4378 if !packet.dst_ip().is_specified() {
4379 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4380 debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
4381 return;
4382 };
4383
4384 if !device.is_loopback()
4392 && (Ipv6::LOOPBACK_SUBNET.contains(&packet.src_ip())
4393 || Ipv6::LOOPBACK_SUBNET.contains(&packet.dst_ip()))
4394 {
4395 debug!(
4396 "receive_ipv6_packet: received loopback packet (src={}, dst={}) \
4397 on non-loopback interface; dropping",
4398 packet.src_ip(),
4399 packet.dst_ip(),
4400 );
4401 return;
4402 }
4403
4404 let (mut packet, delivery_extension_header_action, max_fragment_len) =
4415 match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
4416 Ipv6PacketAction::_Discard => {
4417 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4418 trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
4419 return;
4420 }
4421 Ipv6PacketAction::Continue => {
4422 trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
4423 (packet, Some(Ipv6PacketAction::Continue), None)
4424 }
4425 Ipv6PacketAction::ProcessFragment => {
4426 trace!(
4427 "receive_ipv6_packet: handled IPv6 extension headers: handling \
4428 fragmented packet"
4429 );
4430
4431 let (buf, max_fragment_len) =
4443 match process_fragment(core_ctx, bindings_ctx, device, packet) {
4444 ProcessFragmentResult::Done => return,
4445 ProcessFragmentResult::NotNeeded(packet) => {
4446 match reassemble_ipv6_atomic_fragment(&packet) {
4454 Ok(result) => result,
4455 Err(err) => {
4456 core_ctx
4457 .increment_both(device, |c| &c.fragment_reassembly_error);
4458 debug!(
4459 "receive_ip_packet: failed to reassemble atomic \
4460 fragment: {:?}",
4461 err
4462 );
4463 return;
4464 }
4465 }
4466 }
4467 ProcessFragmentResult::Reassembled { buffer: buf, max_fragment_len } => {
4468 (buf, max_fragment_len)
4469 }
4470 };
4471
4472 let buf = Buf::new(buf, ..);
4473 buffer = packet::Either::B(buf);
4474
4475 match try_parse_ip_packet!(buffer) {
4479 Ok(packet) => {
4480 let packet: Ipv6Packet<_> = packet;
4481 if packet
4484 .iter_extension_hdrs()
4485 .any(|h| matches!(h, Ipv6ExtensionHeader::Fragment { .. }))
4486 {
4487 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4488 debug!(
4489 "receive_ipv6_packet: found fragment header after reassembly; \
4490 dropping"
4491 );
4492 return;
4493 }
4494 (packet, None, Some(max_fragment_len))
4495 }
4496 Err(error) => {
4497 core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4498 debug!(
4499 "receive_ip_packet: fragmented, failed to parse reassembled packet: \
4500 {:?}",
4501 error
4502 );
4503 handle_ipv6_parse_error(
4504 core_ctx,
4505 bindings_ctx,
4506 device,
4507 frame_dst,
4508 device_ip_layer_metadata,
4509 buffer,
4510 error,
4511 );
4512 return;
4513 }
4514 }
4515 }
4516 };
4517
4518 let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
4519 core_ctx,
4520 device,
4521 device_ip_layer_metadata,
4522 gso_info,
4523 );
4524 let mut filter = core_ctx.filter_handler();
4525
4526 match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
4527 filter::Verdict::Proceed(filter::Accept) => {}
4528 filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
4529 packet_metadata.acknowledge_drop();
4530 return;
4531 }
4532 filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
4533 addr,
4534 port,
4535 }) => {
4536 drop(filter);
4539
4540 let Some(addr) = SpecifiedAddr::new(addr) else {
4541 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4542 debug!("cannot perform transparent delivery to unspecified destination; dropping");
4543 packet_metadata.acknowledge_drop();
4544 return;
4545 };
4546
4547 let receive_meta = ReceiveIpPacketMeta {
4548 broadcast: None,
4549 transparent_override: Some(TransparentLocalDelivery { addr, port }),
4550 parsing_context,
4551 };
4552
4553 dispatch_receive_ipv6_packet(
4557 core_ctx,
4558 bindings_ctx,
4559 device,
4560 frame_dst,
4561 packet,
4562 packet_metadata,
4563 receive_meta,
4564 )
4565 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4566 return;
4567 }
4568 }
4569 drop(filter);
4572
4573 let Some(src_ip) = packet.src_ipv6() else {
4574 debug!(
4575 "receive_ipv6_packet: received packet from invalid source {}; dropping",
4576 packet.src_ip()
4577 );
4578 core_ctx.increment_both(device, |c| &c.invalid_source);
4579 packet_metadata.acknowledge_drop();
4580 return;
4581 };
4582
4583 match receive_ipv6_packet_action(
4584 core_ctx,
4585 bindings_ctx,
4586 device,
4587 &packet,
4588 frame_dst,
4589 &packet_metadata.marks,
4590 max_fragment_len,
4591 ) {
4592 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
4593 for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
4599 clone_packet_for_mcast_forwarding! {
4600 let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
4601 };
4602 let SplitMulticastPacketMetadata { primary: this_packet_metadata, secondary } =
4603 packet_metadata.split_for_multicast();
4604 packet_metadata = secondary;
4605 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4606 core_ctx,
4607 copy_of_packet,
4608 this_packet_metadata,
4609 Some(*min_ttl),
4610 device,
4611 &output_interface,
4612 IpPacketDestination::from_addr(dst_ip),
4613 frame_dst,
4614 src_ip,
4615 dst_ip,
4616 )
4617 .perform_action_with_buffer(
4618 core_ctx,
4619 bindings_ctx,
4620 copy_of_buffer,
4621 max_fragment_len,
4622 );
4623 }
4624
4625 if let Some(_) = address_status {
4627 let receive_meta = ReceiveIpPacketMeta {
4628 broadcast: None,
4629 transparent_override: None,
4630 parsing_context,
4631 };
4632
4633 dispatch_receive_ipv6_packet(
4634 core_ctx,
4635 bindings_ctx,
4636 device,
4637 frame_dst,
4638 packet,
4639 packet_metadata,
4640 receive_meta,
4641 )
4642 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4643 } else {
4644 packet_metadata.acknowledge_drop();
4645 }
4646 }
4647 ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
4648 trace!("receive_ipv6_packet: delivering locally");
4649
4650 let action = if let Some(action) = delivery_extension_header_action {
4651 action
4652 } else {
4653 ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
4654 };
4655 match action {
4656 Ipv6PacketAction::_Discard => {
4657 core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4658 trace!(
4659 "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
4660 );
4661 packet_metadata.acknowledge_drop();
4662 }
4663 Ipv6PacketAction::Continue => {
4664 trace!(
4665 "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
4666 );
4667
4668 match internal_forwarding {
4671 InternalForwarding::Used(outbound_device) => {
4672 core_ctx.increment_both(device, |c| &c.forward);
4673 match core_ctx.filter_handler().forwarding_hook(
4674 &mut packet,
4675 device,
4676 &outbound_device,
4677 &mut packet_metadata,
4678 ) {
4679 filter::Verdict::Stop(filter::DropOrReject::Drop) => {
4680 packet_metadata.acknowledge_drop();
4681 return;
4682 }
4683 filter::Verdict::Stop(filter::DropOrReject::Reject(
4684 _reject_type,
4685 )) => {
4686 packet_metadata.acknowledge_drop();
4688 return;
4689 }
4690 filter::Verdict::Proceed(filter::Accept) => {}
4691 }
4692 }
4693 InternalForwarding::NotUsed => {}
4694 }
4695
4696 let meta = ReceiveIpPacketMeta {
4697 broadcast: None,
4698 transparent_override: None,
4699 parsing_context,
4700 };
4701 dispatch_receive_ipv6_packet(
4702 core_ctx,
4703 bindings_ctx,
4704 device,
4705 frame_dst,
4706 packet,
4707 packet_metadata,
4708 meta,
4709 )
4710 .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4711 }
4712 Ipv6PacketAction::ProcessFragment => {
4713 unreachable!("found fragment header after reassembly")
4716 }
4717 }
4718 }
4719 ReceivePacketAction::Forward {
4720 original_dst,
4721 dst: Destination { device: dst_device, next_hop },
4722 } => {
4723 determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4724 core_ctx,
4725 packet,
4726 packet_metadata,
4727 None,
4728 device,
4729 &dst_device,
4730 IpPacketDestination::from_next_hop(next_hop, original_dst),
4731 frame_dst,
4732 src_ip,
4733 original_dst,
4734 )
4735 .perform_action_with_buffer(
4736 core_ctx,
4737 bindings_ctx,
4738 buffer,
4739 max_fragment_len,
4740 );
4741 }
4742 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
4743 let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
4744 drop_packet_and_undo_parse!(packet, buffer);
4745 debug!("received IPv6 packet with no known route to destination {}", dst_ip);
4746 let marks = packet_metadata.marks;
4747 packet_metadata.acknowledge_drop();
4748
4749 let src_ip = match src_ip {
4750 Ipv6SourceAddr::Unspecified => {
4751 core_ctx.increment_both(device, |c| &c.unspecified_source);
4752 return;
4753 }
4754 Ipv6SourceAddr::Unicast(src_ip) => {
4755 SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
4756 }
4757 };
4758
4759 IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
4760 core_ctx,
4761 bindings_ctx,
4762 Some(device),
4763 frame_dst,
4764 src_ip,
4765 SocketIpAddr::new_from_witness(dst_ip),
4766 buffer,
4767 Icmpv6Error::NetUnreachable,
4768 meta.header_len(),
4769 proto,
4770 &marks,
4771 );
4772 }
4773 ReceivePacketAction::Drop { reason } => {
4774 core_ctx.increment_both(device, |c| &c.dropped);
4775 let src_ip = packet.src_ip();
4776 let dst_ip = packet.dst_ip();
4777 packet_metadata.acknowledge_drop();
4778 debug!(
4779 "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
4780 {device:?}: {reason:?}",
4781 );
4782 }
4783 }
4784}
4785
4786#[derive(Debug, PartialEq)]
4788pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
4789 Deliver {
4791 address_status: I::AddressStatus,
4793 internal_forwarding: InternalForwarding<DeviceId>,
4796 },
4797
4798 Forward {
4800 original_dst: SpecifiedAddr<I::Addr>,
4802 dst: Destination<I::Addr, DeviceId>,
4804 },
4805
4806 MulticastForward {
4814 targets: MulticastRouteTargets<DeviceId>,
4816 address_status: Option<I::AddressStatus>,
4819 dst_ip: SpecifiedAddr<I::Addr>,
4821 },
4822
4823 SendNoRouteToDest {
4829 dst: NonMappedAddr<SpecifiedAddr<I::Addr>>,
4831 },
4832
4833 #[allow(missing_docs)]
4837 Drop { reason: DropReason },
4838}
4839
4840fn choose_highest_priority_address_status<I: IpLayerIpExt>(
4843 address_statuses: impl Iterator<Item = I::AddressStatus>,
4844) -> Option<I::AddressStatus> {
4845 address_statuses.max_by_key(|status| {
4846 #[derive(GenericOverIp)]
4847 #[generic_over_ip(I, Ip)]
4848 struct Wrap<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
4849 I::map_ip_in(
4850 Wrap(status),
4851 |Wrap(v4_status)| match v4_status {
4852 Ipv4PresentAddressStatus::UnicastTentative => 0,
4853 _ => 1,
4854 },
4855 |Wrap(v6_status)| match v6_status {
4856 Ipv6PresentAddressStatus::UnicastTentative => 0,
4857 _ => 1,
4858 },
4859 )
4860 })
4861}
4862
4863#[derive(Debug, PartialEq)]
4865pub enum DropReason {
4866 Tentative,
4868 UnspecifiedDestination,
4870 InvalidDestination,
4872 ForwardUnspecifiedSource,
4874 ForwardLinkLocal,
4876 ForwardingDisabledInboundIface,
4879 MulticastNoInterest,
4885}
4886
4887pub fn receive_ipv4_packet_action<BC, CC, B>(
4889 core_ctx: &mut CC,
4890 bindings_ctx: &mut BC,
4891 device: &CC::DeviceId,
4892 packet: &Ipv4Packet<B>,
4893 frame_dst: Option<LocalFrameDestination>,
4894 marks: &Marks,
4895 max_fragment_len: Option<usize>,
4896) -> ReceivePacketAction<Ipv4, CC::DeviceId>
4897where
4898 BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
4899 CC: IpLayerContext<Ipv4, BC>,
4900 B: SplitByteSlice,
4901{
4902 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4903 core_ctx.increment_both(device, |c| &c.unspecified_destination);
4904 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4905 };
4906
4907 let highest_priority = if device.is_loopback() {
4920 core_ctx.with_address_statuses(dst_ip, |it| {
4921 let it = it.map(|(_device, status)| status);
4922 choose_highest_priority_address_status::<Ipv4>(it)
4923 })
4924 } else {
4925 core_ctx.address_status_for_device(dst_ip, device).into_present()
4926 };
4927 match highest_priority {
4928 Some(
4929 address_status @ (Ipv4PresentAddressStatus::UnicastAssigned
4930 | Ipv4PresentAddressStatus::LoopbackSubnet),
4931 ) => {
4932 core_ctx.increment_both(device, |c| &c.deliver_unicast);
4933 ReceivePacketAction::Deliver {
4934 address_status,
4935 internal_forwarding: InternalForwarding::NotUsed,
4936 }
4937 }
4938 Some(Ipv4PresentAddressStatus::UnicastTentative) => {
4939 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4945 ReceivePacketAction::Drop { reason: DropReason::Tentative }
4946 }
4947
4948 Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4949 receive_ip_multicast_packet_action(
4950 core_ctx,
4951 bindings_ctx,
4952 device,
4953 packet,
4954 Some(address_status),
4955 dst_ip,
4956 frame_dst,
4957 *marks,
4958 max_fragment_len,
4959 )
4960 }
4961 Some(
4962 address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4963 | Ipv4PresentAddressStatus::SubnetBroadcast),
4964 ) => {
4965 core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
4966 ReceivePacketAction::Deliver {
4967 address_status,
4968 internal_forwarding: InternalForwarding::NotUsed,
4969 }
4970 }
4971 None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4972 core_ctx,
4973 bindings_ctx,
4974 dst_ip,
4975 device,
4976 packet,
4977 frame_dst,
4978 marks,
4979 max_fragment_len,
4980 ),
4981 }
4982}
4983
4984pub fn receive_ipv6_packet_action<BC, CC, B>(
4986 core_ctx: &mut CC,
4987 bindings_ctx: &mut BC,
4988 device: &CC::DeviceId,
4989 packet: &Ipv6Packet<B>,
4990 frame_dst: Option<LocalFrameDestination>,
4991 marks: &Marks,
4992 max_fragment_len: Option<usize>,
4993) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4994where
4995 BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4996 CC: IpLayerContext<Ipv6, BC>,
4997 B: SplitByteSlice,
4998{
4999 let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
5000 core_ctx.increment_both(device, |c| &c.unspecified_destination);
5001 return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
5002 };
5003
5004 let highest_priority = if device.is_loopback() {
5017 core_ctx.with_address_statuses(dst_ip, |it| {
5018 let it = it.map(|(_device, status)| status);
5019 choose_highest_priority_address_status::<Ipv6>(it)
5020 })
5021 } else {
5022 core_ctx.address_status_for_device(dst_ip, device).into_present()
5023 };
5024 match highest_priority {
5025 Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
5026 receive_ip_multicast_packet_action(
5027 core_ctx,
5028 bindings_ctx,
5029 device,
5030 packet,
5031 Some(address_status),
5032 dst_ip,
5033 frame_dst,
5034 *marks,
5035 max_fragment_len,
5036 )
5037 }
5038 Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
5039 core_ctx.increment_both(device, |c| &c.deliver_unicast);
5040 ReceivePacketAction::Deliver {
5041 address_status,
5042 internal_forwarding: InternalForwarding::NotUsed,
5043 }
5044 }
5045 Some(Ipv6PresentAddressStatus::UnicastTentative) => {
5046 core_ctx.increment_both(device, |c| &c.drop_for_tentative);
5077 ReceivePacketAction::Drop { reason: DropReason::Tentative }
5078 }
5079 None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
5080 core_ctx,
5081 bindings_ctx,
5082 dst_ip,
5083 device,
5084 packet,
5085 frame_dst,
5086 marks,
5087 max_fragment_len,
5088 ),
5089 }
5090}
5091
5092fn receive_ip_multicast_packet_action<
5095 I: IpLayerIpExt,
5096 B: SplitByteSlice,
5097 BC: IpLayerBindingsContext<I, CC::DeviceId>,
5098 CC: IpLayerContext<I, BC>,
5099>(
5100 core_ctx: &mut CC,
5101 bindings_ctx: &mut BC,
5102 device: &CC::DeviceId,
5103 packet: &I::Packet<B>,
5104 address_status: Option<I::AddressStatus>,
5105 dst_ip: SpecifiedAddr<I::Addr>,
5106 frame_dst: Option<LocalFrameDestination>,
5107 marks: Marks,
5108 max_fragment_len: Option<usize>,
5109) -> ReceivePacketAction<I, CC::DeviceId> {
5110 let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
5111 core_ctx,
5112 bindings_ctx,
5113 packet,
5114 device,
5115 frame_dst,
5116 max_fragment_len,
5117 marks,
5118 );
5119 match (targets, address_status) {
5120 (Some(targets), address_status) => {
5121 if address_status.is_some() {
5122 core_ctx.increment_both(device, |c| &c.deliver_multicast);
5123 }
5124 ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
5125 }
5126 (None, Some(address_status)) => {
5127 core_ctx.increment_both(device, |c| &c.deliver_multicast);
5130 ReceivePacketAction::Deliver {
5131 address_status,
5132 internal_forwarding: InternalForwarding::NotUsed,
5133 }
5134 }
5135 (None, None) => {
5136 core_ctx.increment_both(device, |c| &c.multicast_no_interest);
5145 ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
5146 }
5147 }
5148}
5149
5150fn receive_ip_packet_action_common<
5153 I: IpLayerIpExt,
5154 B: SplitByteSlice,
5155 BC: IpLayerBindingsContext<I, CC::DeviceId>,
5156 CC: IpLayerContext<I, BC>,
5157>(
5158 core_ctx: &mut CC,
5159 bindings_ctx: &mut BC,
5160 dst_ip: SpecifiedAddr<I::Addr>,
5161 device_id: &CC::DeviceId,
5162 packet: &I::Packet<B>,
5163 frame_dst: Option<LocalFrameDestination>,
5164 marks: &Marks,
5165 max_fragment_len: Option<usize>,
5166) -> ReceivePacketAction<I, CC::DeviceId> {
5167 if dst_ip.is_multicast() {
5168 return receive_ip_multicast_packet_action(
5169 core_ctx,
5170 bindings_ctx,
5171 device_id,
5172 packet,
5173 None,
5174 dst_ip,
5175 frame_dst,
5176 *marks,
5177 max_fragment_len,
5178 );
5179 }
5180
5181 let Some(dst_ip) = NonMappedAddr::new(dst_ip) else {
5183 return ReceivePacketAction::Drop { reason: DropReason::InvalidDestination };
5184 };
5185
5186 if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
5188 core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
5201 return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
5202 }
5203 let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
5210 return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
5211 };
5212
5213 if let Some(dst_ip) = NonMulticastAddr::new(dst_ip) {
5220 if let Some((outbound_device, address_status)) =
5221 get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
5222 {
5223 return ReceivePacketAction::Deliver {
5224 address_status,
5225 internal_forwarding: InternalForwarding::Used(outbound_device),
5226 };
5227 }
5228 }
5229
5230 if I::map_ip_in(
5245 &packet,
5246 |_| false,
5247 |packet| packet.src_ip().is_link_local() || packet.dst_ip().is_link_local(),
5248 ) {
5249 return ReceivePacketAction::Drop { reason: DropReason::ForwardLinkLocal };
5250 }
5251
5252 match lookup_route_table(
5253 core_ctx,
5254 dst_ip.get(),
5255 RuleInput {
5256 packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
5257 marks,
5258 },
5259 ) {
5260 Some(dst) => {
5261 core_ctx.increment_both(device_id, |c| &c.forward);
5262 ReceivePacketAction::Forward { original_dst: *dst_ip, dst }
5263 }
5264 None => {
5265 core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
5266 ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
5267 }
5268 }
5269}
5270
5271fn lookup_route_table<
5273 I: IpLayerIpExt,
5274 BC: IpLayerBindingsContext<I, CC::DeviceId>,
5275 CC: IpStateContext<I, BC>,
5276>(
5277 core_ctx: &mut CC,
5278 dst_ip: I::Addr,
5279 rule_input: RuleInput<'_, I, CC::DeviceId>,
5280) -> Option<Destination<I::Addr, CC::DeviceId>> {
5281 let bound_device = match rule_input.packet_origin {
5282 PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
5283 PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
5284 };
5285 core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
5286 match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
5287 match table.lookup(core_ctx, bound_device, dst_ip) {
5288 Some(dst) => ControlFlow::Break(Some(dst)),
5289 None => ControlFlow::Continue(()),
5290 }
5291 }) {
5292 ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
5293 inner: dst,
5294 observed_source_address_matcher: _,
5295 })) => dst,
5296 ControlFlow::Break(RuleAction::Unreachable) => None,
5297 ControlFlow::Continue(RuleWalkInfo {
5298 inner: (),
5299 observed_source_address_matcher: _,
5300 }) => None,
5301 }
5302 })
5303}
5304
5305#[derive(Debug, Derivative, Clone)]
5307#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
5308pub enum IpPacketDestination<I: BroadcastIpExt, D> {
5309 Broadcast(I::BroadcastMarker),
5311
5312 Multicast(MulticastAddr<I::Addr>),
5314
5315 Neighbor(SpecifiedAddr<I::Addr>),
5318
5319 Loopback(D),
5322}
5323
5324impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
5325 pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
5327 match MulticastAddr::new(addr.into_addr()) {
5328 Some(mc_addr) => Self::Multicast(mc_addr),
5329 None => Self::Neighbor(addr),
5330 }
5331 }
5332
5333 pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
5335 match next_hop {
5336 NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
5337 NextHop::Gateway(gateway) => Self::Neighbor(gateway),
5338 NextHop::Broadcast(marker) => Self::Broadcast(marker),
5339 }
5340 }
5341}
5342
5343#[derive(Debug, Clone)]
5345pub struct SendIpPacketMeta<I: IpExt, D, Src> {
5346 pub device: D,
5348
5349 pub src_ip: Src,
5351
5352 pub dst_ip: SpecifiedAddr<I::Addr>,
5354
5355 pub destination: IpPacketDestination<I, D>,
5357
5358 pub proto: I::Proto,
5360
5361 pub ttl: Option<NonZeroU8>,
5365
5366 pub mtu: Mtu,
5371
5372 pub dscp_and_ecn: DscpAndEcn,
5374}
5375
5376impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5377 for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
5378{
5379 fn from(
5380 SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
5381 I,
5382 D,
5383 SpecifiedAddr<I::Addr>,
5384 >,
5385 ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
5386 SendIpPacketMeta {
5387 device,
5388 src_ip: Some(src_ip),
5389 dst_ip,
5390 destination,
5391 proto,
5392 ttl,
5393 mtu,
5394 dscp_and_ecn,
5395 }
5396 }
5397}
5398
5399pub trait IpLayerHandler<I: IpExt + FragmentationIpExt + GsoIpExt + FilterIpExt, BC>:
5405 DeviceIdContext<AnyDevice>
5406{
5407 fn send_ip_packet_from_device<S>(
5410 &mut self,
5411 bindings_ctx: &mut BC,
5412 meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
5413 body: S,
5414 ) -> Result<(), IpSendFrameError<S>>
5415 where
5416 S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
5417 S::Buffer: BufferMut;
5418
5419 fn send_ip_frame<S>(
5426 &mut self,
5427 bindings_ctx: &mut BC,
5428 device: &Self::DeviceId,
5429 destination: IpPacketDestination<I, &Self::DeviceId>,
5430 body: S,
5431 ) -> Result<(), IpSendFrameError<S>>
5432 where
5433 S: FragmentableIpSerializer<I, Buffer: BufferMut>
5434 + MaybeSegmentableIpSerializer<I>
5435 + FilterIpPacket<I>;
5436}
5437
5438impl<I, BC, CC> IpLayerHandler<I, BC> for CC
5439where
5440 I: IpLayerIpExt,
5441 BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
5442 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
5443{
5444 fn send_ip_packet_from_device<S>(
5445 &mut self,
5446 bindings_ctx: &mut BC,
5447 meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
5448 body: S,
5449 ) -> Result<(), IpSendFrameError<S>>
5450 where
5451 S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
5452 S::Buffer: BufferMut,
5453 {
5454 send_ip_packet_from_device(
5455 self,
5456 bindings_ctx,
5457 meta,
5458 body,
5459 IpLayerPacketMetadata::new_local_tx(Default::default(), Default::default(), None),
5460 )
5461 }
5462
5463 fn send_ip_frame<S>(
5464 &mut self,
5465 bindings_ctx: &mut BC,
5466 device: &Self::DeviceId,
5467 destination: IpPacketDestination<I, &Self::DeviceId>,
5468 body: S,
5469 ) -> Result<(), IpSendFrameError<S>>
5470 where
5471 S: FragmentableIpSerializer<I, Buffer: BufferMut>
5472 + MaybeSegmentableIpSerializer<I>
5473 + FilterIpPacket<I>,
5474 {
5475 send_ip_frame(
5476 self,
5477 bindings_ctx,
5478 device,
5479 destination,
5480 body,
5481 IpLayerPacketMetadata::new_local_tx(Default::default(), Default::default(), None),
5482 Mtu::no_limit(),
5483 )
5484 }
5485}
5486
5487pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
5494 core_ctx: &mut CC,
5495 bindings_ctx: &mut BC,
5496 meta: SendIpPacketMeta<
5497 I,
5498 &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
5499 Option<SpecifiedAddr<I::Addr>>,
5500 >,
5501 body: S,
5502 packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
5503) -> Result<(), IpSendFrameError<S>>
5504where
5505 I: IpLayerIpExt,
5506 BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
5507 CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
5508 S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
5509 S::Buffer: BufferMut,
5510{
5511 let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
5512 meta;
5513 core_ctx.increment_both(device, |c| &c.send_ip_packet);
5514 let next_packet_id = gen_ip_packet_id(core_ctx);
5515 let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
5516 let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
5517 let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
5518
5519 #[derive(GenericOverIp)]
5520 #[generic_over_ip(I, Ip)]
5521 struct Wrap<'a, I: IpLayerIpExt> {
5522 builder: &'a mut I::PacketBuilder<NetworkSerializationContext>,
5523 next_packet_id: I::PacketId,
5524 }
5525
5526 I::map_ip::<_, ()>(
5527 Wrap { builder: &mut builder, next_packet_id },
5528 |Wrap { builder, next_packet_id }| {
5529 builder.id(next_packet_id);
5530 },
5531 |Wrap { builder: _, next_packet_id: () }| {
5532 },
5534 );
5535
5536 builder.set_dscp_and_ecn(dscp_and_ecn);
5537
5538 let ip_frame = builder.wrap_body(body);
5539 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
5540 .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
5541}
5542
5543pub trait FilterHandlerProvider<I: FilterIpExt, BT: FilterBindingsTypes>:
5545 IpDeviceAddressIdContext<I, DeviceId: netstack3_base::InterfaceProperties<BT::DeviceClass>>
5546{
5547 type Handler<'a>: filter::FilterHandler<I, BT, DeviceId = Self::DeviceId, WeakAddressId = Self::WeakAddressId>
5549 where
5550 Self: 'a;
5551
5552 fn filter_handler(&mut self) -> Self::Handler<'_>;
5554}
5555
5556#[cfg(any(test, feature = "testutils"))]
5557pub(crate) mod testutil {
5558 use super::*;
5559
5560 use netstack3_base::testutil::{FakeBindingsCtx, FakeCoreCtx, FakeStrongDeviceId};
5561 use netstack3_base::{
5562 AssignedAddrIpExt, NetworkSerializer, SendFrameContext, SendFrameError, SendableFrameMeta,
5563 };
5564
5565 #[derive(Debug, GenericOverIp)]
5567 #[generic_over_ip()]
5568 #[allow(missing_docs)]
5569 pub enum DualStackSendIpPacketMeta<D> {
5570 V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
5571 V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
5572 }
5573
5574 impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5575 for DualStackSendIpPacketMeta<D>
5576 {
5577 fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
5578 #[derive(GenericOverIp)]
5579 #[generic_over_ip(I, Ip)]
5580 struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
5581 use DualStackSendIpPacketMeta::*;
5582 I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
5583 }
5584 }
5585
5586 impl<I: IpExt, S, DeviceId, BC>
5587 SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
5588 for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
5589 {
5590 fn send_meta<SS>(
5591 self,
5592 core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
5593 bindings_ctx: &mut BC,
5594 frame: SS,
5595 ) -> Result<(), SendFrameError<SS>>
5596 where
5597 SS: NetworkSerializer,
5598 SS::Buffer: BufferMut,
5599 {
5600 SendFrameContext::send_frame(
5601 &mut core_ctx.frames,
5602 bindings_ctx,
5603 DualStackSendIpPacketMeta::from(self),
5604 frame,
5605 )
5606 }
5607 }
5608
5609 #[derive(Debug)]
5611 pub struct WrongIpVersion;
5612
5613 impl<D> DualStackSendIpPacketMeta<D> {
5614 pub fn try_as<I: IpExt>(
5617 &self,
5618 ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
5619 #[derive(GenericOverIp)]
5620 #[generic_over_ip(I, Ip)]
5621 struct Wrap<'a, I: IpExt, D>(
5622 Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
5623 );
5624 use DualStackSendIpPacketMeta::*;
5625 let Wrap(dual_stack) = I::map_ip(
5626 self,
5627 |value| {
5628 Wrap(match value {
5629 V4(meta) => Some(meta),
5630 V6(_) => None,
5631 })
5632 },
5633 |value| {
5634 Wrap(match value {
5635 V4(_) => None,
5636 V6(meta) => Some(meta),
5637 })
5638 },
5639 );
5640 dual_stack.ok_or(WrongIpVersion)
5641 }
5642 }
5643
5644 impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
5645 where
5646 I: AssignedAddrIpExt + FilterIpExt,
5647 BC: FilterBindingsContext<DeviceId>,
5648 DeviceId: FakeStrongDeviceId + netstack3_base::InterfaceProperties<BC::DeviceClass>,
5649 {
5650 type Handler<'a>
5651 = filter::testutil::NoopImpl<DeviceId>
5652 where
5653 Self: 'a;
5654
5655 fn filter_handler(&mut self) -> Self::Handler<'_> {
5656 filter::testutil::NoopImpl::default()
5657 }
5658 }
5659
5660 impl<TimerId, Event: Debug, State, FrameMeta> MarksBindingsContext
5661 for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
5662 {
5663 fn marks_to_keep_on_egress() -> &'static [MarkDomain] {
5664 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark1];
5665 &MARKS
5666 }
5667
5668 fn marks_to_set_on_ingress() -> &'static [MarkDomain] {
5669 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark2];
5670 &MARKS
5671 }
5672 }
5673}
5674
5675#[cfg(test)]
5676mod test {
5677 use super::*;
5678
5679 #[test]
5680 fn highest_priority_address_status_v4() {
5681 assert_eq!(
5683 choose_highest_priority_address_status::<Ipv4>(
5684 [
5685 Ipv4PresentAddressStatus::UnicastAssigned,
5686 Ipv4PresentAddressStatus::UnicastTentative
5687 ]
5688 .into_iter()
5689 ),
5690 Some(Ipv4PresentAddressStatus::UnicastAssigned)
5691 )
5692 }
5693
5694 #[test]
5695 fn highest_priority_address_status_v6() {
5696 assert_eq!(
5698 choose_highest_priority_address_status::<Ipv6>(
5699 [
5700 Ipv6PresentAddressStatus::UnicastAssigned,
5701 Ipv6PresentAddressStatus::UnicastTentative
5702 ]
5703 .into_iter()
5704 ),
5705 Some(Ipv6PresentAddressStatus::UnicastAssigned)
5706 )
5707 }
5708}