Kaynağa Gözat

Merge pull request #966 from korken89/neighbor-cache-expiry-fix

Reset expiry of entries in the neighbor cache on packet reception
Dario Nieuwenhuis 8 ay önce
ebeveyn
işleme
8be46b9287

+ 2 - 2
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 = []

+ 1 - 1
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),

+ 1 - 1
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)

+ 9 - 3
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.

+ 10 - 0
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<Packet<'a>> {
@@ -196,6 +197,15 @@ impl InterfaceInner {
             }
         }
 
+        #[cfg(feature = "medium-ethernet")]
+        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),
 

+ 10 - 0
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<Packet<'frame>> {
         let ipv6_repr = check!(Ipv6Repr::parse(ipv6_packet));
@@ -228,6 +229,15 @@ impl InterfaceInner {
         #[cfg(not(feature = "socket-raw"))]
         let handled_by_raw_socket = false;
 
+        #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
+        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,
             meta,

+ 2 - 2
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,

+ 9 - 1
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")]

+ 5 - 0
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
         ),

+ 15 - 0
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

+ 17 - 0
src/iface/neighbor.rs

@@ -63,6 +63,23 @@ impl Cache {
         }
     }
 
+    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,
+        }) = self.storage.get_mut(&protocol_addr)
+        {
+            if source_hardware_addr == *hardware_addr {
+                *expires_at = timestamp + Self::ENTRY_LIFETIME;
+            }
+        }
+    }
+
     pub fn fill(
         &mut self,
         protocol_addr: IpAddress,

+ 24 - 0
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",