[libvirt] [PATCH rebase v4 0/5] qemu: use arp table of host to get the

introduce VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP to get ip address of VM from the output of /proc/net/arp Chen Hanxiao (5): util: introduce virNetlinkGetNeighbor to get neighbor table entry util: introduce helper to parse message from RTM_GETNEIGH query qemu: introduce qemuARPGetInterfaces to get IP from host's arp table virsh: add --source arp to domifaddr news: qemu: use arp table of host to get the IP address of guests docs/news.xml | 9 ++ include/libvirt/libvirt-domain.h | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt-domain.c | 7 ++ src/libvirt_private.syms | 6 ++ src/qemu/qemu_driver.c | 72 ++++++++++++++++ src/util/Makefile.inc.am | 2 + src/util/virarptable.c | 181 +++++++++++++++++++++++++++++++++++++++ src/util/virarptable.h | 48 +++++++++++ src/util/virnetlink.c | 82 ++++++++++++++++++ src/util/virnetlink.h | 2 + tools/virsh-domain-monitor.c | 2 + tools/virsh.pod | 7 +- 14 files changed, 418 insertions(+), 3 deletions(-) create mode 100644 src/util/virarptable.c create mode 100644 src/util/virarptable.h -- 2.14.3

From: Chen Hanxiao <chenhanxiao@gmail.com> use RTM_GETNEIGH to query arp table entry by netlink socket Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com> --- v4: use netlink to get arp table entry src/libvirt_private.syms | 1 + src/util/virnetlink.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virnetlink.h | 2 ++ 3 files changed, 85 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3766e20d3..11b9f4937 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2386,6 +2386,7 @@ virNetlinkEventServiceStart; virNetlinkEventServiceStop; virNetlinkEventServiceStopAll; virNetlinkGetErrorCode; +virNetlinkGetNeighbor; virNetlinkShutdown; virNetlinkStartup; diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index e61bbb96d..f0a92db23 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -590,6 +590,88 @@ virNetlinkDelLink(const char *ifname, virNetlinkDelLinkFallback fallback) goto cleanup; } +/** + * virNetlinkGetNeighbor: + * + * @nlData: Gets a pointer to the raw data from netlink. + MUST BE FREED BY CALLER! + * @src_pid: pid used for nl_pid of the local end of the netlink message + * (0 == "use getpid()") + * @dst_pid: pid of destination nl_pid if the kernel + * is not the target of the netlink message but it is to be + * sent to another process (0 if sending to the kernel) + * + * Get neighbor table entry from netlink. + * + * Returns 0 on success, -1 on fatal error. + */ +int +virNetlinkGetNeighbor(void **nlData, uint32_t src_pid, uint32_t dst_pid) +{ + int rc = -1; + struct nlmsghdr *resp = NULL; + struct nlmsgerr *err; + struct ndmsg ndinfo = { + .ndm_family = AF_UNSPEC, + }; + unsigned int recvbuflen; + struct nl_msg *nl_msg; + + nl_msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_DUMP | NLM_F_REQUEST); + if (!nl_msg) { + virReportOOMError(); + return -1; + } + + if (nlmsg_append(nl_msg, &ndinfo, sizeof(ndinfo), NLMSG_ALIGNTO) < 0) + goto buffer_too_small; + + + if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, + src_pid, dst_pid, NETLINK_ROUTE, 0) < 0) + goto cleanup; + + if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL) + goto malformed_resp; + + switch (resp->nlmsg_type) { + case NLMSG_ERROR: + err = (struct nlmsgerr *)NLMSG_DATA(resp); + if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) + goto malformed_resp; + + if (err->error) { + virReportSystemError(-err->error, + "%s", _("error dumping")); + goto cleanup; + } + break; + + case RTM_NEWNEIGH: + break; + + default: + goto malformed_resp; + } + rc = recvbuflen; + + cleanup: + nlmsg_free(nl_msg); + if (rc < 0) + VIR_FREE(resp); + *nlData = resp; + return rc; + + malformed_resp: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed netlink response message")); + goto cleanup; + + buffer_too_small: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("allocated netlink buffer is too small")); + goto cleanup; +} int virNetlinkGetErrorCode(struct nlmsghdr *resp, unsigned int recvbuflen) diff --git a/src/util/virnetlink.h b/src/util/virnetlink.h index 088b01343..2a9de0a57 100644 --- a/src/util/virnetlink.h +++ b/src/util/virnetlink.h @@ -71,6 +71,8 @@ int virNetlinkDumpLink(const char *ifname, int ifindex, void **nlData, struct nlattr **tb, uint32_t src_pid, uint32_t dst_pid) ATTRIBUTE_RETURN_CHECK; +int +virNetlinkGetNeighbor(void **nlData, uint32_t src_pid, uint32_t dst_pid); typedef void (*virNetlinkEventHandleCallback)(struct nlmsghdr *, unsigned int length, -- 2.14.3

