[libvirt] [PATCHv2 1/2] util: Functions to update host network device's multicast filter

From: Tony Krowiak <akrowiak@linux.vnet.ibm.com> This patch provides the utility functions to needed to synchronize the changes made to a guest domain network device's multicast filter with the corresponding macvtap device's filter on the host: * Get/add/remove multicast MAC addresses * Get the macvtap device's RX filter list Signed-off-by: Tony Krowiak <akrowiak@linux.vnet.ibm.com> --- Changes from V1: * Using virHexToBin function to parse HEX MAC address instead of sscanf in virMacAddrParseHex function * Using ENOSYS in error messages for empty functions * Reading entire file with virFileReadAll function when parsing /proc/net/dev_mcast file * Using VIR_APPEND_ELEMENT macro when appending array of /proc/net/dev_mcast file objects * Misc. formatting changes src/libvirt_private.syms | 4 + src/util/virmacaddr.c | 37 +++++ src/util/virmacaddr.h | 4 + src/util/virnetdev.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virnetdev.h | 11 ++ 5 files changed, 416 insertions(+), 0 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d6265ac..6d06a2c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1590,13 +1590,16 @@ virMacAddrIsBroadcastRaw; virMacAddrIsMulticast; virMacAddrIsUnicast; virMacAddrParse; +virMacAddrParseHex; virMacAddrSet; virMacAddrSetRaw; # util/virnetdev.h +virNetDevAddMulti; virNetDevAddRoute; virNetDevClearIPv4Address; +virNetDevDelMulti; virNetDevExists; virNetDevGetIndex; virNetDevGetIPv4Address; @@ -1604,6 +1607,7 @@ virNetDevGetLinkInfo; virNetDevGetMAC; virNetDevGetMTU; virNetDevGetPhysicalFunction; +virNetDevGetRxFilter; virNetDevGetVirtualFunctionIndex; virNetDevGetVirtualFunctionInfo; virNetDevGetVirtualFunctions; diff --git a/src/util/virmacaddr.c b/src/util/virmacaddr.c index ebd1182..ae5e5d2 100644 --- a/src/util/virmacaddr.c +++ b/src/util/virmacaddr.c @@ -198,6 +198,43 @@ virMacAddrFormat(const virMacAddr *addr, return str; } +/** + * virMacAddrParseHex: + * @str: string hexadecimal representation of MAC address, e.g., "F801EFCE3aCB" + * @addr: 6-byte MAC address + * + * Parse the hexadecimal representation of a MAC address + * + * Return 0 upon success, or -1 in case of error. + */ +int +virMacAddrParseHex(const char* str, virMacAddrPtr addr) +{ + if (strlen(str) != VIR_MAC_HEXLEN) + return -1; + + size_t iaddr; + size_t istr; + + + for (istr = 0, iaddr = 0; iaddr < VIR_MAC_BUFLEN; istr += 2, iaddr++) { + unsigned int hex; + + if (sscanf(&str[istr], "%02x", &hex) != 1) + break; + + if (hex > UCHAR_MAX) + break; + + addr->addr[iaddr] = hex; + } + + if (istr == VIR_MAC_HEXLEN) + return 0; + + return -1; +} + void virMacAddrGenerate(const unsigned char prefix[VIR_MAC_PREFIX_BUFLEN], virMacAddrPtr addr) { diff --git a/src/util/virmacaddr.h b/src/util/virmacaddr.h index 49efc36..72a285a 100644 --- a/src/util/virmacaddr.h +++ b/src/util/virmacaddr.h @@ -27,6 +27,7 @@ # include "internal.h" # define VIR_MAC_BUFLEN 6 +#define VIR_MAC_HEXLEN (VIR_MAC_BUFLEN * 2) # define VIR_MAC_PREFIX_BUFLEN 3 # define VIR_MAC_STRING_BUFLEN (VIR_MAC_BUFLEN * 3) @@ -50,6 +51,9 @@ void virMacAddrGenerate(const unsigned char prefix[VIR_MAC_PREFIX_BUFLEN], virMacAddrPtr addr); int virMacAddrParse(const char* str, virMacAddrPtr addr) ATTRIBUTE_RETURN_CHECK; +int virMacAddrParseHex(const char* str, + virMacAddrPtr addr) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; bool virMacAddrIsUnicast(const virMacAddr *addr); bool virMacAddrIsMulticast(const virMacAddr *addr); bool virMacAddrIsBroadcastRaw(const unsigned char s[VIR_MAC_BUFLEN]); diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index db5623a..5e53f5f 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -56,6 +56,33 @@ VIR_LOG_INIT("util.netdev"); +# define VIR_MCAST_NAME_LEN (IFNAMSIZ + 1) +# define VIR_MCAST_INDEX_TOKEN_IDX 0 +# define VIR_MCAST_NAME_TOKEN_IDX 1 +# define VIR_MCAST_USERS_TOKEN_IDX 2 +# define VIR_MCAST_GLOBAL_TOKEN_IDX 3 +# define VIR_MCAST_ADDR_TOKEN_IDX 4 +# define VIR_MCAST_NUM_TOKENS 5 +# define VIR_MCAST_TOKEN_DELIMS " \n" +# define VIR_MCAST_ADDR_LEN (VIR_MAC_HEXLEN + 1) + +typedef struct _virNetDevMcastEntry virNetDevMcastEntry; +typedef virNetDevMcastEntry *virNetDevMcastEntryPtr; +struct _virNetDevMcastEntry { + int index; + char name[VIR_MCAST_NAME_LEN]; + int users; + bool global; + virMacAddr macaddr; +}; + +typedef struct _virNetDevMcast virNetDevMcast; +typedef virNetDevMcast *virNetDevMcastPtr; +struct _virNetDevMcast { + size_t nentries; + virNetDevMcastEntryPtr *entries; +}; + #if defined(HAVE_STRUCT_IFREQ) static int virNetDevSetupControlFull(const char *ifname, struct ifreq *ifr, @@ -1934,6 +1961,266 @@ virNetDevGetLinkInfo(const char *ifname, #endif /* defined(__linux__) */ +#if defined(SIOCADDMULTI) && defined(HAVE_STRUCT_IFREQ) +/** + * virNetDevAddMulti: + * @ifname: interface name to which to add multicast MAC address + * @macaddr: MAC address + * + * This function adds the @macaddr to the multicast list for a given interface + * @ifname. + * + * Returns 0 in case of success or -1 on failure + */ +int virNetDevAddMulti(const char *ifname, + virMacAddrPtr macaddr) +{ + int fd = -1; + int ret = -1; + struct ifreq ifr; + + if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0) + return -1; + + ifr.ifr_hwaddr.sa_family = AF_UNSPEC; + virMacAddrGetRaw(macaddr, (unsigned char *)ifr.ifr_hwaddr.sa_data); + + if (ioctl(fd, SIOCADDMULTI, &ifr) < 0) { + char macstr[VIR_MAC_STRING_BUFLEN]; + virReportSystemError(errno, + _("Cannot add multicast MAC %s on '%s' interface"), + virMacAddrFormat(macaddr, macstr), ifname); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FORCE_CLOSE(fd); + return ret; +} +#else +int virNetDevAddMulti(const char *ifname, + virMacAddrPtr macaddr ATTRIBUTE_UNUSED) +{ + char macstr[VIR_MAC_STRING_BUFLEN]; + virReportSystemError(errno, + _("Cannot add multicast MAC %s on '%s' interface"), + virMacAddrFormat(macaddr, macstr), ifname); + return -1; +} +#endif + +#if defined(SIOCDELMULTI) && defined(HAVE_STRUCT_IFREQ) +/** + * virNetDevDelMulti: + * @ifname: interface name from which to delete the multicast MAC address + * @macaddr: MAC address + * + * This function deletes the @macaddr from the multicast list for a given + * interface @ifname. + * + * Returns 0 in case of success or -1 on failure + */ +int virNetDevDelMulti(const char *ifname, + virMacAddrPtr macaddr) +{ + int fd = -1; + int ret = -1; + struct ifreq ifr; + + if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0) + return -1; + + ifr.ifr_hwaddr.sa_family = AF_UNSPEC; + virMacAddrGetRaw(macaddr, (unsigned char *)ifr.ifr_hwaddr.sa_data); + + if (ioctl(fd, SIOCDELMULTI, &ifr) < 0) { + char macstr[VIR_MAC_STRING_BUFLEN]; + virReportSystemError(errno, + _("Cannot add multicast MAC %s on '%s' interface"), + virMacAddrFormat(macaddr, macstr), ifname); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FORCE_CLOSE(fd); + return ret; +} +#else +int virNetDevDelMulti(const char *ifname, + virMacAddrPtr macaddr ATTRIBUTE_UNUSED) +{ + char macstr[VIR_MAC_STRING_BUFLEN]; + virReportSystemError(errno, + _("Cannot delete multicast MAC %s on '%s' interface"), + virMacAddrFormat(macaddr, macstr), ifname); + return -1; +} +#endif + +static int virNetDevParseMcast(char *buf, virNetDevMcastEntryPtr mcast) +{ + int ifindex; + int num; + char *next; + char *token; + char *saveptr; + char *endptr; + + for (ifindex = 0, next = buf; ifindex < VIR_MCAST_NUM_TOKENS; ifindex++, + next = NULL) { + token = strtok_r(next, VIR_MCAST_TOKEN_DELIMS, &saveptr); + + if (token == NULL) { + virReportSystemError(EINVAL, + _("failed to parse multicast address from '%s'"), + buf); + return -1; + } + + switch (ifindex) { + case VIR_MCAST_INDEX_TOKEN_IDX: + if (virStrToLong_i(token, &endptr, 10, &num) < 0) { + virReportSystemError(EINVAL, + _("Failed to parse index from '%s'"), + buf); + return -1; + + } + + mcast->index = num; + + break; + case VIR_MCAST_NAME_TOKEN_IDX: + if (virStrncpy(mcast->name, token, strlen(token), + VIR_MCAST_NAME_LEN) == NULL) { + virReportSystemError(EINVAL, + _("Failed to parse NIC name from '%s'"), + buf); + return -1; + } + + break; + case VIR_MCAST_USERS_TOKEN_IDX: + if (virStrToLong_i(token, &endptr, 10, &num) < 0) { + virReportSystemError(EINVAL, + _("Failed to parse users from '%s'"), + buf); + return -1; + + } + + mcast->users = num; + + break; + case VIR_MCAST_GLOBAL_TOKEN_IDX: + if (virStrToLong_i(token, &endptr, 10, &num) < 0) { + virReportSystemError(EINVAL, + _("Failed to parse users from '%s'"), + buf); + return -1; + + } + + mcast->global = num; + + break; + case VIR_MCAST_ADDR_TOKEN_IDX: + if (virMacAddrParseHex((const char*)token, + &mcast->macaddr) < 0) { + virReportSystemError(EINVAL, + _("Failed to parse MAC address from '%s'"), + buf); + } + + break; + default: + break; + } + } + + return 0; +} + + +static int virNetDevGetMcast(const char *ifname, + virNetDevMcastPtr mcast) +{ + FILE *file; + const char *path = "/proc/net/dev_mcast"; + char buf[256]; + int ret = -1; + virNetDevMcastEntry entry; + virNetDevMcastEntryPtr *entries = NULL; + size_t nentries = 0; + size_t entries_sz = 0; + size_t i; + mcast->entries = NULL; + mcast->nentries = 0; + + file = fopen(path, "r"); + + if (!file) { + virReportSystemError(errno, + _("cannot open multicast address file %s"), path); + return -1; + } + + while (fgets(buf, sizeof(buf), file)) { + if (virNetDevParseMcast(buf, &entry) < 0) { + goto error; + } + + if (entry.global && STREQ(ifname, entry.name)) { + if (VIR_RESIZE_N(entries, entries_sz, + nentries, 1) < 0) { + virReportSystemError(ENOMEM, + _("Failed to resize multicast MAC address array: " + "ptr=%p, alloc=%zu, count=%zu, add=1"), + entries, entries_sz, nentries); + goto error; + } + + if (VIR_ALLOC(entries[nentries]) < 0) { + char addr[VIR_MAC_STRING_BUFLEN]; + virReportSystemError(ENOMEM, + _("Failed to allocate storage for MAC address %s"), + virMacAddrFormat(&mcast->entries[nentries]->macaddr, + addr)); + goto error; + } + + memcpy(entries[nentries++], &entry, + sizeof(virNetDevMcastEntry)); + } + + memset(buf, 0, sizeof(buf)); + memset(&entry, 0, sizeof(virNetDevMcastEntry)); + } + + + mcast->nentries = nentries; + mcast->entries = entries; + ret = 0; + + error: + VIR_FORCE_FCLOSE(file); + + if ((ret < 0) && (nentries > 0)) { + for (i = 0; i < nentries; i++) { + VIR_FREE(entries[i]); + } + + VIR_FREE(entries); + } + + return ret; +} + + VIR_ENUM_IMPL(virNetDevRxFilterMode, VIR_NETDEV_RX_FILTER_MODE_LAST, "none", @@ -1941,6 +2228,37 @@ VIR_ENUM_IMPL(virNetDevRxFilterMode, "all"); +static int virNetDevGetMulticastTable(const char *ifname, + virNetDevRxFilterPtr filter) +{ + int i; + int ret = -1; + virNetDevMcast mcast; + filter->multicast.nTable = 0; + filter->multicast.table = NULL; + + if (virNetDevGetMcast(ifname, &mcast) < 0) + goto error; + + if (mcast.nentries > 0) { + if (VIR_ALLOC_N(filter->multicast.table, mcast.nentries)) + goto error; + + for (i = 0; i < mcast.nentries; i++) { + virMacAddrSet(&filter->multicast.table[i], + &mcast.entries[i]->macaddr); + } + + filter->multicast.nTable = mcast.nentries; + } + + ret = 0; + + error: + return ret; +} + + virNetDevRxFilterPtr virNetDevRxFilterNew(void) { @@ -1963,3 +2281,45 @@ virNetDevRxFilterFree(virNetDevRxFilterPtr filter) VIR_FREE(filter); } } + + +/** + * virNetDevGetRxFilter: + * This function supplies the RX filter list for a given device interface + * + * @ifname: Name of the interface + * @filter: The RX filter list + * + * Returns 0 or -1 on failure. + */ +int virNetDevGetRxFilter(const char *ifname, + virNetDevRxFilterPtr *filter) +{ + int ret = -1; + virNetDevRxFilterPtr fil = virNetDevRxFilterNew(); + + if (!fil) { + virReportSystemError(ENOMEM, + _("Failed to allocate filter for %s interface"), + ifname); + + } + + if (virNetDevGetMAC(ifname, &fil->mac)) + goto cleanup; + + if (virNetDevGetMulticastTable(ifname, fil)) + goto cleanup; + + ret = 0; + + cleanup: + if (ret < 0) { + virNetDevRxFilterFree(fil); + fil = NULL; + } + + *filter = fil; + + return ret; +} diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index 2a6e67d..1d274b3 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -30,6 +30,7 @@ # include "virmacaddr.h" # include "virpci.h" # include "device_conf.h" +# include "virutil.h" # ifdef HAVE_STRUCT_IFREQ typedef struct ifreq virIfreq; @@ -189,5 +190,15 @@ int virNetDevGetLinkInfo(const char *ifname, virNetDevRxFilterPtr virNetDevRxFilterNew(void) ATTRIBUTE_RETURN_CHECK; void virNetDevRxFilterFree(virNetDevRxFilterPtr filter); +int virNetDevGetRxFilter(const char *ifname, + virNetDevRxFilterPtr *filter) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + +int virNetDevAddMulti(const char *ifname, + virMacAddrPtr macaddr) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; +int virNetDevDelMulti(const char *ifname, + virMacAddrPtr macaddr) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; #endif /* __VIR_NETDEV_H__ */ -- 1.7.1

