From bcd3d6936e189b89479431b7c939eb25f01c0a83 Mon Sep 17 00:00:00 2001 From: Markus Rudy Date: Mon, 18 May 2026 09:57:44 +0200 Subject: [PATCH] agent: use rtnetlink to add ARP neighbour The rtnetlink crate has had an API for neighbours since 0.11. The last attempt to use this API caused problems on AKS, but looking at it again shows that not all functionality was ported back then (state, flags and lladdr). Attempt the migration again, considering all parameters. Fixes: #11942 Signed-off-by: Markus Rudy --- src/agent/src/netlink.rs | 71 ++++++++++------------------------------ 1 file changed, 17 insertions(+), 54 deletions(-) diff --git a/src/agent/src/netlink.rs b/src/agent/src/netlink.rs index 72c75265f2..205e340ca7 100644 --- a/src/agent/src/netlink.rs +++ b/src/agent/src/netlink.rs @@ -4,19 +4,18 @@ // use anyhow::{anyhow, Context, Result}; -use futures::{future, StreamExt, TryStreamExt}; +use futures::{future, TryStreamExt}; use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network}; use netlink_packet_route::link::{LinkAttribute, LinkMessage}; -use netlink_packet_route::neighbour::{self, NeighbourFlag}; +use netlink_packet_route::neighbour::NeighbourFlag; use netlink_packet_route::route::{RouteFlag, RouteHeader, RouteProtocol, RouteScope, RouteType}; use netlink_packet_route::{ address::{AddressAttribute, AddressMessage}, route::RouteMetric, }; use netlink_packet_route::{ - neighbour::{NeighbourAddress, NeighbourAttribute, NeighbourState}, + neighbour::NeighbourState, route::{RouteAddress, RouteAttribute, RouteMessage}, - AddressFamily, }; use nix::errno::Errno; use protocols::types::{ARPNeighbor, IPAddress, IPFamily, Interface, Route}; @@ -641,20 +640,6 @@ impl Handle { let ip = IpAddr::from_str(ip_address) .map_err(|e| anyhow!("Failed to parse IP {}: {:?}", ip_address, e))?; - // Import rtnetlink objects that make sense only for this function - use libc::{NDA_UNSPEC, NLM_F_ACK, NLM_F_CREATE, NLM_F_REPLACE, NLM_F_REQUEST}; - use neighbour::{NeighbourHeader, NeighbourMessage}; - use netlink_packet_core::{NetlinkMessage, NetlinkPayload}; - use netlink_packet_route::RouteNetlinkMessage as RtnlMessage; - use rtnetlink::Error; - - const IFA_F_PERMANENT: u16 = 0x80; // See https://github.com/little-dude/netlink/blob/0185b2952505e271805902bf175fee6ea86c42b8/netlink-packet-route/src/rtnl/constants.rs#L770 - let state = if neigh.state != 0 { - neigh.state as u16 - } else { - IFA_F_PERMANENT - }; - let link = self.find_link(LinkFilter::Name(&neigh.device)).await?; let mut flags = Vec::new(); @@ -663,45 +648,23 @@ impl Handle { flags.push(flag); } } - - let mut message = NeighbourMessage::default(); - - message.header = NeighbourHeader { - family: match ip { - IpAddr::V4(_) => AddressFamily::Inet, - IpAddr::V6(_) => AddressFamily::Inet6, - }, - ifindex: link.index(), - state: NeighbourState::from(state), - flags, - kind: RouteType::from(NDA_UNSPEC as u8), + let state = if neigh.state == 0 { + NeighbourState::Permanent + } else { + (neigh.state as u16).into() }; - - let mut nlas = vec![NeighbourAttribute::Destination(match ip { - IpAddr::V4(ipv4_addr) => NeighbourAddress::from(ipv4_addr), - IpAddr::V6(ipv6_addr) => NeighbourAddress::from(ipv6_addr), - })]; - + let mut req = self + .handle + .neighbours() + .add(link.index(), ip) + .state(state) + .flags(flags) + .replace(); if !neigh.lladdr.is_empty() { - nlas.push(NeighbourAttribute::LinkLocalAddress( - parse_mac_address(&neigh.lladdr)?.to_vec(), - )); + let lladdr = parse_mac_address(&neigh.lladdr).context("parsing lladdr")?; + req = req.link_local_address(&lladdr); } - - message.attributes = nlas; - - // Send request and ACK - let mut req = NetlinkMessage::from(RtnlMessage::NewNeighbour(message)); - req.header.flags = (NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE) as u16; - - let mut response = self.handle.request(req)?; - while let Some(message) = response.next().await { - if let NetlinkPayload::Error(err) = message.payload { - return Err(anyhow!(Error::NetlinkError(err))); - } - } - - Ok(()) + req.execute().await.context("executing NeighbourAddRequest") } }