[libvirt] [PATCH rebase v4 2/5] util: introduce helper to parse message from RTM_GETNEIGH query
John Ferlan
jferlan at redhat.com
Fri Mar 16 10:53:58 UTC 2018
On 03/08/2018 02: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
>
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
[...]
More information about the libvir-list
mailing list