From: Tony Krowiak <akrowiak@xxxxxxxxxxxxxxxxxx> 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@xxxxxxxxxxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list