From fd758773d831e0f439551cb4ea44c76cb5a244a0 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Fri, 2 Aug 2024 10:43:47 +0200 Subject: [PATCH 1/3] Reset expiry of entries in the neighbor cache on packet reception --- src/iface/interface/ipv4.rs | 4 ++++ src/iface/interface/ipv6.rs | 4 ++++ src/iface/neighbor.rs | 10 ++++++++++ 3 files changed, 18 insertions(+) diff --git a/src/iface/interface/ipv4.rs b/src/iface/interface/ipv4.rs index 3a5a864ee..84b265c5e 100644 --- a/src/iface/interface/ipv4.rs +++ b/src/iface/interface/ipv4.rs @@ -196,6 +196,10 @@ impl InterfaceInner { } } + #[cfg(feature = "medium-ethernet")] + self.neighbor_cache + .reset_expiry_if_existing(IpAddress::Ipv4(ipv4_repr.src_addr), self.now); + match ipv4_repr.next_header { IpProtocol::Icmp => self.process_icmpv4(sockets, ipv4_repr, ip_payload), diff --git a/src/iface/interface/ipv6.rs b/src/iface/interface/ipv6.rs index a72492bb2..28c446304 100644 --- a/src/iface/interface/ipv6.rs +++ b/src/iface/interface/ipv6.rs @@ -228,6 +228,10 @@ impl InterfaceInner { #[cfg(not(feature = "socket-raw"))] let handled_by_raw_socket = false; + #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))] + self.neighbor_cache + .reset_expiry_if_existing(IpAddress::Ipv6(ipv6_repr.src_addr), self.now); + self.process_nxt_hdr( sockets, meta, diff --git a/src/iface/neighbor.rs b/src/iface/neighbor.rs index 8fa1d7d5d..543d78c98 100644 --- a/src/iface/neighbor.rs +++ b/src/iface/neighbor.rs @@ -63,6 +63,16 @@ impl Cache { } } + pub fn reset_expiry_if_existing(&mut self, protocol_addr: IpAddress, timestamp: Instant) { + if let Some(Neighbor { + expires_at, + hardware_addr: _, + }) = self.storage.get_mut(&protocol_addr) + { + *expires_at = timestamp + Self::ENTRY_LIFETIME; + } + } + pub fn fill( &mut self, protocol_addr: IpAddress, From a11428dfc9ce29be7ae7eb2d7330049062ff23dc Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Fri, 2 Aug 2024 15:30:59 +0200 Subject: [PATCH 2/3] Updated based on dirbaio's comments - Check for unicast destination - Source IP matches cache - Source hardware address matches cache --- src/iface/interface/ethernet.rs | 12 +++++++++--- src/iface/interface/ipv4.rs | 10 ++++++++-- src/iface/interface/ipv6.rs | 10 ++++++++-- src/iface/interface/mod.rs | 4 ++-- src/iface/interface/sixlowpan.rs | 10 +++++++++- src/iface/interface/tests/ipv4.rs | 5 +++++ src/iface/interface/tests/ipv6.rs | 15 +++++++++++++++ src/iface/neighbor.rs | 13 ++++++++++--- src/wire/mod.rs | 24 ++++++++++++++++++++++++ 9 files changed, 90 insertions(+), 13 deletions(-) diff --git a/src/iface/interface/ethernet.rs b/src/iface/interface/ethernet.rs index 4d29faa11..da2d01229 100644 --- a/src/iface/interface/ethernet.rs +++ b/src/iface/interface/ethernet.rs @@ -25,13 +25,19 @@ impl InterfaceInner { EthernetProtocol::Ipv4 => { let ipv4_packet = check!(Ipv4Packet::new_checked(eth_frame.payload())); - self.process_ipv4(sockets, meta, &ipv4_packet, fragments) - .map(EthernetPacket::Ip) + self.process_ipv4( + sockets, + meta, + eth_frame.src_addr().into(), + &ipv4_packet, + fragments, + ) + .map(EthernetPacket::Ip) } #[cfg(feature = "proto-ipv6")] EthernetProtocol::Ipv6 => { let ipv6_packet = check!(Ipv6Packet::new_checked(eth_frame.payload())); - self.process_ipv6(sockets, meta, &ipv6_packet) + self.process_ipv6(sockets, meta, eth_frame.src_addr().into(), &ipv6_packet) .map(EthernetPacket::Ip) } // Drop all other traffic. diff --git a/src/iface/interface/ipv4.rs b/src/iface/interface/ipv4.rs index 84b265c5e..e75159ea2 100644 --- a/src/iface/interface/ipv4.rs +++ b/src/iface/interface/ipv4.rs @@ -91,6 +91,7 @@ impl InterfaceInner { &mut self, sockets: &mut SocketSet, meta: PacketMeta, + source_hardware_addr: HardwareAddress, ipv4_packet: &Ipv4Packet<&'a [u8]>, frag: &'a mut FragmentsBuffer, ) -> Option> { @@ -197,8 +198,13 @@ impl InterfaceInner { } #[cfg(feature = "medium-ethernet")] - self.neighbor_cache - .reset_expiry_if_existing(IpAddress::Ipv4(ipv4_repr.src_addr), self.now); + if self.is_unicast_v4(ipv4_repr.dst_addr) { + self.neighbor_cache.reset_expiry_if_existing( + IpAddress::Ipv4(ipv4_repr.src_addr), + source_hardware_addr, + self.now, + ); + } match ipv4_repr.next_header { IpProtocol::Icmp => self.process_icmpv4(sockets, ipv4_repr, ip_payload), diff --git a/src/iface/interface/ipv6.rs b/src/iface/interface/ipv6.rs index 28c446304..a8d29e48c 100644 --- a/src/iface/interface/ipv6.rs +++ b/src/iface/interface/ipv6.rs @@ -187,6 +187,7 @@ impl InterfaceInner { &mut self, sockets: &mut SocketSet, meta: PacketMeta, + source_hardware_addr: HardwareAddress, ipv6_packet: &Ipv6Packet<&'frame [u8]>, ) -> Option> { let ipv6_repr = check!(Ipv6Repr::parse(ipv6_packet)); @@ -229,8 +230,13 @@ impl InterfaceInner { let handled_by_raw_socket = false; #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))] - self.neighbor_cache - .reset_expiry_if_existing(IpAddress::Ipv6(ipv6_repr.src_addr), self.now); + if ipv6_repr.dst_addr.is_unicast() { + self.neighbor_cache.reset_expiry_if_existing( + IpAddress::Ipv6(ipv6_repr.src_addr), + source_hardware_addr, + self.now, + ); + } self.process_nxt_hdr( sockets, diff --git a/src/iface/interface/mod.rs b/src/iface/interface/mod.rs index f8c8afb69..7eed974e8 100644 --- a/src/iface/interface/mod.rs +++ b/src/iface/interface/mod.rs @@ -785,12 +785,12 @@ impl InterfaceInner { Ok(IpVersion::Ipv4) => { let ipv4_packet = check!(Ipv4Packet::new_checked(ip_payload)); - self.process_ipv4(sockets, meta, &ipv4_packet, frag) + self.process_ipv4(sockets, meta, HardwareAddress::Ip, &ipv4_packet, frag) } #[cfg(feature = "proto-ipv6")] Ok(IpVersion::Ipv6) => { let ipv6_packet = check!(Ipv6Packet::new_checked(ip_payload)); - self.process_ipv6(sockets, meta, &ipv6_packet) + self.process_ipv6(sockets, meta, HardwareAddress::Ip, &ipv6_packet) } // Drop all other traffic. _ => None, diff --git a/src/iface/interface/sixlowpan.rs b/src/iface/interface/sixlowpan.rs index 3caa446f5..a89934f1f 100644 --- a/src/iface/interface/sixlowpan.rs +++ b/src/iface/interface/sixlowpan.rs @@ -99,7 +99,15 @@ impl InterfaceInner { } }; - self.process_ipv6(sockets, meta, &check!(Ipv6Packet::new_checked(payload))) + self.process_ipv6( + sockets, + meta, + match ieee802154_repr.src_addr { + Some(s) => HardwareAddress::Ieee802154(s), + None => HardwareAddress::Ieee802154(Ieee802154Address::Absent), + }, + &check!(Ipv6Packet::new_checked(payload)), + ) } #[cfg(feature = "proto-sixlowpan-fragmentation")] diff --git a/src/iface/interface/tests/ipv4.rs b/src/iface/interface/tests/ipv4.rs index 475911bed..1c394f2a9 100644 --- a/src/iface/interface/tests/ipv4.rs +++ b/src/iface/interface/tests/ipv4.rs @@ -91,6 +91,7 @@ fn test_no_icmp_no_unicast(#[case] medium: Medium) { iface.inner.process_ipv4( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &frame, &mut iface.fragments ), @@ -152,6 +153,7 @@ fn test_icmp_error_no_payload(#[case] medium: Medium) { iface.inner.process_ipv4( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &frame, &mut iface.fragments ), @@ -397,6 +399,7 @@ fn test_handle_ipv4_broadcast(#[case] medium: Medium) { iface.inner.process_ipv4( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &frame, &mut iface.fragments ), @@ -828,6 +831,7 @@ fn test_raw_socket_no_reply(#[case] medium: Medium) { iface.inner.process_ipv4( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &frame, &mut iface.fragments ), @@ -925,6 +929,7 @@ fn test_raw_socket_with_udp_socket(#[case] medium: Medium) { iface.inner.process_ipv4( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &frame, &mut iface.fragments ), diff --git a/src/iface/interface/tests/ipv6.rs b/src/iface/interface/tests/ipv6.rs index c891ecc34..785daba11 100644 --- a/src/iface/interface/tests/ipv6.rs +++ b/src/iface/interface/tests/ipv6.rs @@ -86,6 +86,7 @@ fn any_ip(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), None @@ -98,6 +99,7 @@ fn any_ip(#[case] medium: Medium) { .process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ) .is_some()); @@ -125,6 +127,7 @@ fn multicast_source_address(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -173,6 +176,7 @@ fn hop_by_hop_skip_with_icmp(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -208,6 +212,7 @@ fn hop_by_hop_discard_with_icmp(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -262,6 +267,7 @@ fn hop_by_hop_discard_param_problem(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -319,6 +325,7 @@ fn hop_by_hop_discard_with_multicast(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -378,6 +385,7 @@ fn imcp_empty_echo_request(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -438,6 +446,7 @@ fn icmp_echo_request(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -485,6 +494,7 @@ fn icmp_echo_reply_as_input(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -533,6 +543,7 @@ fn unknown_proto_with_multicast_dst_address(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -582,6 +593,7 @@ fn unknown_proto(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -626,6 +638,7 @@ fn ndsic_neighbor_advertisement_ethernet(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -682,6 +695,7 @@ fn ndsic_neighbor_advertisement_ethernet_multicast_addr(#[case] medium: Medium) iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response @@ -734,6 +748,7 @@ fn ndsic_neighbor_advertisement_ieee802154(#[case] medium: Medium) { iface.inner.process_ipv6( &mut sockets, PacketMeta::default(), + HardwareAddress::default(), &Ipv6Packet::new_checked(&data[..]).unwrap() ), response diff --git a/src/iface/neighbor.rs b/src/iface/neighbor.rs index 543d78c98..dcef2bb87 100644 --- a/src/iface/neighbor.rs +++ b/src/iface/neighbor.rs @@ -63,13 +63,20 @@ impl Cache { } } - pub fn reset_expiry_if_existing(&mut self, protocol_addr: IpAddress, timestamp: Instant) { + pub fn reset_expiry_if_existing( + &mut self, + protocol_addr: IpAddress, + source_hardware_addr: HardwareAddress, + timestamp: Instant, + ) { if let Some(Neighbor { expires_at, - hardware_addr: _, + hardware_addr, }) = self.storage.get_mut(&protocol_addr) { - *expires_at = timestamp + Self::ENTRY_LIFETIME; + if source_hardware_addr == *hardware_addr { + *expires_at = timestamp + Self::ENTRY_LIFETIME; + } } } diff --git a/src/wire/mod.rs b/src/wire/mod.rs index a552b63b4..c197afed9 100644 --- a/src/wire/mod.rs +++ b/src/wire/mod.rs @@ -323,6 +323,30 @@ pub enum HardwareAddress { Ieee802154(Ieee802154Address), } +#[cfg(any( + feature = "medium-ip", + feature = "medium-ethernet", + feature = "medium-ieee802154" +))] +#[cfg(test)] +impl Default for HardwareAddress { + fn default() -> Self { + #![allow(unreachable_code)] + #[cfg(feature = "medium-ethernet")] + { + return Self::Ethernet(EthernetAddress::default()); + } + #[cfg(feature = "medium-ip")] + { + return Self::Ip; + } + #[cfg(feature = "medium-ieee802154")] + { + Self::Ieee802154(Ieee802154Address::default()) + } + } +} + #[cfg(any( feature = "medium-ip", feature = "medium-ethernet", From 8e97c95f23719f8b5291663a213737cbc86ca455 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Mon, 5 Aug 2024 11:23:20 +0200 Subject: [PATCH 3/3] Update default neighbor cache size to 8 entries --- Cargo.toml | 4 ++-- build.rs | 2 +- gen_config.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 576cf175b..a505a214a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -151,11 +151,11 @@ iface-max-sixlowpan-address-context-count-1024 = [] iface-neighbor-cache-count-1 = [] iface-neighbor-cache-count-2 = [] iface-neighbor-cache-count-3 = [] -iface-neighbor-cache-count-4 = [] # Default +iface-neighbor-cache-count-4 = [] iface-neighbor-cache-count-5 = [] iface-neighbor-cache-count-6 = [] iface-neighbor-cache-count-7 = [] -iface-neighbor-cache-count-8 = [] +iface-neighbor-cache-count-8 = [] # Default iface-neighbor-cache-count-16 = [] iface-neighbor-cache-count-32 = [] iface-neighbor-cache-count-64 = [] diff --git a/build.rs b/build.rs index 1ee723eb7..e1746d23f 100644 --- a/build.rs +++ b/build.rs @@ -9,7 +9,7 @@ static CONFIGS: &[(&str, usize)] = &[ ("IFACE_MAX_ADDR_COUNT", 2), ("IFACE_MAX_MULTICAST_GROUP_COUNT", 4), ("IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT", 4), - ("IFACE_NEIGHBOR_CACHE_COUNT", 4), + ("IFACE_NEIGHBOR_CACHE_COUNT", 8), ("IFACE_MAX_ROUTE_COUNT", 2), ("FRAGMENTATION_BUFFER_SIZE", 1500), ("ASSEMBLER_MAX_SEGMENT_COUNT", 4), diff --git a/gen_config.py b/gen_config.py index e33f74606..1407ca2d6 100644 --- a/gen_config.py +++ b/gen_config.py @@ -30,7 +30,7 @@ def feature(name, default, min, max, pow2=None): feature("iface_max_addr_count", default=2, min=1, max=8) feature("iface_max_multicast_group_count", default=4, min=1, max=1024, pow2=8) feature("iface_max_sixlowpan_address_context_count", default=4, min=1, max=1024, pow2=8) -feature("iface_neighbor_cache_count", default=4, min=1, max=1024, pow2=8) +feature("iface_neighbor_cache_count", default=8, min=1, max=1024, pow2=8) feature("iface_max_route_count", default=2, min=1, max=1024, pow2=8) feature("fragmentation_buffer_size", default=1500, min=256, max=65536, pow2=True) feature("assembler_max_segment_count", default=4, min=1, max=32, pow2=4)