From: Chen Hanxiao <chenhanxiao@gmail.com> introduce helper to parse RTM_GETNEIGH query message and store it in struct virArpTable. Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com> --- v4-rebase: fit split Makefile.am fit new virMacAddr fields v4: use netlink query instead of parsing /proc/net/arp v3: s/virGetArpTable/virArpTableGet alloc virArpTable in virArpTableGet return ENOSUPP on none-Linux platform move helpers to virarptable.[ch] po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 5 ++ src/util/Makefile.inc.am | 2 + src/util/virarptable.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virarptable.h | 48 +++++++++++++ 6 files changed, 238 insertions(+) create mode 100644 src/util/virarptable.c create mode 100644 src/util/virarptable.h diff --git a/po/POTFILES.in b/po/POTFILES.in index cfdd4ebdd..71c61dec9 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -192,6 +192,7 @@ src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c src/util/viralloc.c +src/util/virarptable.c src/util/viraudit.c src/util/virauth.c src/util/virauthconfig.c diff --git a/src/Makefile.am b/src/Makefile.am index 8b1e4c8a4..82c5d5cde 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -672,6 +672,7 @@ noinst_LTLIBRARIES += libvirt-setuid-rpc-client.la libvirt_setuid_rpc_client_la_SOURCES = \ util/viralloc.c \ util/virarch.c \ + util/virarptable.c \ util/viratomic.c \ util/viratomic.h \ util/virbitmap.c \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 11b9f4937..05b0c5b0e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1365,6 +1365,11 @@ virArchGetWordSize; virArchToString; +# util/virarptable.h +virArpTableFree; +virArpTableGet; + + # util/viraudit.h virAuditClose; virAuditEncode; diff --git a/src/util/Makefile.inc.am b/src/util/Makefile.inc.am index a91b30dca..02d9c42cc 100644 --- a/src/util/Makefile.inc.am +++ b/src/util/Makefile.inc.am @@ -5,6 +5,8 @@ UTIL_SOURCES = \ util/viralloc.h \ util/virarch.c \ util/virarch.h \ + util/virarptable.c \ + util/virarptable.h \ util/viratomic.c \ util/viratomic.h \ util/viraudit.c \ diff --git a/src/util/virarptable.c b/src/util/virarptable.c new file mode 100644 index 000000000..cb56338eb --- /dev/null +++ b/src/util/virarptable.c @@ -0,0 +1,181 @@ +/* + * virarptable.c Linux ARP table handling + * + * Copyright (C) 2018 Chen Hanxiao + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Chen Hanxiao <chenhanxiao@gmail.com> + */ + +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <arpa/inet.h> + +#include "viralloc.h" +#include "virarptable.h" +#include "virfile.h" +#include "virlog.h" +#include "virnetlink.h" +#include "virsocketaddr.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("util.arptable"); + +#ifdef __linux__ + +# define NDA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) + +static int +parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + while (RTA_OK(rta, len)) { + if ((rta->rta_type <= max) && (!tb[rta->rta_type])) + tb[rta->rta_type] = rta; + rta = RTA_NEXT(rta, len); + } + + if (len) + VIR_WARN("malformed netlink message: Deficit %d, rta_len=%d", + len, rta->rta_len); + return 0; +} + +virArpTablePtr virArpTableGet(void) +{ + int num = 0; + int msglen; + void *nlData = NULL; + virArpTablePtr table = NULL; + char *ipstr = NULL; + struct nlmsghdr* nh; + struct rtattr * tb[NDA_MAX+1]; + + msglen = virNetlinkGetNeighbor(&nlData, 0, 0); + if (msglen < 0) + return NULL; + + if (VIR_ALLOC(table) < 0) + return NULL; + + nh = (struct nlmsghdr*)nlData; + + while (NLMSG_OK(nh, msglen)) { + struct ndmsg *r = NLMSG_DATA(nh); + int len = nh->nlmsg_len; + void *addr; + + if ((len -= NLMSG_LENGTH(sizeof(*nh))) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("wrong nlmsg len")); + goto cleanup; + } + + if (r->ndm_family && (r->ndm_family != AF_INET)) + goto next_nlmsg; + + /* catch stale and reachalbe arp entry only */ + if (r->ndm_state && + (!(r->ndm_state == NUD_STALE || r->ndm_state == NUD_REACHABLE))) { + nh = NLMSG_NEXT(nh, msglen); + continue; + } + + if (nh->nlmsg_type == NLMSG_DONE) + goto end_of_netlink_messages; + + parse_rtattr(tb, NDA_MAX, NDA_RTA(r), + nh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); + + if (tb[NDA_DST] == NULL || tb[NDA_LLADDR] == NULL) + goto next_nlmsg; + + if (tb[NDA_DST]) { + virSocketAddr virAddr; + if (VIR_REALLOC_N(table->t, num + 1) < 0) + goto cleanup; + + table->n = num + 1; + + addr = RTA_DATA(tb[NDA_DST]); + bzero(&virAddr, sizeof(virAddr)); + virAddr.len = sizeof(virAddr.data.inet4); + virAddr.data.inet4.sin_family = AF_INET; + virAddr.data.inet4.sin_addr = *(struct in_addr *)addr; + ipstr = virSocketAddrFormat(&virAddr); + + if (VIR_STRDUP(table->t[num].ipaddr, ipstr) < 0) + goto cleanup; + + VIR_FREE(ipstr); + } + + if (tb[NDA_LLADDR]) { + virMacAddr macaddr; + char ifmac[VIR_MAC_STRING_BUFLEN]; + + addr = RTA_DATA(tb[NDA_LLADDR]); + memcpy(macaddr.addr, addr, VIR_MAC_BUFLEN); + + virMacAddrFormat(&macaddr, ifmac); + + if (VIR_STRDUP(table->t[num].mac, ifmac) < 0) + goto cleanup; + + num++; + } + + next_nlmsg: + nh = NLMSG_NEXT(nh, msglen); + } + + end_of_netlink_messages: + VIR_FREE(nlData); + return table; + + cleanup: + VIR_FREE(ipstr); + VIR_FREE(nlData); + return NULL; +} + +#else + +virArpTablePtr virArpTableGet(void) +{ + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("get arp table not implemented on this platform")); + return NULL; +} + +#endif /* __linux__ */ + +void +virArpTableFree(virArpTablePtr table) +{ + size_t i; + for (i = 0; i < table->n; i++) { + VIR_FREE(table->t[i].ipaddr); + VIR_FREE(table->t[i].mac); + } + VIR_FREE(table); +} diff --git a/src/util/virarptable.h b/src/util/virarptable.h new file mode 100644 index 000000000..404d8eb86 --- /dev/null +++ b/src/util/virarptable.h @@ -0,0 +1,48 @@ +/* + * virarptable.h Linux ARP table handling + * + * Copyright (C) 2018 Chen Hanxiao + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Chen Hanxiao <chenhanxiao@gmail.com> + */ + +#ifndef __VIR_ARPTABLE_H__ +# define __VIR_ARPTABLE_H__ + +# include "internal.h" +# include <linux/rtnetlink.h> + +typedef struct _virArpTableEntry virArpTableEntry; +typedef virArpTableEntry *virArpTableEntryPtr; +typedef struct _virArpTable virArpTable; +typedef virArpTable *virArpTablePtr; + +struct _virArpTableEntry{ + char *ipaddr; + char *mac; +}; + +struct _virArpTable { + int n; + virArpTableEntryPtr t; +}; + +virArpTablePtr virArpTableGet(void); +void virArpTableFree(virArpTablePtr table); + +#endif /* __VIR_ARPTABLE_H__ */ -- 2.14.3

