[libvirt] [PATCH v4 2/5] util: introduce helper to parse message from RTM_GETNEIGH query

Chen Hanxiao chen_han_xiao at 126.com
Thu Feb 8 07:47:01 UTC 2018


From: Chen Hanxiao <chenhanxiao at gmail.com>

introduce helper to parse RTM_GETNEIGH query message and
store it in struct virArpTable.

Signed-off-by: Chen Hanxiao <chenhanxiao at gmail.com>
---
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/virarptable.c   | 182 +++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virarptable.h   |  47 ++++++++++++
 5 files changed, 236 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 cbf2accba..0f2ba7490 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -193,6 +193,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 79adc9ba5..dd79b58e0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -98,6 +98,7 @@ augeastest_DATA =
 UTIL_SOURCES = \
 		util/viralloc.c util/viralloc.h \
 		util/virarch.h util/virarch.c \
+		util/virarptable.h util/virarptable.c \
 		util/viratomic.h util/viratomic.c \
 		util/viraudit.c util/viraudit.h \
 		util/virauth.c util/virauth.h \
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d90eb3dde..1167220f2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1346,6 +1346,11 @@ virArchGetWordSize;
 virArchToString;
 
 
+# util/virarptable.h
+virArpTableFree;
+virArpTableGet;
+
+
 # util/viraudit.h
 virAuditClose;
 virAuditEncode;
diff --git a/src/util/virarptable.c b/src/util/virarptable.c
new file mode 100644
index 000000000..cbf085403
--- /dev/null
+++ b/src/util/virarptable.c
@@ -0,0 +1,182 @@
+/*
+ * 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 at 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);
+          macaddr.generated = false;
+
+          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..682919812
--- /dev/null
+++ b/src/util/virarptable.h
@@ -0,0 +1,47 @@
+/*
+ * 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 at gmail.com>
+ */
+
+#ifndef __VIR_ARPTABLE_H__
+# define __VIR_ARPTABLE_H__
+
+# include "internal.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




More information about the libvir-list mailing list