@@ -613,6 +613,7 @@ where
613613 /// This function panics if any of the addresses are not unicast.
614614 pub fn update_ip_addrs < F : FnOnce ( & mut ManagedSlice < ' a , IpCidr > ) > ( & mut self , f : F ) {
615615 f ( & mut self . inner . ip_addrs ) ;
616+ InterfaceInner :: flush_cache ( & mut self . inner ) ;
616617 InterfaceInner :: check_ip_addrs ( & self . inner . ip_addrs )
617618 }
618619
@@ -2225,6 +2226,12 @@ impl<'a> InterfaceInner<'a> {
22252226 Err ( Error :: Unaddressable )
22262227 }
22272228
2229+ fn flush_cache ( & mut self ) {
2230+ if let Some ( cache) = self . neighbor_cache . as_mut ( ) {
2231+ cache. flush ( )
2232+ }
2233+ }
2234+
22282235 fn dispatch_ip < Tx : TxToken > (
22292236 & mut self ,
22302237 cx : & Context ,
@@ -3313,6 +3320,76 @@ mod test {
33133320 ) ;
33143321 }
33153322
3323+ #[ test]
3324+ #[ cfg( all( feature = "medium-ethernet" , feature = "proto-ipv4" ) ) ]
3325+ fn test_arp_flush_after_update_ip ( ) {
3326+ let ( mut iface, mut socket_set) = create_loopback_ethernet ( ) ;
3327+
3328+ let mut eth_bytes = vec ! [ 0u8 ; 42 ] ;
3329+
3330+ let local_ip_addr = Ipv4Address ( [ 0x7f , 0x00 , 0x00 , 0x01 ] ) ;
3331+ let remote_ip_addr = Ipv4Address ( [ 0x7f , 0x00 , 0x00 , 0x02 ] ) ;
3332+ let local_hw_addr = EthernetAddress ( [ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ] ) ;
3333+ let remote_hw_addr = EthernetAddress ( [ 0x52 , 0x54 , 0x00 , 0x00 , 0x00 , 0x00 ] ) ;
3334+
3335+ let repr = ArpRepr :: EthernetIpv4 {
3336+ operation : ArpOperation :: Request ,
3337+ source_hardware_addr : remote_hw_addr,
3338+ source_protocol_addr : remote_ip_addr,
3339+ target_hardware_addr : EthernetAddress :: default ( ) ,
3340+ target_protocol_addr : Ipv4Address ( [ 0x7f , 0x00 , 0x00 , 0x01 ] ) ,
3341+ } ;
3342+
3343+ let mut frame = EthernetFrame :: new_unchecked ( & mut eth_bytes) ;
3344+ frame. set_dst_addr ( EthernetAddress :: BROADCAST ) ;
3345+ frame. set_src_addr ( remote_hw_addr) ;
3346+ frame. set_ethertype ( EthernetProtocol :: Arp ) ;
3347+ {
3348+ let mut packet = ArpPacket :: new_unchecked ( frame. payload_mut ( ) ) ;
3349+ repr. emit ( & mut packet) ;
3350+ }
3351+
3352+ let cx = iface. context ( Instant :: from_secs ( 0 ) ) ;
3353+
3354+ // Ensure an ARP Request for us triggers an ARP Reply
3355+ assert_eq ! (
3356+ iface
3357+ . inner
3358+ . process_ethernet( & cx, & mut socket_set, frame. into_inner( ) ) ,
3359+ Ok ( Some ( EthernetPacket :: Arp ( ArpRepr :: EthernetIpv4 {
3360+ operation: ArpOperation :: Reply ,
3361+ source_hardware_addr: local_hw_addr,
3362+ source_protocol_addr: local_ip_addr,
3363+ target_hardware_addr: remote_hw_addr,
3364+ target_protocol_addr: remote_ip_addr
3365+ } ) ) )
3366+ ) ;
3367+
3368+ // Ensure the address of the requestor was entered in the cache
3369+ assert_eq ! (
3370+ iface. inner. lookup_hardware_addr(
3371+ & cx,
3372+ MockTxToken ,
3373+ & IpAddress :: Ipv4 ( local_ip_addr) ,
3374+ & IpAddress :: Ipv4 ( remote_ip_addr)
3375+ ) ,
3376+ Ok ( ( HardwareAddress :: Ethernet ( remote_hw_addr) , MockTxToken ) )
3377+ ) ;
3378+
3379+ // Update IP addrs to trigger ARP cache flush
3380+ let local_ip_addr_new = Ipv4Address ( [ 0x7f , 0x00 , 0x00 , 0x01 ] ) ;
3381+ iface. update_ip_addrs ( |addrs| {
3382+ addrs. iter_mut ( ) . next ( ) . map ( |addr| {
3383+ * addr = IpCidr :: Ipv4 ( Ipv4Cidr :: new ( local_ip_addr_new, 24 ) ) ;
3384+ } ) ;
3385+ } ) ;
3386+
3387+ // ARP cache flush after address change
3388+ assert ! ( !iface
3389+ . inner
3390+ . has_neighbor( & cx, & IpAddress :: Ipv4 ( remote_ip_addr) ) ) ;
3391+ }
3392+
33163393 #[ test]
33173394 #[ cfg( all( feature = "socket-icmp" , feature = "proto-ipv4" ) ) ]
33183395 fn test_icmpv4_socket ( ) {
0 commit comments