On 03/08/2018 08:11 AM, Chen Hanxiao wrote:
From: Chen Hanxiao <chenhanxiao@gmail.com>
introduce helper to parse RTM_GETNEIGH query message and store it in struct virArpTable.
Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com> --- v4-rebase: fit split Makefile.am fit new virMacAddr fields
v4: use netlink query instead of parsing /proc/net/arp
v3: s/virGetArpTable/virArpTableGet alloc virArpTable in virArpTableGet return ENOSUPP on none-Linux platform move helpers to virarptable.[ch]
po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 5 ++ src/util/Makefile.inc.am | 2 + src/util/virarptable.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virarptable.h | 48 +++++++++++++ 6 files changed, 238 insertions(+) create mode 100644 src/util/virarptable.c create mode 100644 src/util/virarptable.h
diff --git a/po/POTFILES.in b/po/POTFILES.in index cfdd4ebdd..71c61dec9 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -192,6 +192,7 @@ src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c src/util/viralloc.c +src/util/virarptable.c src/util/viraudit.c src/util/virauth.c src/util/virauthconfig.c diff --git a/src/Makefile.am b/src/Makefile.am index 8b1e4c8a4..82c5d5cde 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -672,6 +672,7 @@ noinst_LTLIBRARIES += libvirt-setuid-rpc-client.la libvirt_setuid_rpc_client_la_SOURCES = \ util/viralloc.c \ util/virarch.c \ + util/virarptable.c \ util/viratomic.c \ util/viratomic.h \ util/virbitmap.c \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 11b9f4937..05b0c5b0e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1365,6 +1365,11 @@ virArchGetWordSize; virArchToString;
+# util/virarptable.h +virArpTableFree; +virArpTableGet; + + # util/viraudit.h virAuditClose; virAuditEncode; diff --git a/src/util/Makefile.inc.am b/src/util/Makefile.inc.am index a91b30dca..02d9c42cc 100644 --- a/src/util/Makefile.inc.am +++ b/src/util/Makefile.inc.am @@ -5,6 +5,8 @@ UTIL_SOURCES = \ util/viralloc.h \ util/virarch.c \ util/virarch.h \ + util/virarptable.c \ + util/virarptable.h \ util/viratomic.c \ util/viratomic.h \ util/viraudit.c \ diff --git a/src/util/virarptable.c b/src/util/virarptable.c new file mode 100644 index 000000000..cb56338eb --- /dev/null +++ b/src/util/virarptable.c @@ -0,0 +1,181 @@ +/* + * virarptable.c Linux ARP table handling + * + * Copyright (C) 2018 Chen Hanxiao + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Chen Hanxiao <chenhanxiao@gmail.com> + */ + +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <arpa/inet.h> + +#include "viralloc.h" +#include "virarptable.h" +#include "virfile.h" +#include "virlog.h" +#include "virnetlink.h" +#include "virsocketaddr.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("util.arptable"); + +#ifdef __linux__ + +# define NDA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) + +static int +parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + while (RTA_OK(rta, len)) { + if ((rta->rta_type <= max) && (!tb[rta->rta_type])) + tb[rta->rta_type] = rta; + rta = RTA_NEXT(rta, len); + } + + if (len) + VIR_WARN("malformed netlink message: Deficit %d, rta_len=%d", + len, rta->rta_len); + return 0; +} + +virArpTablePtr virArpTableGet(void) +{ + int num = 0; + int msglen; + void *nlData = NULL; + virArpTablePtr table = NULL; + char *ipstr = NULL; + struct nlmsghdr* nh; + struct rtattr * tb[NDA_MAX+1]; + + msglen = virNetlinkGetNeighbor(&nlData, 0, 0); + if (msglen < 0) + return NULL; + + if (VIR_ALLOC(table) < 0) + return NULL; + + nh = (struct nlmsghdr*)nlData; + + while (NLMSG_OK(nh, msglen)) { + struct ndmsg *r = NLMSG_DATA(nh); + int len = nh->nlmsg_len; + void *addr; + + if ((len -= NLMSG_LENGTH(sizeof(*nh))) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("wrong nlmsg len")); + goto cleanup; + } + + if (r->ndm_family && (r->ndm_family != AF_INET)) + goto next_nlmsg; + + /* catch stale and reachalbe arp entry only */ + if (r->ndm_state && + (!(r->ndm_state == NUD_STALE || r->ndm_state == NUD_REACHABLE))) { + nh = NLMSG_NEXT(nh, msglen); + continue; + } + + if (nh->nlmsg_type == NLMSG_DONE) + goto end_of_netlink_messages; + + parse_rtattr(tb, NDA_MAX, NDA_RTA(r), + nh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); + + if (tb[NDA_DST] == NULL || tb[NDA_LLADDR] == NULL) + goto next_nlmsg; + + if (tb[NDA_DST]) { + virSocketAddr virAddr; + if (VIR_REALLOC_N(table->t, num + 1) < 0) + goto cleanup; + + table->n = num + 1; + + addr = RTA_DATA(tb[NDA_DST]); + bzero(&virAddr, sizeof(virAddr)); + virAddr.len = sizeof(virAddr.data.inet4); + virAddr.data.inet4.sin_family = AF_INET; + virAddr.data.inet4.sin_addr = *(struct in_addr *)addr; + ipstr = virSocketAddrFormat(&virAddr); + + if (VIR_STRDUP(table->t[num].ipaddr, ipstr) < 0) + goto cleanup; + + VIR_FREE(ipstr); + } + + if (tb[NDA_LLADDR]) { + virMacAddr macaddr; + char ifmac[VIR_MAC_STRING_BUFLEN]; + + addr = RTA_DATA(tb[NDA_LLADDR]); + memcpy(macaddr.addr, addr, VIR_MAC_BUFLEN); + + virMacAddrFormat(&macaddr, ifmac); + + if (VIR_STRDUP(table->t[num].mac, ifmac) < 0) + goto cleanup; + + num++; + } + + next_nlmsg: + nh = NLMSG_NEXT(nh, msglen); + } + + end_of_netlink_messages: + VIR_FREE(nlData); + return table; + + cleanup: + VIR_FREE(ipstr); + VIR_FREE(nlData); + return NULL; +} + +#else + +virArpTablePtr virArpTableGet(void) +{ + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("get arp table not implemented on this platform")); + return NULL; +} + +#endif /* __linux__ */ + +void +virArpTableFree(virArpTablePtr table) +{ + size_t i; + for (i = 0; i < table->n; i++) { + VIR_FREE(table->t[i].ipaddr); + VIR_FREE(table->t[i].mac); + }
You need to free table->t too.
+ VIR_FREE(table); +}
Michal

