@@ -613,6 +613,7 @@ where
613
613
/// This function panics if any of the addresses are not unicast.
614
614
pub fn update_ip_addrs < F : FnOnce ( & mut ManagedSlice < ' a , IpCidr > ) > ( & mut self , f : F ) {
615
615
f ( & mut self . inner . ip_addrs ) ;
616
+ InterfaceInner :: flush_cache ( & mut self . inner ) ;
616
617
InterfaceInner :: check_ip_addrs ( & self . inner . ip_addrs )
617
618
}
618
619
@@ -2225,6 +2226,12 @@ impl<'a> InterfaceInner<'a> {
2225
2226
Err ( Error :: Unaddressable )
2226
2227
}
2227
2228
2229
+ fn flush_cache ( & mut self ) {
2230
+ if let Some ( cache) = self . neighbor_cache . as_mut ( ) {
2231
+ cache. flush ( )
2232
+ }
2233
+ }
2234
+
2228
2235
fn dispatch_ip < Tx : TxToken > (
2229
2236
& mut self ,
2230
2237
cx : & Context ,
@@ -3313,6 +3320,76 @@ mod test {
3313
3320
) ;
3314
3321
}
3315
3322
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
+
3316
3393
#[ test]
3317
3394
#[ cfg( all( feature = "socket-icmp" , feature = "proto-ipv4" ) ) ]
3318
3395
fn test_icmpv4_socket ( ) {
0 commit comments