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

Michal Privoznik mprivozn at redhat.com
Thu Mar 15 10:22:59 UTC 2018


On 03/08/2018 08:11 AM, Chen Hanxiao wrote:
> 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-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 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);
> +
> +          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




More information about the libvir-list mailing list