On 03/08/2018 02:11 AM, Chen Hanxiao wrote:
From: Chen Hanxiao <chenhanxiao@gmail.com>
introduce helper to parse RTM_GETNEIGH query message and store it in struct virArpTable.
Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com> --- v4-rebase: fit split Makefile.am fit new virMacAddr fields
v4: use netlink query instead of parsing /proc/net/arp
v3: s/virGetArpTable/virArpTableGet alloc virArpTable in virArpTableGet return ENOSUPP on none-Linux platform move helpers to virarptable.[ch]
po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 5 ++ src/util/Makefile.inc.am | 2 + src/util/virarptable.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virarptable.h | 48 +++++++++++++ 6 files changed, 238 insertions(+) create mode 100644 src/util/virarptable.c create mode 100644 src/util/virarptable.h
Couple of Coverity issues.... [...]
diff --git a/src/util/virarptable.c b/src/util/virarptable.c new file mode 100644 index 000000000..cb56338eb --- /dev/null +++ b/src/util/virarptable.c
[...]
+# define NDA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) + +static int +parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + while (RTA_OK(rta, len)) { + if ((rta->rta_type <= max) && (!tb[rta->rta_type])) + tb[rta->rta_type] = rta; + rta = RTA_NEXT(rta, len); + } + + if (len) + VIR_WARN("malformed netlink message: Deficit %d, rta_len=%d", + len, rta->rta_len); + return 0; +} + +virArpTablePtr virArpTableGet(void)
As an aside - this format is non standard, should be virArpTablePtr virArpTableGet(void) and there should be 2 blank lines between functions.
+{ + int num = 0; + int msglen; + void *nlData = NULL; + virArpTablePtr table = NULL; + char *ipstr = NULL; + struct nlmsghdr* nh; + struct rtattr * tb[NDA_MAX+1]; + + msglen = virNetlinkGetNeighbor(&nlData, 0, 0); + if (msglen < 0) + return NULL; + + if (VIR_ALLOC(table) < 0) + return NULL; + + nh = (struct nlmsghdr*)nlData; + + while (NLMSG_OK(nh, msglen)) { + struct ndmsg *r = NLMSG_DATA(nh); + int len = nh->nlmsg_len; + void *addr; + + if ((len -= NLMSG_LENGTH(sizeof(*nh))) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("wrong nlmsg len")); + goto cleanup; + } + + if (r->ndm_family && (r->ndm_family != AF_INET)) + goto next_nlmsg; + + /* catch stale and reachalbe arp entry only */ + if (r->ndm_state && + (!(r->ndm_state == NUD_STALE || r->ndm_state == NUD_REACHABLE))) { + nh = NLMSG_NEXT(nh, msglen); + continue; + } + + if (nh->nlmsg_type == NLMSG_DONE) + goto end_of_netlink_messages; + + parse_rtattr(tb, NDA_MAX, NDA_RTA(r), + nh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); + + if (tb[NDA_DST] == NULL || tb[NDA_LLADDR] == NULL) + goto next_nlmsg; + + if (tb[NDA_DST]) { + virSocketAddr virAddr; + if (VIR_REALLOC_N(table->t, num + 1) < 0) + goto cleanup; + + table->n = num + 1; + + addr = RTA_DATA(tb[NDA_DST]); + bzero(&virAddr, sizeof(virAddr)); + virAddr.len = sizeof(virAddr.data.inet4); + virAddr.data.inet4.sin_family = AF_INET; + virAddr.data.inet4.sin_addr = *(struct in_addr *)addr; + ipstr = virSocketAddrFormat(&virAddr); + + if (VIR_STRDUP(table->t[num].ipaddr, ipstr) < 0) + goto cleanup; + + VIR_FREE(ipstr); + } + + if (tb[NDA_LLADDR]) { + virMacAddr macaddr; + char ifmac[VIR_MAC_STRING_BUFLEN]; + + addr = RTA_DATA(tb[NDA_LLADDR]); + memcpy(macaddr.addr, addr, VIR_MAC_BUFLEN); + + virMacAddrFormat(&macaddr, ifmac); + + if (VIR_STRDUP(table->t[num].mac, ifmac) < 0) + goto cleanup; + + num++; + } + + next_nlmsg: + nh = NLMSG_NEXT(nh, msglen); + } + + end_of_netlink_messages: + VIR_FREE(nlData); + return table; + + cleanup:
If we end up here, then @table (and anything that's allocated into it) is leaked
+ VIR_FREE(ipstr); + VIR_FREE(nlData); + return NULL; +} + +#else + +virArpTablePtr virArpTableGet(void)
Similar comment here about the format...
+{ + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("get arp table not implemented on this platform")); + return NULL; +} + +#endif /* __linux__ */ + +void +virArpTableFree(virArpTablePtr table) +{ + size_t i;
This can be called by qemuARPGetInterfaces when @table == NULL, so it would be good to put in a "if (!table) return;" right here
+ for (i = 0; i < table->n; i++) { + VIR_FREE(table->t[i].ipaddr); + VIR_FREE(table->t[i].mac); + } + VIR_FREE(table); +}
John [...]

