Skip to content

Commit 7dd009d

Browse files
bors[bot]deantvv
andauthored
Merge #564
564: arp: flush neighbor cache after IP update r=Dirbaio a=deantvv Related to #543 Co-authored-by: Dean Li <deantvv@gmail.com>
2 parents 72f2073 + a666a7a commit 7dd009d

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

src/iface/interface.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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() {

src/iface/neighbor.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ impl<'a> Cache<'a> {
218218
pub(crate) fn limit_rate(&mut self, timestamp: Instant) {
219219
self.silent_until = timestamp + Self::SILENT_TIME;
220220
}
221+
222+
pub(crate) fn flush(&mut self) {
223+
self.storage.clear()
224+
}
221225
}
222226

223227
#[cfg(test)]
@@ -370,4 +374,27 @@ mod test {
370374
Answer::NotFound
371375
);
372376
}
377+
378+
#[test]
379+
fn test_flush() {
380+
let mut cache_storage = [Default::default(); 3];
381+
let mut cache = Cache::new(&mut cache_storage[..]);
382+
383+
cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(0));
384+
assert_eq!(
385+
cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0)),
386+
Answer::Found(HADDR_A)
387+
);
388+
assert!(!cache
389+
.lookup(&MOCK_IP_ADDR_2, Instant::from_millis(0))
390+
.found());
391+
392+
cache.flush();
393+
assert!(!cache
394+
.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0))
395+
.found());
396+
assert!(!cache
397+
.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0))
398+
.found());
399+
}
373400
}

0 commit comments

Comments
 (0)