Changeset
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
Git apply log
Switched to a new branch '20180308071159.9861-1-chen_han_xiao@126.com'
Applying: util: introduce virNetlinkGetNeighbor to get neighbor table entry
Applying: util: introduce helper to parse message from RTM_GETNEIGH query
Applying: qemu: introduce qemuARPGetInterfaces to get IP from host's arp table
Applying: virsh: add --source arp to domifaddr
Applying: news: qemu: use arp table of host to get the IP address of guests
To https://github.com/patchew-project/libvirt
 * [new tag]             patchew/20180308071159.9861-1-chen_han_xiao@126.com -> patchew/20180308071159.9861-1-chen_han_xiao@126.com
Test passed: syntax-check

loading

[libvirt] [PATCH rebase v4 0/5] qemu: use arp table of host to get the
Posted by Chen Hanxiao, 15 weeks ago
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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH rebase v4 0/5] qemu: use arp table of host to get the
Posted by Chen Hanxiao, 14 weeks ago


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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH rebase v4 0/5] qemu: use arp table of host to get the
Posted by Michal Privoznik, 14 weeks ago
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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH rebase v4 0/5] qemu: use arp table of host to get the
Posted by Chen Hanxiao, 14 weeks ago

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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH rebase v4 1/5] util: introduce virNetlinkGetNeighbor to get neighbor table entry
Posted by Chen Hanxiao, 15 weeks ago
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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH rebase v4 2/5] util: introduce helper to parse message from RTM_GETNEIGH query
Posted by Chen Hanxiao, 15 weeks ago
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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH rebase v4 2/5] util: introduce helper to parse message from RTM_GETNEIGH query
Posted by Michal Privoznik, 14 weeks ago
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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH rebase v4 2/5] util: introduce helper to parse message from RTM_GETNEIGH query
Posted by John Ferlan, 14 weeks ago

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

[...]

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH rebase v4 2/5] util: introduce helper to parse message from RTM_GETNEIGH query
Posted by Chen Hanxiao, 14 weeks ago

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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH rebase v4 3/5] qemu: introduce qemuARPGetInterfaces to get IP from host's arp table
Posted by Chen Hanxiao, 15 weeks ago
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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH rebase v4 3/5] qemu: introduce qemuARPGetInterfaces to get IP from host's arp table
Posted by Michal Privoznik, 14 weeks ago
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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH rebase v4 3/5] qemu: introduce qemuARPGetInterfaces to get IP from host's arp table
Posted by John Ferlan, 14 weeks ago

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,
> 

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH rebase v4 4/5] virsh: add --source arp to domifaddr
Posted by Chen Hanxiao, 15 weeks ago
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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH rebase v4 5/5] news: qemu: use arp table of host to get the IP address of guests
Posted by Chen Hanxiao, 15 weeks ago
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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list