From: Tony Krowiak <akrowiak@linux.vnet.ibm.com> This patch adds functionality to processNicRxFilterChangedEvent(). The old and new multicast lists are compared and the filters in the macvtap are programmed to match the guest's filters. Signed-off-by: Tony Krowiak <akrowiak@linux.vnet.ibm.com> --- src/qemu/qemu_driver.c | 150 ++++++++++++++++++++++++++++++++++++++++-------- src/util/virmacaddr.c | 32 +++------- src/util/virnetdev.c | 149 ++++++++++++++++++++++++++--------------------- 3 files changed, 218 insertions(+), 113 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 7c9b1ab..cf1ae9c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4147,6 +4147,118 @@ processDeviceDeletedEvent(virQEMUDriverPtr driver, static void +syncNicRxFilterMacAddr(char *ifname, virNetDevRxFilterPtr guestFilter, + virNetDevRxFilterPtr hostFilter) +{ + char newMacStr[VIR_MAC_STRING_BUFLEN]; + + if (virMacAddrCmp(&hostFilter->mac, &guestFilter->mac)) { + virMacAddrFormat(&guestFilter->mac, newMacStr); + + /* set new MAC address from guest to associated macvtap device */ + if (virNetDevSetMAC(ifname, &guestFilter->mac)) { + VIR_WARN("Couldn't set new MAC address %s to device %s " + "while responding to NIC_RX_FILTER_CHANGED", + newMacStr, ifname); + } else { + VIR_DEBUG("device %s MAC address set to %s", ifname, newMacStr); + } + } +} + + +static void +syncNicRxFilterGuestMulticast(char *ifname, virNetDevRxFilterPtr guestFilter, + virNetDevRxFilterPtr hostFilter) +{ + size_t i, j; + bool found; + char macstr[VIR_MAC_STRING_BUFLEN]; + + for (i = 0; i < guestFilter->multicast.nTable; i++) { + found = false; + + for (j = 0; j < hostFilter->multicast.nTable; j++) { + if (virMacAddrCmp(&guestFilter->multicast.table[i], + &hostFilter->multicast.table[j]) == 0) { + found = true; + break; + } + } + + if (!found) { + virMacAddrFormat(&guestFilter->multicast.table[i], macstr); + + if (virNetDevAddMulti(ifname, &guestFilter->multicast.table[i])) { + VIR_WARN("Couldn't add new multicast MAC address %s to " + "device %s while responding to NIC_RX_FILTER_CHANGED", + macstr, ifname); + } else { + VIR_DEBUG("Added multicast MAC %s to %s interface", + macstr, ifname); + } + } + } +} + + +static void +syncNicRxFilterHostMulticast(char *ifname, virNetDevRxFilterPtr guestFilter, + virNetDevRxFilterPtr hostFilter) +{ + size_t i, j; + bool found; + char macstr[VIR_MAC_STRING_BUFLEN]; + + for (i = 0; i < hostFilter->multicast.nTable; i++) { + found = false; + + for (j = 0; j < guestFilter->multicast.nTable; j++) { + if (virMacAddrCmp(&hostFilter->multicast.table[i], + &guestFilter->multicast.table[j]) == 0) { + found = true; + break; + } + } + + if (!found) { + virMacAddrFormat(&hostFilter->multicast.table[i], macstr); + + if (virNetDevDelMulti(ifname, &hostFilter->multicast.table[i])) { + VIR_WARN("Couldn't delete multicast MAC address %s from " + "device %s while responding to NIC_RX_FILTER_CHANGED", + macstr, ifname); + } else { + VIR_DEBUG("Deleted multicast MAC %s from %s interface", + macstr, ifname); + } + } + } +} + + +static void +syncNicRxFilterMulticast(char *ifname, + virNetDevRxFilterPtr guestFilter, + virNetDevRxFilterPtr hostFilter) +{ +VIR_DEBUG("RXFILTER: guest multicast list:"); +if (guestFilter->multicast.nTable) { +char addr[VIR_MAC_STRING_BUFLEN]; +for (size_t i = 0; i < guestFilter->multicast.nTable; i++) { +VIR_DEBUG("RXFILTER: %s", virMacAddrFormat(&guestFilter->multicast.table[i], addr)); +} +if (hostFilter->multicast.nTable) { +char addr[VIR_MAC_STRING_BUFLEN]; +for (size_t i = 0; i < hostFilter->multicast.nTable; i++) { +VIR_DEBUG("RXFILTER: %s", virMacAddrFormat(&hostFilter->multicast.table[i], addr)); +} +} + syncNicRxFilterGuestMulticast(ifname, guestFilter, hostFilter); + syncNicRxFilterHostMulticast(ifname, guestFilter, hostFilter); +} + +static void processNicRxFilterChangedEvent(virQEMUDriverPtr driver, virDomainObjPtr vm, char *devAlias) @@ -4155,9 +4267,8 @@ processNicRxFilterChangedEvent(virQEMUDriverPtr driver, qemuDomainObjPrivatePtr priv = vm->privateData; virDomainDeviceDef dev; virDomainNetDefPtr def; - virNetDevRxFilterPtr filter = NULL; - virMacAddr oldMAC; - char newMacStr[VIR_MAC_STRING_BUFLEN]; + virNetDevRxFilterPtr guestFilter = NULL; + virNetDevRxFilterPtr hostFilter = NULL; int ret; VIR_DEBUG("Received NIC_RX_FILTER_CHANGED event for device %s " @@ -4202,37 +4313,27 @@ processNicRxFilterChangedEvent(virQEMUDriverPtr driver, "device %s in domain %s", def->info.alias, vm->def->name); qemuDomainObjEnterMonitor(driver, vm); - ret = qemuMonitorQueryRxFilter(priv->mon, devAlias, &filter); + ret = qemuMonitorQueryRxFilter(priv->mon, devAlias, &guestFilter); qemuDomainObjExitMonitor(driver, vm); if (ret < 0) goto endjob; - virMacAddrFormat(&filter->mac, newMacStr); - if (virDomainNetGetActualType(def) == VIR_DOMAIN_NET_TYPE_DIRECT) { - /* For macvtap connections, set the macvtap device's MAC - * address to match that of the guest device. - */ - - if (virNetDevGetMAC(def->ifname, &oldMAC) < 0) { - VIR_WARN("Couldn't get current MAC address of device %s " + if (virNetDevGetRxFilter(def->ifname, &hostFilter)) { + VIR_WARN("Couldn't get current RX filter for device %s " "while responding to NIC_RX_FILTER_CHANGED", def->ifname); goto endjob; } - if (virMacAddrCmp(&oldMAC, &filter->mac)) { - /* set new MAC address from guest to associated macvtap device */ - if (virNetDevSetMAC(def->ifname, &filter->mac) < 0) { - VIR_WARN("Couldn't set new MAC address %s to device %s " - "while responding to NIC_RX_FILTER_CHANGED", - newMacStr, def->ifname); - } else { - VIR_DEBUG("device %s MAC address set to %s", - def->ifname, newMacStr); - } - } + /* For macvtap connections, set the following macvtap network device + * attributes to match those of the guest network device: + * - MAC address + * - Multicast MAC address table + */ + syncNicRxFilterMacAddr(def->ifname, guestFilter, hostFilter); + syncNicRxFilterMulticast(def->ifname, guestFilter, hostFilter); } endjob: @@ -4242,7 +4343,8 @@ processNicRxFilterChangedEvent(virQEMUDriverPtr driver, ignore_value(qemuDomainObjEndJob(driver, vm)); cleanup: - virNetDevRxFilterFree(filter); + virNetDevRxFilterFree(hostFilter); + virNetDevRxFilterFree(guestFilter); VIR_FREE(devAlias); virObjectUnref(cfg); } diff --git a/src/util/virmacaddr.c b/src/util/virmacaddr.c index ae5e5d2..612a409 100644 --- a/src/util/virmacaddr.c +++ b/src/util/virmacaddr.c @@ -29,6 +29,7 @@ #include "c-ctype.h" #include "virmacaddr.h" #include "virrandom.h" +#include "virutil.h" static const unsigned char virMacAddrBroadcastAddrRaw[VIR_MAC_BUFLEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -208,31 +209,18 @@ virMacAddrFormat(const virMacAddr *addr, * Return 0 upon success, or -1 in case of error. */ int -virMacAddrParseHex(const char* str, virMacAddrPtr addr) +virMacAddrParseHex(const char *str, virMacAddrPtr addr) { - if (strlen(str) != VIR_MAC_HEXLEN) - return -1; - - size_t iaddr; - size_t istr; - - - for (istr = 0, iaddr = 0; iaddr < VIR_MAC_BUFLEN; istr += 2, iaddr++) { - unsigned int hex; - - if (sscanf(&str[istr], "%02x", &hex) != 1) - break; - - if (hex > UCHAR_MAX) - break; - - addr->addr[iaddr] = hex; - } + size_t i; - if (istr == VIR_MAC_HEXLEN) - return 0; + if (strspn(str, "0123456789abcdefABCDEF") != VIR_MAC_HEXLEN || + str[VIR_MAC_HEXLEN]) + return -1; - return -1; + for (i = 0; i < VIR_MAC_BUFLEN; i++) + addr->addr[i] = (virHexToBin(str[2 * i]) << 4 | + virHexToBin(str[2 * i + 1])); + return 0; } void virMacAddrGenerate(const unsigned char prefix[VIR_MAC_PREFIX_BUFLEN], diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 5e53f5f..296d94d 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -56,6 +56,8 @@ VIR_LOG_INIT("util.netdev"); +# define PROC_NET_DEV_MCAST "/proc/net/dev_mcast" +# define MAX_MCAST_SIZE 50*14336 # define VIR_MCAST_NAME_LEN (IFNAMSIZ + 1) # define VIR_MCAST_INDEX_TOKEN_IDX 0 # define VIR_MCAST_NAME_TOKEN_IDX 1 @@ -2004,9 +2006,9 @@ int virNetDevAddMulti(const char *ifname, virMacAddrPtr macaddr ATTRIBUTE_UNUSED) { char macstr[VIR_MAC_STRING_BUFLEN]; - virReportSystemError(errno, - _("Cannot add multicast MAC %s on '%s' interface"), - virMacAddrFormat(macaddr, macstr), ifname); + virReportError(ENOSYS, + _("Cannot add multicast MAC %s on '%s' interface"), + virMacAddrFormat(macaddr, macstr), ifname); return -1; } #endif @@ -2054,9 +2056,9 @@ int virNetDevDelMulti(const char *ifname, virMacAddrPtr macaddr ATTRIBUTE_UNUSED) { char macstr[VIR_MAC_STRING_BUFLEN]; - virReportSystemError(errno, - _("Cannot delete multicast MAC %s on '%s' interface"), - virMacAddrFormat(macaddr, macstr), ifname); + virReportError(ENOSYS, + _("Cannot delete multicast MAC %s on '%s' interface"), + virMacAddrFormat(macaddr, macstr), ifname); return -1; } #endif @@ -2085,7 +2087,7 @@ static int virNetDevParseMcast(char *buf, virNetDevMcastEntryPtr mcast) case VIR_MCAST_INDEX_TOKEN_IDX: if (virStrToLong_i(token, &endptr, 10, &num) < 0) { virReportSystemError(EINVAL, - _("Failed to parse index from '%s'"), + _("Failed to parse interface index from '%s'"), buf); return -1; @@ -2098,7 +2100,7 @@ static int virNetDevParseMcast(char *buf, virNetDevMcastEntryPtr mcast) if (virStrncpy(mcast->name, token, strlen(token), VIR_MCAST_NAME_LEN) == NULL) { virReportSystemError(EINVAL, - _("Failed to parse NIC name from '%s'"), + _("Failed to parse network device name from '%s'"), buf); return -1; } @@ -2146,75 +2148,90 @@ static int virNetDevParseMcast(char *buf, virNetDevMcastEntryPtr mcast) } +static void virNetDevMcastEntryListFree(size_t nentries, + virNetDevMcastEntryPtr *entries) +{ + size_t i; + + if (entries) { + for (i = 0; i < nentries; i++) + VIR_FREE(entries[i]); + + VIR_FREE(entries); + } +} + + static int virNetDevGetMcast(const char *ifname, virNetDevMcastPtr mcast) { - FILE *file; - const char *path = "/proc/net/dev_mcast"; - char buf[256]; - int ret = -1; - virNetDevMcastEntry entry; + char *cur = NULL; + char *buf = NULL; + char *next = NULL; + int ret = -1, len; + virNetDevMcastEntryPtr entry = NULL; virNetDevMcastEntryPtr *entries = NULL; size_t nentries = 0; - size_t entries_sz = 0; - size_t i; mcast->entries = NULL; mcast->nentries = 0; - file = fopen(path, "r"); + /* Read entire multicast table into memory */ + if ((len = virFileReadAll(PROC_NET_DEV_MCAST, MAX_MCAST_SIZE, &buf)) <= 0) + goto cleanup; - if (!file) { - virReportSystemError(errno, - _("cannot open multicast address file %s"), path); - return -1; - } + cur = buf; - while (fgets(buf, sizeof(buf), file)) { - if (virNetDevParseMcast(buf, &entry) < 0) { - goto error; + while (cur) { +VIR_DEBUG("RXFILTER: %s", cur); + if (!entry) { + if (VIR_ALLOC(entry)) + goto cleanup; } +VIR_DEBUG("RXFILTER: entry=%p", entry); + next = strchr(cur, '\n'); - if (entry.global && STREQ(ifname, entry.name)) { - if (VIR_RESIZE_N(entries, entries_sz, - nentries, 1) < 0) { - virReportSystemError(ENOMEM, - _("Failed to resize multicast MAC address array: " - "ptr=%p, alloc=%zu, count=%zu, add=1"), - entries, entries_sz, nentries); - goto error; - } + if (next) { + next++; + } - if (VIR_ALLOC(entries[nentries]) < 0) { - char addr[VIR_MAC_STRING_BUFLEN]; - virReportSystemError(ENOMEM, - _("Failed to allocate storage for MAC address %s"), - virMacAddrFormat(&mcast->entries[nentries]->macaddr, - addr)); - goto error; - } + if (virNetDevParseMcast(cur, entry)) { + goto cleanup; + } - memcpy(entries[nentries++], &entry, - sizeof(virNetDevMcastEntry)); + /* Only return global multicast MAC addresses for + * specified interface */ + if (entry->global && STREQ(ifname, entry->name)) { + if (VIR_APPEND_ELEMENT(entries, nentries, entry) < 0) + goto cleanup; + + entry = NULL; +VIR_DEBUG("RXFILTER: entries[%lu]=%p", nentries-1, entries[nentries-1]); + } else if (next) { + memset(entry, 0, sizeof(virNetDevMcastEntry)); + } else { + VIR_FREE(entry); } - memset(buf, 0, sizeof(buf)); - memset(&entry, 0, sizeof(virNetDevMcastEntry)); + cur = next; } - mcast->nentries = nentries; mcast->entries = entries; +if (nentries) { +VIR_DEBUG("RXFILTER: entries:"); +char addr[VIR_MAC_STRING_BUFLEN]; +for (size_t i = 0; i < nentries; i++) +VIR_DEBUG("RXFILTER: %d %s %d %d %s", +entries[i]->index, entries[i]->name, entries[i]->users, entries[i]->global, +virMacAddrFormat(&entries[i]->macaddr, addr)); +} ret = 0; + cleanup: + if (ret < 0) { + virNetDevMcastEntryListFree(nentries, entries); - error: - VIR_FORCE_FCLOSE(file); - - if ((ret < 0) && (nentries > 0)) { - for (i = 0; i < nentries; i++) { - VIR_FREE(entries[i]); - } - - VIR_FREE(entries); + if (entry) + VIR_FREE(entry); } return ret; @@ -2231,30 +2248,33 @@ VIR_ENUM_IMPL(virNetDevRxFilterMode, static int virNetDevGetMulticastTable(const char *ifname, virNetDevRxFilterPtr filter) { - int i; + size_t i; int ret = -1; virNetDevMcast mcast; filter->multicast.nTable = 0; filter->multicast.table = NULL; if (virNetDevGetMcast(ifname, &mcast) < 0) - goto error; + goto cleanup; if (mcast.nentries > 0) { if (VIR_ALLOC_N(filter->multicast.table, mcast.nentries)) - goto error; + goto cleanup; for (i = 0; i < mcast.nentries; i++) { virMacAddrSet(&filter->multicast.table[i], &mcast.entries[i]->macaddr); +char addr[VIR_MAC_STRING_BUFLEN]; +VIR_DEBUG("RXFILTER: filter->multicast.table[%lu]=%s", i, virMacAddrFormat(&filter->multicast.table[i], addr)); } filter->multicast.nTable = mcast.nentries; } ret = 0; + cleanup: + virNetDevMcastEntryListFree(mcast.nentries, mcast.entries); - error: return ret; } @@ -2298,21 +2318,16 @@ int virNetDevGetRxFilter(const char *ifname, int ret = -1; virNetDevRxFilterPtr fil = virNetDevRxFilterNew(); - if (!fil) { - virReportSystemError(ENOMEM, - _("Failed to allocate filter for %s interface"), - ifname); - - } + if (!fil) + goto cleanup; if (virNetDevGetMAC(ifname, &fil->mac)) - goto cleanup; + goto cleanup; if (virNetDevGetMulticastTable(ifname, fil)) goto cleanup; ret = 0; - cleanup: if (ret < 0) { virNetDevRxFilterFree(fil); -- 1.7.1

