From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: passt.top; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=XoO6otsW; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by passt.top (Postfix) with ESMTPS id CE2255A0285 for ; Wed, 20 Aug 2025 05:10:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1755659416; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=D8bNw5DzcgqtzA6n2jw2pcnuuTtGFs+jJPyT8adOZTk=; b=XoO6otsWANV9ibD6k+DbHVSBl0bdJ2vnx6yqyHL1V8MemutnmyC4k3wbY4sWb3KHPShvUZ cdlcZpNQqlBi6tOIzvHbsWuH2BlhyS54RgAFvyh/KMTEc9WEwGhLbKyEN6QOuNuJxSV4JV BSb+svHfjESEl4hZtYjpeEANrdaaxtc= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-584-gNee25vINPuskXYOc5wirw-1; Tue, 19 Aug 2025 23:10:11 -0400 X-MC-Unique: gNee25vINPuskXYOc5wirw-1 X-Mimecast-MFC-AGG-ID: gNee25vINPuskXYOc5wirw_1755659410 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B9C5A1800340; Wed, 20 Aug 2025 03:10:09 +0000 (UTC) Received: from jmaloy-thinkpadp16vgen1.rmtcaqc.csb (unknown [10.22.88.50]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E4C9819A4C9C; Wed, 20 Aug 2025 03:10:07 +0000 (UTC) From: Jon Maloy To: sbrivio@redhat.com, dgibson@redhat.com, david@gibson.dropbear.id.au, jmaloy@redhat.com, passt-dev@passt.top Subject: [PATCH v4 1/9] netlink: add function to extract MAC addresses from NDP/ARP table Date: Tue, 19 Aug 2025 23:09:57 -0400 Message-ID: <20250820031005.2725591-2-jmaloy@redhat.com> In-Reply-To: <20250820031005.2725591-1-jmaloy@redhat.com> References: <20250820031005.2725591-1-jmaloy@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 9hYima-pd3AtMqNxo8waN9_N8L4Ru3zrqfIwNku4Ia0_1755659410 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true Message-ID-Hash: JH6CRGWHIHQTZRD5QAMFMEWERW55KFOF X-Message-ID-Hash: JH6CRGWHIHQTZRD5QAMFMEWERW55KFOF X-MailFrom: jmaloy@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The solution to bug https://bugs.passt.top/show_bug.cgi?id=120 requires the ability to translate from an IP address to its corresponding MAC address in cases where those are present in the ARP/NDP table. We add this feature here. Signed-off-by: Jon Maloy --- netlink.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ netlink.h | 2 ++ 2 files changed, 81 insertions(+) diff --git a/netlink.c b/netlink.c index 8f82e73..cf7debc 100644 --- a/netlink.c +++ b/netlink.c @@ -800,6 +800,85 @@ int nl_addr_get(int s, unsigned int ifi, sa_family_t af, return status; } +/** + * nl_neigh_mac_get() - Get neighbor MAC address from the kernel neigh table + * @s: Netlink socket fd + * @addr: IPv4 or IPv6 address + * @ifi: Interface index + * @mac: Buffer for Ethernet MAC, left unchanged if not found/usable + * + * Return: <0 on netlink error; 0 otherwise (drains all replies for @seq). + */ +int nl_neigh_mac_get(int s, const union inany_addr *addr, + int ifi, unsigned char *mac) +{ + const void *ip = inany_v4(addr); + struct req_t { + struct nlmsghdr nlh; + struct ndmsg ndm; + struct rtattr rta; + char ip[RTA_ALIGN(sizeof(struct in6_addr))]; + } req; + struct nlmsghdr *nh; + char buf[NLBUFSIZ]; + ssize_t status; + uint32_t seq; + int msglen; + int iplen; + + memset(&req, 0, sizeof(req)); + req.ndm.ndm_ifindex = ifi; + req.rta.rta_type = NDA_DST; + + if (ip) { + req.ndm.ndm_family = AF_INET; + iplen = sizeof(struct in_addr); + } else { + req.ndm.ndm_family = AF_INET6; + ip = &addr; + iplen = sizeof(struct in6_addr); + } + + req.rta.rta_len = RTA_LENGTH(iplen); + memcpy(RTA_DATA(&req.rta), ip, iplen); + msglen = NLMSG_ALIGN(sizeof(req.nlh) + sizeof(req.ndm) + RTA_LENGTH(iplen)); + seq = nl_send(s, &req, RTM_GETNEIGH, 0, msglen); + + /* Drain all RTM_NEWNEIGH replies for this seq */ + nl_foreach_oftype(nh, status, s, buf, seq, RTM_NEWNEIGH) { + struct ndmsg *ndm = NLMSG_DATA(nh); + struct rtattr *rta = (struct rtattr *)(ndm + 1); + const uint8_t *lladdr = NULL; + size_t na = RTM_PAYLOAD(nh); + const void *dst = NULL; + size_t lladdr_len = 0; + size_t dstlen = 0; + + for (; RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) { + switch (rta->rta_type) { + case NDA_DST: + dst = RTA_DATA(rta); + dstlen = RTA_PAYLOAD(rta); + break; + case NDA_LLADDR: + lladdr = RTA_DATA(rta); + lladdr_len = RTA_PAYLOAD(rta); + break; + default: + break; + } + } + + if (dst && dstlen == (size_t)iplen && memcmp(dst, ip, iplen) == 0) { + /* Only copy Ethernet-style addresses; leave unchanged otherwise */ + if (lladdr && lladdr_len == ETH_ALEN) + memcpy(mac, lladdr, ETH_ALEN); + } + } + + return status; +} + /** * nl_addr_get_ll() - Get first IPv6 link-local address for a given interface * @s: Netlink socket diff --git a/netlink.h b/netlink.h index b51e99c..026c64f 100644 --- a/netlink.h +++ b/netlink.h @@ -17,6 +17,8 @@ int nl_route_dup(int s_src, unsigned int ifi_src, int s_dst, unsigned int ifi_dst, sa_family_t af); int nl_addr_get(int s, unsigned int ifi, sa_family_t af, void *addr, int *prefix_len, void *addr_l); +int nl_neigh_mac_get(int s, const union inany_addr *addr, int ifi, + unsigned char *mac); int nl_addr_set(int s, unsigned int ifi, sa_family_t af, const void *addr, int prefix_len); int nl_addr_get_ll(int s, unsigned int ifi, struct in6_addr *addr); -- 2.50.1