At 2018-03-16 18:53:58, "John Ferlan" <jferlan@redhat.com> wrote:
On 03/08/2018 02:11 AM, Chen Hanxiao wrote:
From: Chen Hanxiao <chenhanxiao@gmail.com>
introduce helper to parse RTM_GETNEIGH query message and store it in struct virArpTable.
Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com> --- v4-rebase: fit split Makefile.am fit new virMacAddr fields
v4: use netlink query instead of parsing /proc/net/arp
v3: s/virGetArpTable/virArpTableGet alloc virArpTable in virArpTableGet return ENOSUPP on none-Linux platform move helpers to virarptable.[ch]
po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 5 ++ src/util/Makefile.inc.am | 2 + src/util/virarptable.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virarptable.h | 48 +++++++++++++ 6 files changed, 238 insertions(+) create mode 100644 src/util/virarptable.c create mode 100644 src/util/virarptable.h
Couple of Coverity issues....
Thanks, will be fixed soon. Regards, - Chen

From: Chen Hanxiao <chenhanxiao@gmail.com> introduce VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP to get ip address of VM from the message of netlink RTM_GETNEIGH Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com> --- v4: remove dummy entry use VIR_APPEND_ELEMENT v3: add docs in virDomainInterfaceAddresses remove error label show network interface which did not match the arp table include/libvirt/libvirt-domain.h | 1 + src/libvirt-domain.c | 7 ++++ src/qemu/qemu_driver.c | 72 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 4048acf38..38e2d9a3e 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -4665,6 +4665,7 @@ typedef virMemoryParameter *virMemoryParameterPtr; typedef enum { VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE = 0, /* Parse DHCP lease file */ VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT = 1, /* Query qemu guest agent */ + VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP = 2, /* Query ARP tables */ # ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LAST diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index eaec0979a..1ae83610d 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -11721,6 +11721,13 @@ virDomainFSInfoFree(virDomainFSInfoPtr info) * To match such interface with the one from @dom XML use MAC address or IP * range. * + * If @source is VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP, the /proc/net/arp + * will be check to obtain the interface addresses. + * As the arp cache did not refresh in time, the returned ip address + * may be unreachable. + * As the route config of the guest, the returned mac address + * may be duplicated. + * * @ifaces->name and @ifaces->hwaddr are never NULL. * * The caller *must* free @ifaces when no longer needed. Usual use case diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9e715e7a0..7d77e1643 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -70,6 +70,7 @@ #include "virnetdevopenvswitch.h" #include "capabilities.h" #include "viralloc.h" +#include "virarptable.h" #include "viruuid.h" #include "domain_conf.h" #include "domain_audit.h" @@ -157,6 +158,9 @@ static int qemuGetDHCPInterfaces(virDomainPtr dom, virDomainObjPtr vm, virDomainInterfacePtr **ifaces); +static int qemuARPGetInterfaces(virDomainObjPtr vm, + virDomainInterfacePtr **ifaces); + static virQEMUDriverPtr qemu_driver; @@ -20516,6 +20520,10 @@ qemuDomainInterfaceAddresses(virDomainPtr dom, break; + case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP: + ret = qemuARPGetInterfaces(vm, ifaces); + break; + default: virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, _("Unknown IP address data source %d"), @@ -20625,6 +20633,70 @@ qemuGetDHCPInterfaces(virDomainPtr dom, } +static int +qemuARPGetInterfaces(virDomainObjPtr vm, + virDomainInterfacePtr **ifaces) +{ + size_t i, j; + size_t ifaces_count = 0; + int ret = -1; + char macaddr[VIR_MAC_STRING_BUFLEN]; + virDomainInterfacePtr *ifaces_ret = NULL; + virDomainInterfacePtr iface = NULL; + virArpTablePtr table; + + table = virArpTableGet(); + if (!table) + goto cleanup; + + for (i = 0; i < vm->def->nnets; i++) { + if (vm->def->nets[i]->type != VIR_DOMAIN_NET_TYPE_NETWORK) + continue; + + virMacAddrFormat(&(vm->def->nets[i]->mac), macaddr); + virArpTableEntry entry; + for (j = 0; j < table->n; j++) { + entry = table->t[j]; + if (STREQ(entry.mac, macaddr)) { + if (VIR_ALLOC(iface) < 0) + goto cleanup; + + iface->naddrs = 1; + if (VIR_STRDUP(iface->name, vm->def->nets[i]->ifname) < 0) + goto cleanup; + + if (VIR_STRDUP(iface->hwaddr, macaddr) < 0) + goto cleanup; + + if (VIR_ALLOC_N(iface->addrs, iface->naddrs) < 0) + goto cleanup; + + if (VIR_STRDUP(iface->addrs->addr, entry.ipaddr) < 0) + goto cleanup; + + if (VIR_APPEND_ELEMENT(ifaces_ret, ifaces_count, iface) < 0) + goto cleanup; + + } + } + } + + VIR_STEAL_PTR(*ifaces, ifaces_ret); + ret = ifaces_count; + + cleanup: + virArpTableFree(table); + + if (ifaces_ret) { + for (i = 0; i < ifaces_count; i++) + virDomainInterfaceFree(ifaces_ret[i]); + } + VIR_FREE(ifaces_ret); + + return ret; +} + + static int qemuDomainSetUserPassword(virDomainPtr dom, const char *user, -- 2.14.3

On 03/08/2018 08:11 AM, Chen Hanxiao wrote:
From: Chen Hanxiao <chenhanxiao@gmail.com>
introduce VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP to get ip address of VM from the message of netlink RTM_GETNEIGH
Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com> --- v4: remove dummy entry use VIR_APPEND_ELEMENT
v3: add docs in virDomainInterfaceAddresses remove error label show network interface which did not match the arp table
include/libvirt/libvirt-domain.h | 1 + src/libvirt-domain.c | 7 ++++ src/qemu/qemu_driver.c | 72 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 4048acf38..38e2d9a3e 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -4665,6 +4665,7 @@ typedef virMemoryParameter *virMemoryParameterPtr; typedef enum { VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE = 0, /* Parse DHCP lease file */ VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT = 1, /* Query qemu guest agent */ + VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP = 2, /* Query ARP tables */
# ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LAST diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index eaec0979a..1ae83610d 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -11721,6 +11721,13 @@ virDomainFSInfoFree(virDomainFSInfoPtr info) * To match such interface with the one from @dom XML use MAC address or IP * range. * + * If @source is VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP, the /proc/net/arp + * will be check to obtain the interface addresses.
This should rather say 'arp table' because we are not obtaining the arp table through /proc file anymore.
+ * As the arp cache did not refresh in time, the returned ip address + * may be unreachable. + * As the route config of the guest, the returned mac address + * may be duplicated. + * * @ifaces->name and @ifaces->hwaddr are never NULL. * * The caller *must* free @ifaces when no longer needed. Usual use case diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9e715e7a0..7d77e1643 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -70,6 +70,7 @@ #include "virnetdevopenvswitch.h" #include "capabilities.h" #include "viralloc.h" +#include "virarptable.h" #include "viruuid.h" #include "domain_conf.h" #include "domain_audit.h" @@ -157,6 +158,9 @@ static int qemuGetDHCPInterfaces(virDomainPtr dom, virDomainObjPtr vm, virDomainInterfacePtr **ifaces);
+static int qemuARPGetInterfaces(virDomainObjPtr vm, + virDomainInterfacePtr **ifaces); + static virQEMUDriverPtr qemu_driver;
@@ -20516,6 +20520,10 @@ qemuDomainInterfaceAddresses(virDomainPtr dom,
break;
+ case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP: + ret = qemuARPGetInterfaces(vm, ifaces); + break; + default: virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, _("Unknown IP address data source %d"), @@ -20625,6 +20633,70 @@ qemuGetDHCPInterfaces(virDomainPtr dom, }
+static int +qemuARPGetInterfaces(virDomainObjPtr vm, + virDomainInterfacePtr **ifaces) +{ + size_t i, j; + size_t ifaces_count = 0; + int ret = -1; + char macaddr[VIR_MAC_STRING_BUFLEN]; + virDomainInterfacePtr *ifaces_ret = NULL; + virDomainInterfacePtr iface = NULL; + virArpTablePtr table; + + table = virArpTableGet(); + if (!table) + goto cleanup; + + for (i = 0; i < vm->def->nnets; i++) { + if (vm->def->nets[i]->type != VIR_DOMAIN_NET_TYPE_NETWORK) + continue; + + virMacAddrFormat(&(vm->def->nets[i]->mac), macaddr); + virArpTableEntry entry;
When declaring variables in a block the same rules apply as when doing so at top level. That is, this @entry declaration should be the first line in this block. Alternatively, it can be declared in the next for loop.
+ for (j = 0; j < table->n; j++) { + entry = table->t[j]; + if (STREQ(entry.mac, macaddr)) { + if (VIR_ALLOC(iface) < 0) + goto cleanup; + + iface->naddrs = 1; + if (VIR_STRDUP(iface->name, vm->def->nets[i]->ifname) < 0) + goto cleanup; + + if (VIR_STRDUP(iface->hwaddr, macaddr) < 0) + goto cleanup; + + if (VIR_ALLOC_N(iface->addrs, iface->naddrs) < 0) + goto cleanup; + + if (VIR_STRDUP(iface->addrs->addr, entry.ipaddr) < 0) + goto cleanup; + + if (VIR_APPEND_ELEMENT(ifaces_ret, ifaces_count, iface) < 0) + goto cleanup; + + } + } + } + + VIR_STEAL_PTR(*ifaces, ifaces_ret); + ret = ifaces_count; + + cleanup: + virArpTableFree(table); + + if (ifaces_ret) { + for (i = 0; i < ifaces_count; i++) + virDomainInterfaceFree(ifaces_ret[i]); + } + VIR_FREE(ifaces_ret); + + return ret; +} + + static int qemuDomainSetUserPassword(virDomainPtr dom, const char *user,
Michal

On 03/08/2018 02:11 AM, Chen Hanxiao wrote:
From: Chen Hanxiao <chenhanxiao@gmail.com>
introduce VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP to get ip address of VM from the message of netlink RTM_GETNEIGH
Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com> --- v4: remove dummy entry use VIR_APPEND_ELEMENT
v3: add docs in virDomainInterfaceAddresses remove error label show network interface which did not match the arp table
include/libvirt/libvirt-domain.h | 1 + src/libvirt-domain.c | 7 ++++ src/qemu/qemu_driver.c | 72 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+)
More Coverity found issues... [...]
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9e715e7a0..7d77e1643 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c
[...]
+static int +qemuARPGetInterfaces(virDomainObjPtr vm, + virDomainInterfacePtr **ifaces) +{ + size_t i, j; + size_t ifaces_count = 0; + int ret = -1; + char macaddr[VIR_MAC_STRING_BUFLEN]; + virDomainInterfacePtr *ifaces_ret = NULL; + virDomainInterfacePtr iface = NULL; + virArpTablePtr table; + + table = virArpTableGet(); + if (!table) + goto cleanup; + + for (i = 0; i < vm->def->nnets; i++) { + if (vm->def->nets[i]->type != VIR_DOMAIN_NET_TYPE_NETWORK) + continue; + + virMacAddrFormat(&(vm->def->nets[i]->mac), macaddr); + virArpTableEntry entry; + for (j = 0; j < table->n; j++) { + entry = table->t[j]; + if (STREQ(entry.mac, macaddr)) { + if (VIR_ALLOC(iface) < 0) + goto cleanup;
Prior to getting to the VIR_APPEND_ELEMENT, we can jump to cleanup and we leak @iface and everything that's been allocated within @iface.
+ + iface->naddrs = 1; + if (VIR_STRDUP(iface->name, vm->def->nets[i]->ifname) < 0) + goto cleanup; + + if (VIR_STRDUP(iface->hwaddr, macaddr) < 0) + goto cleanup; + + if (VIR_ALLOC_N(iface->addrs, iface->naddrs) < 0) + goto cleanup; + + if (VIR_STRDUP(iface->addrs->addr, entry.ipaddr) < 0) + goto cleanup; + + if (VIR_APPEND_ELEMENT(ifaces_ret, ifaces_count, iface) < 0) + goto cleanup; + + } + } + } + + VIR_STEAL_PTR(*ifaces, ifaces_ret); + ret = ifaces_count; + + cleanup: + virArpTableFree(table);
As noted in patch2, we can get here if table == NULL when virArpTableGet fails, so either we fix it here or in the API itself. The API should be fixed rather than here...
+ + if (ifaces_ret) { + for (i = 0; i < ifaces_count; i++) + virDomainInterfaceFree(ifaces_ret[i]); + } + VIR_FREE(ifaces_ret); + + return ret; +} + + static int qemuDomainSetUserPassword(virDomainPtr dom, const char *user,

From: Chen Hanxiao <chenhanxiao@gmail.com> We can use: domifaddr f26-cloud --source arp to get the address. Acked-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com> --- tools/virsh-domain-monitor.c | 2 ++ tools/virsh.pod | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 32a42707e..68da11ed5 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -2190,6 +2190,8 @@ cmdDomIfAddr(vshControl *ctl, const vshCmd *cmd) source = VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE; } else if (STREQ(sourcestr, "agent")) { source = VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT; + } else if (STREQ(sourcestr, "arp")) { + source = VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP; } else { vshError(ctl, _("Unknown data source '%s'"), sourcestr); goto cleanup; diff --git a/tools/virsh.pod b/tools/virsh.pod index 8f0e8d74b..515f18fdc 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -759,7 +759,7 @@ B<Explanation of fields> (fields appear in the following order): =item B<domifaddr> I<domain> [I<interface>] [I<--full>] - [I<--source lease|agent>] + [I<--source lease|agent|arp>] Get a list of interfaces of a running domain along with their IP and MAC addresses, or limited output just for one interface if I<interface> is @@ -774,8 +774,9 @@ only the interface name and MAC address is displayed for the first name and MAC address with "-" for the others using the same name and MAC address. The I<--source> argument specifies what data source to use for the -addresses, currently one of 'lease' to read DHCP leases, or 'agent' to query -the guest OS via an agent. If unspecified, 'lease' is the default. +addresses, currently 'lease' to read DHCP leases, 'agent' to query +the guest OS via an agent, or 'arp' to get IP from host's arp tables. +If unspecified, 'lease' is the default. =item B<domifstat> I<domain> I<interface-device> -- 2.14.3

From: Chen Hanxiao <chenhanxiao@gmail.com> Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com> --- v4: rebase on 4.2 v3: more verbose description docs/news.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/news.xml b/docs/news.xml index a51ca973e..6d729d508 100644 --- a/docs/news.xml +++ b/docs/news.xml @@ -46,6 +46,15 @@ information, log the relevant data to the domain log file. </description> </change> + <change> + <summary> + qemu: use arp table of host to get the IP address of guests + </summary> + <description> + Find IP address of a VM by arp table on hosts. + If someone customizing IP address inside VM, it will be helpful. + </description> + </change> </section> <section title="Bug fixes"> </section> -- 2.14.3

On 03/08/2018 08:11 AM, Chen Hanxiao wrote:
introduce VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP to get ip address of VM from the output of /proc/net/arp
Chen Hanxiao (5): util: introduce virNetlinkGetNeighbor to get neighbor table entry util: introduce helper to parse message from RTM_GETNEIGH query qemu: introduce qemuARPGetInterfaces to get IP from host's arp table virsh: add --source arp to domifaddr news: qemu: use arp table of host to get the IP address of guests
docs/news.xml | 9 ++ include/libvirt/libvirt-domain.h | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt-domain.c | 7 ++ src/libvirt_private.syms | 6 ++ src/qemu/qemu_driver.c | 72 ++++++++++++++++ src/util/Makefile.inc.am | 2 + src/util/virarptable.c | 181 +++++++++++++++++++++++++++++++++++++++ src/util/virarptable.h | 48 +++++++++++ src/util/virnetlink.c | 82 ++++++++++++++++++ src/util/virnetlink.h | 2 + tools/virsh-domain-monitor.c | 2 + tools/virsh.pod | 7 +- 14 files changed, 418 insertions(+), 3 deletions(-) create mode 100644 src/util/virarptable.c create mode 100644 src/util/virarptable.h
I've fixed both small issues I raised, ACKed and pushed. Michal

At 2018-03-15 18:23:03, "Michal Privoznik" <mprivozn@redhat.com> wrote:
On 03/08/2018 08:11 AM, Chen Hanxiao wrote:
introduce VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP to get ip address of VM from the output of /proc/net/arp
Chen Hanxiao (5): util: introduce virNetlinkGetNeighbor to get neighbor table entry util: introduce helper to parse message from RTM_GETNEIGH query qemu: introduce qemuARPGetInterfaces to get IP from host's arp table virsh: add --source arp to domifaddr news: qemu: use arp table of host to get the IP address of guests
docs/news.xml | 9 ++ include/libvirt/libvirt-domain.h | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt-domain.c | 7 ++ src/libvirt_private.syms | 6 ++ src/qemu/qemu_driver.c | 72 ++++++++++++++++ src/util/Makefile.inc.am | 2 + src/util/virarptable.c | 181 +++++++++++++++++++++++++++++++++++++++ src/util/virarptable.h | 48 +++++++++++ src/util/virnetlink.c | 82 ++++++++++++++++++ src/util/virnetlink.h | 2 + tools/virsh-domain-monitor.c | 2 + tools/virsh.pod | 7 +- 14 files changed, 418 insertions(+), 3 deletions(-) create mode 100644 src/util/virarptable.c create mode 100644 src/util/virarptable.h
I've fixed both small issues I raised, ACKed and pushed.
Thanks. Regards, - Chen

At 2018-03-08 15:11:54, "Chen Hanxiao" <chen_han_xiao@126.com> wrote:
introduce VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP to get ip address of VM from the output of /proc/net/arp
Chen Hanxiao (5): util: introduce virNetlinkGetNeighbor to get neighbor table entry util: introduce helper to parse message from RTM_GETNEIGH query qemu: introduce qemuARPGetInterfaces to get IP from host's arp table virsh: add --source arp to domifaddr news: qemu: use arp table of host to get the IP address of guests
docs/news.xml | 9 ++ include/libvirt/libvirt-domain.h | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt-domain.c | 7 ++ src/libvirt_private.syms | 6 ++ src/qemu/qemu_driver.c | 72 ++++++++++++++++ src/util/Makefile.inc.am | 2 + src/util/virarptable.c | 181 +++++++++++++++++++++++++++++++++++++++ src/util/virarptable.h | 48 +++++++++++ src/util/virnetlink.c | 82 ++++++++++++++++++ src/util/virnetlink.h | 2 + tools/virsh-domain-monitor.c | 2 + tools/virsh.pod | 7 +- 14 files changed, 418 insertions(+), 3 deletions(-) create mode 100644 src/util/virarptable.c create mode 100644 src/util/virarptable.h
--
ping Regards, - Chen
participants (3)
-
Chen Hanxiao
-
John Ferlan
-
Michal Privoznik