I think you forgot to merge in your modifications from V1 - although the commit log is changed, the code is still the V1 patch :-) On 10/13/2014 03:52 PM, akrowiak@linux.vnet.ibm.com wrote:
From: Tony Krowiak <akrowiak@linux.vnet.ibm.com>
This patch provides the utility functions to needed to synchronize the changes made to a guest domain network device's multicast filter with the corresponding macvtap device's filter on the host:
* Get/add/remove multicast MAC addresses * Get the macvtap device's RX filter list
Signed-off-by: Tony Krowiak <akrowiak@linux.vnet.ibm.com> ---
Changes from V1:
* Using virHexToBin function to parse HEX MAC address instead of sscanf in virMacAddrParseHex function * Using ENOSYS in error messages for empty functions * Reading entire file with virFileReadAll function when parsing /proc/net/dev_mcast file * Using VIR_APPEND_ELEMENT macro when appending array of /proc/net/dev_mcast file objects * Misc. formatting changes
src/libvirt_private.syms | 4 + src/util/virmacaddr.c | 37 +++++ src/util/virmacaddr.h | 4 + src/util/virnetdev.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virnetdev.h | 11 ++ 5 files changed, 416 insertions(+), 0 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d6265ac..6d06a2c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1590,13 +1590,16 @@ virMacAddrIsBroadcastRaw; virMacAddrIsMulticast; virMacAddrIsUnicast; virMacAddrParse; +virMacAddrParseHex; virMacAddrSet; virMacAddrSetRaw;
# util/virnetdev.h +virNetDevAddMulti; virNetDevAddRoute; virNetDevClearIPv4Address; +virNetDevDelMulti; virNetDevExists; virNetDevGetIndex; virNetDevGetIPv4Address; @@ -1604,6 +1607,7 @@ virNetDevGetLinkInfo; virNetDevGetMAC; virNetDevGetMTU; virNetDevGetPhysicalFunction; +virNetDevGetRxFilter; virNetDevGetVirtualFunctionIndex; virNetDevGetVirtualFunctionInfo; virNetDevGetVirtualFunctions; diff --git a/src/util/virmacaddr.c b/src/util/virmacaddr.c index ebd1182..ae5e5d2 100644 --- a/src/util/virmacaddr.c +++ b/src/util/virmacaddr.c @@ -198,6 +198,43 @@ virMacAddrFormat(const virMacAddr *addr, return str; }
+/** + * virMacAddrParseHex: + * @str: string hexadecimal representation of MAC address, e.g., "F801EFCE3aCB" + * @addr: 6-byte MAC address + * + * Parse the hexadecimal representation of a MAC address + * + * Return 0 upon success, or -1 in case of error. + */ +int +virMacAddrParseHex(const char* str, virMacAddrPtr addr) +{ + if (strlen(str) != VIR_MAC_HEXLEN) + return -1; + + size_t iaddr; + size_t istr; + + + for (istr = 0, iaddr = 0; iaddr < VIR_MAC_BUFLEN; istr += 2, iaddr++) { + unsigned int hex; + + if (sscanf(&str[istr], "%02x", &hex) != 1) + break; + + if (hex > UCHAR_MAX) + break; + + addr->addr[iaddr] = hex; + } + + if (istr == VIR_MAC_HEXLEN) + return 0; + + return -1; +} + void virMacAddrGenerate(const unsigned char prefix[VIR_MAC_PREFIX_BUFLEN], virMacAddrPtr addr) { diff --git a/src/util/virmacaddr.h b/src/util/virmacaddr.h index 49efc36..72a285a 100644 --- a/src/util/virmacaddr.h +++ b/src/util/virmacaddr.h @@ -27,6 +27,7 @@ # include "internal.h"
# define VIR_MAC_BUFLEN 6 +#define VIR_MAC_HEXLEN (VIR_MAC_BUFLEN * 2) # define VIR_MAC_PREFIX_BUFLEN 3 # define VIR_MAC_STRING_BUFLEN (VIR_MAC_BUFLEN * 3)
@@ -50,6 +51,9 @@ void virMacAddrGenerate(const unsigned char prefix[VIR_MAC_PREFIX_BUFLEN], virMacAddrPtr addr); int virMacAddrParse(const char* str, virMacAddrPtr addr) ATTRIBUTE_RETURN_CHECK; +int virMacAddrParseHex(const char* str, + virMacAddrPtr addr) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; bool virMacAddrIsUnicast(const virMacAddr *addr); bool virMacAddrIsMulticast(const virMacAddr *addr); bool virMacAddrIsBroadcastRaw(const unsigned char s[VIR_MAC_BUFLEN]); diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index db5623a..5e53f5f 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -56,6 +56,33 @@
VIR_LOG_INIT("util.netdev");
+# define VIR_MCAST_NAME_LEN (IFNAMSIZ + 1) +# define VIR_MCAST_INDEX_TOKEN_IDX 0 +# define VIR_MCAST_NAME_TOKEN_IDX 1 +# define VIR_MCAST_USERS_TOKEN_IDX 2 +# define VIR_MCAST_GLOBAL_TOKEN_IDX 3 +# define VIR_MCAST_ADDR_TOKEN_IDX 4 +# define VIR_MCAST_NUM_TOKENS 5 +# define VIR_MCAST_TOKEN_DELIMS " \n" +# define VIR_MCAST_ADDR_LEN (VIR_MAC_HEXLEN + 1) + +typedef struct _virNetDevMcastEntry virNetDevMcastEntry; +typedef virNetDevMcastEntry *virNetDevMcastEntryPtr; +struct _virNetDevMcastEntry { + int index; + char name[VIR_MCAST_NAME_LEN]; + int users; + bool global; + virMacAddr macaddr; +}; + +typedef struct _virNetDevMcast virNetDevMcast; +typedef virNetDevMcast *virNetDevMcastPtr; +struct _virNetDevMcast { + size_t nentries; + virNetDevMcastEntryPtr *entries; +}; + #if defined(HAVE_STRUCT_IFREQ) static int virNetDevSetupControlFull(const char *ifname, struct ifreq *ifr, @@ -1934,6 +1961,266 @@ virNetDevGetLinkInfo(const char *ifname, #endif /* defined(__linux__) */
+#if defined(SIOCADDMULTI) && defined(HAVE_STRUCT_IFREQ) +/** + * virNetDevAddMulti: + * @ifname: interface name to which to add multicast MAC address + * @macaddr: MAC address + * + * This function adds the @macaddr to the multicast list for a given interface + * @ifname. + * + * Returns 0 in case of success or -1 on failure + */ +int virNetDevAddMulti(const char *ifname, + virMacAddrPtr macaddr) +{ + int fd = -1; + int ret = -1; + struct ifreq ifr; + + if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0) + return -1; + + ifr.ifr_hwaddr.sa_family = AF_UNSPEC; + virMacAddrGetRaw(macaddr, (unsigned char *)ifr.ifr_hwaddr.sa_data); + + if (ioctl(fd, SIOCADDMULTI, &ifr) < 0) { + char macstr[VIR_MAC_STRING_BUFLEN]; + virReportSystemError(errno, + _("Cannot add multicast MAC %s on '%s' interface"), + virMacAddrFormat(macaddr, macstr), ifname); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FORCE_CLOSE(fd); + return ret; +} +#else +int virNetDevAddMulti(const char *ifname, + virMacAddrPtr macaddr ATTRIBUTE_UNUSED) +{ + char macstr[VIR_MAC_STRING_BUFLEN]; + virReportSystemError(errno, + _("Cannot add multicast MAC %s on '%s' interface"), + virMacAddrFormat(macaddr, macstr), ifname); + return -1; +} +#endif + +#if defined(SIOCDELMULTI) && defined(HAVE_STRUCT_IFREQ) +/** + * virNetDevDelMulti: + * @ifname: interface name from which to delete the multicast MAC address + * @macaddr: MAC address + * + * This function deletes the @macaddr from the multicast list for a given + * interface @ifname. + * + * Returns 0 in case of success or -1 on failure + */ +int virNetDevDelMulti(const char *ifname, + virMacAddrPtr macaddr) +{ + int fd = -1; + int ret = -1; + struct ifreq ifr; + + if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0) + return -1; + + ifr.ifr_hwaddr.sa_family = AF_UNSPEC; + virMacAddrGetRaw(macaddr, (unsigned char *)ifr.ifr_hwaddr.sa_data); + + if (ioctl(fd, SIOCDELMULTI, &ifr) < 0) { + char macstr[VIR_MAC_STRING_BUFLEN]; + virReportSystemError(errno, + _("Cannot add multicast MAC %s on '%s' interface"), + virMacAddrFormat(macaddr, macstr), ifname); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FORCE_CLOSE(fd); + return ret; +} +#else +int virNetDevDelMulti(const char *ifname, + virMacAddrPtr macaddr ATTRIBUTE_UNUSED) +{ + char macstr[VIR_MAC_STRING_BUFLEN]; + virReportSystemError(errno, + _("Cannot delete multicast MAC %s on '%s' interface"), + virMacAddrFormat(macaddr, macstr), ifname); + return -1; +} +#endif + +static int virNetDevParseMcast(char *buf, virNetDevMcastEntryPtr mcast) +{ + int ifindex; + int num; + char *next; + char *token; + char *saveptr; + char *endptr; + + for (ifindex = 0, next = buf; ifindex < VIR_MCAST_NUM_TOKENS; ifindex++, + next = NULL) { + token = strtok_r(next, VIR_MCAST_TOKEN_DELIMS, &saveptr); + + if (token == NULL) { + virReportSystemError(EINVAL, + _("failed to parse multicast address from '%s'"), + buf); + return -1; + } + + switch (ifindex) { + case VIR_MCAST_INDEX_TOKEN_IDX: + if (virStrToLong_i(token, &endptr, 10, &num) < 0) { + virReportSystemError(EINVAL, + _("Failed to parse index from '%s'"), + buf); + return -1; + + } + + mcast->index = num; + + break; + case VIR_MCAST_NAME_TOKEN_IDX: + if (virStrncpy(mcast->name, token, strlen(token), + VIR_MCAST_NAME_LEN) == NULL) { + virReportSystemError(EINVAL, + _("Failed to parse NIC name from '%s'"), + buf); + return -1; + } + + break; + case VIR_MCAST_USERS_TOKEN_IDX: + if (virStrToLong_i(token, &endptr, 10, &num) < 0) { + virReportSystemError(EINVAL, + _("Failed to parse users from '%s'"), + buf); + return -1; + + } + + mcast->users = num; + + break; + case VIR_MCAST_GLOBAL_TOKEN_IDX: + if (virStrToLong_i(token, &endptr, 10, &num) < 0) { + virReportSystemError(EINVAL, + _("Failed to parse users from '%s'"), + buf); + return -1; + + } + + mcast->global = num; + + break; + case VIR_MCAST_ADDR_TOKEN_IDX: + if (virMacAddrParseHex((const char*)token, + &mcast->macaddr) < 0) { + virReportSystemError(EINVAL, + _("Failed to parse MAC address from '%s'"), + buf); + } + + break; + default: + break; + } + } + + return 0; +} + + +static int virNetDevGetMcast(const char *ifname, + virNetDevMcastPtr mcast) +{ + FILE *file; + const char *path = "/proc/net/dev_mcast"; + char buf[256]; + int ret = -1; + virNetDevMcastEntry entry; + virNetDevMcastEntryPtr *entries = NULL; + size_t nentries = 0; + size_t entries_sz = 0; + size_t i; + mcast->entries = NULL; + mcast->nentries = 0; + + file = fopen(path, "r"); + + if (!file) { + virReportSystemError(errno, + _("cannot open multicast address file %s"), path); + return -1; + } + + while (fgets(buf, sizeof(buf), file)) { + if (virNetDevParseMcast(buf, &entry) < 0) { + goto error; + } + + if (entry.global && STREQ(ifname, entry.name)) { + if (VIR_RESIZE_N(entries, entries_sz, + nentries, 1) < 0) { + virReportSystemError(ENOMEM, + _("Failed to resize multicast MAC address array: " + "ptr=%p, alloc=%zu, count=%zu, add=1"), + entries, entries_sz, nentries); + goto error; + } + + if (VIR_ALLOC(entries[nentries]) < 0) { + char addr[VIR_MAC_STRING_BUFLEN]; + virReportSystemError(ENOMEM, + _("Failed to allocate storage for MAC address %s"), + virMacAddrFormat(&mcast->entries[nentries]->macaddr, + addr)); + goto error; + } + + memcpy(entries[nentries++], &entry, + sizeof(virNetDevMcastEntry)); + } + + memset(buf, 0, sizeof(buf)); + memset(&entry, 0, sizeof(virNetDevMcastEntry)); + } + + + mcast->nentries = nentries; + mcast->entries = entries; + ret = 0; + + error: + VIR_FORCE_FCLOSE(file); + + if ((ret < 0) && (nentries > 0)) { + for (i = 0; i < nentries; i++) { + VIR_FREE(entries[i]); + } + + VIR_FREE(entries); + } + + return ret; +} + + VIR_ENUM_IMPL(virNetDevRxFilterMode, VIR_NETDEV_RX_FILTER_MODE_LAST, "none", @@ -1941,6 +2228,37 @@ VIR_ENUM_IMPL(virNetDevRxFilterMode, "all");
+static int virNetDevGetMulticastTable(const char *ifname, + virNetDevRxFilterPtr filter) +{ + int i; + int ret = -1; + virNetDevMcast mcast; + filter->multicast.nTable = 0; + filter->multicast.table = NULL; + + if (virNetDevGetMcast(ifname, &mcast) < 0) + goto error; + + if (mcast.nentries > 0) { + if (VIR_ALLOC_N(filter->multicast.table, mcast.nentries)) + goto error; + + for (i = 0; i < mcast.nentries; i++) { + virMacAddrSet(&filter->multicast.table[i], + &mcast.entries[i]->macaddr); + } + + filter->multicast.nTable = mcast.nentries; + } + + ret = 0; + + error: + return ret; +} + + virNetDevRxFilterPtr virNetDevRxFilterNew(void) { @@ -1963,3 +2281,45 @@ virNetDevRxFilterFree(virNetDevRxFilterPtr filter) VIR_FREE(filter); } } + + +/** + * virNetDevGetRxFilter: + * This function supplies the RX filter list for a given device interface + * + * @ifname: Name of the interface + * @filter: The RX filter list + * + * Returns 0 or -1 on failure. + */ +int virNetDevGetRxFilter(const char *ifname, + virNetDevRxFilterPtr *filter) +{ + int ret = -1; + virNetDevRxFilterPtr fil = virNetDevRxFilterNew(); + + if (!fil) { + virReportSystemError(ENOMEM, + _("Failed to allocate filter for %s interface"), + ifname); + + } + + if (virNetDevGetMAC(ifname, &fil->mac)) + goto cleanup; + + if (virNetDevGetMulticastTable(ifname, fil)) + goto cleanup; + + ret = 0; + + cleanup: + if (ret < 0) { + virNetDevRxFilterFree(fil); + fil = NULL; + } + + *filter = fil; + + return ret; +} diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index 2a6e67d..1d274b3 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -30,6 +30,7 @@ # include "virmacaddr.h" # include "virpci.h" # include "device_conf.h" +# include "virutil.h"
# ifdef HAVE_STRUCT_IFREQ typedef struct ifreq virIfreq; @@ -189,5 +190,15 @@ int virNetDevGetLinkInfo(const char *ifname, virNetDevRxFilterPtr virNetDevRxFilterNew(void) ATTRIBUTE_RETURN_CHECK; void virNetDevRxFilterFree(virNetDevRxFilterPtr filter); +int virNetDevGetRxFilter(const char *ifname, + virNetDevRxFilterPtr *filter) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + +int virNetDevAddMulti(const char *ifname, + virMacAddrPtr macaddr) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; +int virNetDevDelMulti(const char *ifname, + virMacAddrPtr macaddr) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
#endif /* __VIR_NETDEV_H__ */

