Add a FreeBSD implementation of the virArpTableGet() function. Update the bhyve driver's bhyveDomainInterfaceAddresses() to use it for the VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP source type. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_driver.c | 5 +- src/util/virarptable.c | 105 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 107 insertions(+), 3 deletions(-) diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index 93c07c6945..c8dd1a728a 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -1868,12 +1868,15 @@ bhyveDomainInterfaceAddresses(virDomainPtr domain, goto cleanup; switch (source) { + case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP: + ret = virDomainNetARPInterfaces(vm->def, ifaces); + break; + case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE: ret = virDomainNetDHCPInterfaces(vm->def, ifaces); break; case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT: - case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP: virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, _("Unsupported IP address data source %1$d"), source); diff --git a/src/util/virarptable.c b/src/util/virarptable.c index 20d11f97b0..2c5a58b695 100644 --- a/src/util/virarptable.c +++ b/src/util/virarptable.c @@ -1,7 +1,8 @@ /* - * virarptable.c Linux ARP table handling + * virarptable.c ARP table handling * * Copyright (C) 2018 Chen Hanxiao + * Copyright (C) 2026 The FreeBSD Foundation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,6 +23,16 @@ #ifdef __linux__ # include <linux/rtnetlink.h> +#elif defined(__FreeBSD__) +# include <sys/types.h> +# include <sys/socket.h> +# include <sys/sysctl.h> +# include <net/if.h> +# include <net/if_dl.h> +# include <net/if_types.h> +# include <netinet/in.h> +# include <net/route.h> +# include <arpa/inet.h> #endif #include "viralloc.h" @@ -145,6 +156,96 @@ virArpTableGet(void) return NULL; } +#elif defined(__FreeBSD__) + +# define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +# define ADVANCE(x, n) (x += ROUNDUP((n)->rtm_msglen)) + +virArpTable * +virArpTableGet(void) +{ + int num = 0; + int mib[6]; + size_t needed; + g_autofree char *buf = NULL; + char *next, *lim; + struct rt_msghdr *rtm; + struct sockaddr_in *sin; + struct sockaddr_dl *sdl; + virArpTable *table = NULL; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET; + mib[4] = NET_RT_FLAGS; + mib[5] = RTF_LLINFO; + + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { + virReportSystemError(errno, "%s", _("failed to get ARP table via sysctl")); + return NULL; + } + + if (needed == 0) + return NULL; + + buf = g_new0(char, needed); + + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { + virReportSystemError(errno, "%s", _("failed to get ARP table via sysctl")); + return NULL; + } + + table = g_new0(virArpTable, 1); + + lim = buf + needed; + VIR_WARNINGS_NO_CAST_ALIGN + for (next = buf; next < lim;) { + rtm = (struct rt_msghdr *)next; + + if (rtm->rtm_msglen == 0) + break; + + sin = (struct sockaddr_in *)(rtm + 1); + sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin_len)); + + if (sdl->sdl_alen && + (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_BRIDGE)) { + g_autofree char *ipstr = NULL; + virSocketAddr virAddr = { 0 }; + virMacAddr macaddr; + char ifmac[VIR_MAC_STRING_BUFLEN]; + + VIR_REALLOC_N(table->t, num + 1); + table->n = num + 1; + + virAddr.len = sizeof(virAddr.data.inet4); + virAddr.data.inet4.sin_family = AF_INET; + virAddr.data.inet4.sin_addr = sin->sin_addr; + ipstr = virSocketAddrFormat(&virAddr); + + table->t[num].ipaddr = g_strdup(ipstr); + + memcpy(macaddr.addr, LLADDR(sdl), VIR_MAC_BUFLEN); + + virMacAddrFormat(&macaddr, ifmac); + + table->t[num].mac = g_strdup(ifmac); + + num++; + } + + ADVANCE(next, rtm); + } + VIR_WARNINGS_RESET + + return table; +} + +# undef ROUNDUP +# undef ADVANCE + #else virArpTable * @@ -155,7 +256,7 @@ virArpTableGet(void) return NULL; } -#endif /* __linux__ */ +#endif void virArpTableFree(virArpTable *table) -- 2.52.0