On 03/08/2018 02:11 AM, Chen Hanxiao wrote:
From: Chen Hanxiao <chenhanxiao(a)gmail.com>
introduce helper to parse RTM_GETNEIGH query message and
store it in struct virArpTable.
Signed-off-by: Chen Hanxiao <chenhanxiao(a)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
[...]