On 10/14/2014 02:41 PM, Laine Stump wrote:
I think you forgot to merge in your modifications from V1 - although the commit log is changed, the code is still the V1 patch :-)
Ah, I see that you sent the actual V2 patch last weekend, and only sent this update to move the "changes from V1" message out of the commit log message - I'll just review what you sent on Oct 10 - no need to resend yet again. (Sorry I haven't already reviewed - I've been travelling since last Thursday, and am currently in a conference room at KVM Forum).
On 10/13/2014 03:52 PM, akrowiak@linux.vnet.ibm.com wrote:
From: Tony Krowiak <akrowiak@linux.vnet.ibm.com>
This patch provides the utility functions to needed to synchronize the changes made to a guest domain network device's multicast filter with the corresponding macvtap device's filter on the host:
* Get/add/remove multicast MAC addresses * Get the macvtap device's RX filter list
Signed-off-by: Tony Krowiak <akrowiak@linux.vnet.ibm.com> ---
Changes from V1:
* Using virHexToBin function to parse HEX MAC address instead of sscanf in virMacAddrParseHex function * Using ENOSYS in error messages for empty functions * Reading entire file with virFileReadAll function when parsing /proc/net/dev_mcast file * Using VIR_APPEND_ELEMENT macro when appending array of /proc/net/dev_mcast file objects * Misc. formatting changes
src/libvirt_private.syms | 4 + src/util/virmacaddr.c | 37 +++++ src/util/virmacaddr.h | 4 + src/util/virnetdev.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virnetdev.h | 11 ++ 5 files changed, 416 insertions(+), 0 deletions(-)
participants (2)
-
akrowiak@linux.vnet.ibm.com
-
Laine Stump