[libvirt] [PATCH 0/4] Support macvlan devices for LXC containers

This series does the bare minimum required to support the network inteface type=direct for LXC containers, using macvlan devices as the implementation. There is a slight complication though... For bridged container NICs we create a veth pair of devices. One of the devices lives host side, and is enslaved in a bridge. The other veth device gets moved to the container namespace to form the eth0. So we both both a host & container side device visible. For direct container NICS we create a macvlan device, which is moved to the container namespace. There is no host side interface that is dedicated for the container - only the general ethernet device the macvlan is bound to. Since there is no host side interface for the container we are unable to create network filter rules, or network bandwidth controls. In addition while we could perform the 8021.Qb{gh} association during container startup, before moving the macvlan device to the container namespace, we can't perform any disassociation on container shutdown. By the time we see the container has shutdown, the macvlan device has already been killed off. The inability to setup iptables/tc rules against devices that are only visible in the container namespace is arguably a flaw in the Linux kernel's namespace code support for iptables/tc. There ought to be a syntax for iptables/tc to write rules which affect NICs in other namespaces

From: "Daniel P. Berrange" <berrange@redhat.com> The virDomainNetGetActualBridgeName and virDomainNetGetActualDirectDev methods both return strings that point to data in the virDomainDefPtr struct, and should therefore not be freed. The return values should thus be 'const char *' not 'char *'. * src/conf/domain_conf.c, src/conf/domain_conf.h: Mark const * src/network/bridge_driver.c: Update to use a const char * --- src/conf/domain_conf.c | 4 ++-- src/conf/domain_conf.h | 4 ++-- src/network/bridge_driver.c | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 9528697..5a83dec 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -13046,7 +13046,7 @@ virDomainNetGetActualType(virDomainNetDefPtr iface) return iface->data.network.actual->type; } -char * +const char * virDomainNetGetActualBridgeName(virDomainNetDefPtr iface) { if (iface->type == VIR_DOMAIN_NET_TYPE_BRIDGE) @@ -13058,7 +13058,7 @@ virDomainNetGetActualBridgeName(virDomainNetDefPtr iface) return iface->data.network.actual->data.bridge.brname; } -char * +const char * virDomainNetGetActualDirectDev(virDomainNetDefPtr iface) { if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 9528199..4e86d30 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1794,8 +1794,8 @@ int virDomainGraphicsListenSetNetwork(virDomainGraphicsDefPtr def, ATTRIBUTE_NONNULL(1); int virDomainNetGetActualType(virDomainNetDefPtr iface); -char *virDomainNetGetActualBridgeName(virDomainNetDefPtr iface); -char *virDomainNetGetActualDirectDev(virDomainNetDefPtr iface); +const char *virDomainNetGetActualBridgeName(virDomainNetDefPtr iface); +const char *virDomainNetGetActualDirectDev(virDomainNetDefPtr iface); int virDomainNetGetActualDirectMode(virDomainNetDefPtr iface); virNetDevVPortProfilePtr virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface); diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 5dfc294..623e4b3 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2898,7 +2898,7 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) struct network_driver *driver = driverState; virNetworkObjPtr network; virNetworkDefPtr netdef; - char *actualDev; + const char *actualDev; int ret = -1; if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) @@ -2924,8 +2924,8 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) if (!actualDev) { networkReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("the interface uses a direct mode, but has no source dev")); - goto cleanup; - } + goto cleanup; + } netdef = network->def; if (netdef->nForwardIfs == 0) { @@ -2998,7 +2998,7 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) struct network_driver *driver = driverState; virNetworkObjPtr network = NULL; virNetworkDefPtr netdef; - char *actualDev; + const char *actualDev; int ret = -1; if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) @@ -3025,8 +3025,8 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) if (!actualDev) { networkReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("the interface uses a direct mode, but has no source dev")); - goto cleanup; - } + goto cleanup; + } netdef = network->def; if (netdef->nForwardIfs == 0) { -- 1.7.6.4

On 11/10/2011 06:28 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange"<berrange@redhat.com>
The virDomainNetGetActualBridgeName and virDomainNetGetActualDirectDev methods both return strings that point to data in the virDomainDefPtr struct, and should therefore not be freed. The return values should thus be 'const char *' not 'char *'.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Mark const * src/network/bridge_driver.c: Update to use a const char * --- src/conf/domain_conf.c | 4 ++-- src/conf/domain_conf.h | 4 ++-- src/network/bridge_driver.c | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 9528697..5a83dec 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -13046,7 +13046,7 @@ virDomainNetGetActualType(virDomainNetDefPtr iface) return iface->data.network.actual->type; }
-char * +const char * virDomainNetGetActualBridgeName(virDomainNetDefPtr iface) { if (iface->type == VIR_DOMAIN_NET_TYPE_BRIDGE) @@ -13058,7 +13058,7 @@ virDomainNetGetActualBridgeName(virDomainNetDefPtr iface) return iface->data.network.actual->data.bridge.brname; }
-char * +const char * virDomainNetGetActualDirectDev(virDomainNetDefPtr iface) { if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 9528199..4e86d30 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1794,8 +1794,8 @@ int virDomainGraphicsListenSetNetwork(virDomainGraphicsDefPtr def, ATTRIBUTE_NONNULL(1);
int virDomainNetGetActualType(virDomainNetDefPtr iface); -char *virDomainNetGetActualBridgeName(virDomainNetDefPtr iface); -char *virDomainNetGetActualDirectDev(virDomainNetDefPtr iface); +const char *virDomainNetGetActualBridgeName(virDomainNetDefPtr iface); +const char *virDomainNetGetActualDirectDev(virDomainNetDefPtr iface); int virDomainNetGetActualDirectMode(virDomainNetDefPtr iface); virNetDevVPortProfilePtr virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface); diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 5dfc294..623e4b3 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2898,7 +2898,7 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) struct network_driver *driver = driverState; virNetworkObjPtr network; virNetworkDefPtr netdef; - char *actualDev; + const char *actualDev; int ret = -1;
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) @@ -2924,8 +2924,8 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) if (!actualDev) { networkReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("the interface uses a direct mode, but has no source dev")); - goto cleanup; - } + goto cleanup; + }
netdef = network->def; if (netdef->nForwardIfs == 0) { @@ -2998,7 +2998,7 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) struct network_driver *driver = driverState; virNetworkObjPtr network = NULL; virNetworkDefPtr netdef; - char *actualDev; + const char *actualDev; int ret = -1;
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) @@ -3025,8 +3025,8 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) if (!actualDev) { networkReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("the interface uses a direct mode, but has no source dev")); - goto cleanup; - } + goto cleanup; + }
netdef = network->def; if (netdef->nForwardIfs == 0) {
ACK

From: "Daniel P. Berrange" <berrange@redhat.com> The current lxcSetupInterfaces() method directly performs setup of the bridge devices. Since it will shortly need to also create macvlan devices, move the bridge related code into a separate method * src/lxc/lxc_driver.c: Split lxcSetupInterfaces() to create a new lxcSetupInterfaceBridge() --- src/lxc/lxc_driver.c | 167 +++++++++++++++++++++++++++++-------------------- 1 files changed, 99 insertions(+), 68 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index ccd8bad..4f6807b 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1175,6 +1175,61 @@ static void lxcVmCleanup(lxc_driver_t *driver, } } + +static int lxcSetupInterfaceBridged(virConnectPtr conn, + virDomainNetDefPtr net, + const char *brname, + unsigned int *nveths, + char ***veths) +{ + int ret = -1; + char *parentVeth; + char *containerVeth = NULL; + + VIR_DEBUG("calling vethCreate()"); + parentVeth = net->ifname; + if (virNetDevVethCreate(&parentVeth, &containerVeth) < 0) + goto cleanup; + VIR_DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth); + + if (net->ifname == NULL) + net->ifname = parentVeth; + + if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) { + virReportOOMError(); + VIR_FREE(containerVeth); + goto cleanup; + } + (*veths)[(*nveths)] = containerVeth; + (*nveths)++; + + if (virNetDevSetMAC(containerVeth, net->mac) < 0) + goto cleanup; + + if (virNetDevBridgeAddPort(brname, parentVeth) < 0) + goto cleanup; + + if (virNetDevSetOnline(parentVeth, true) < 0) + goto cleanup; + + if (virNetDevBandwidthSet(net->ifname, + virDomainNetGetActualBandwidth(net)) < 0) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("cannot set bandwidth limits on %s"), + net->ifname); + goto cleanup; + } + + if (net->filter && + virDomainConfNWFilterInstantiate(conn, net) < 0) + goto cleanup; + + ret = 0; + +cleanup: + return ret; +} + /** * lxcSetupInterfaces: * @conn: pointer to connection @@ -1193,39 +1248,56 @@ static int lxcSetupInterfaces(virConnectPtr conn, unsigned int *nveths, char ***veths) { - int rc = -1, i; - char *bridge = NULL; + int ret = -1; + size_t i; for (i = 0 ; i < def->nnets ; i++) { - char *parentVeth; - char *containerVeth = NULL; - /* If appropriate, grab a physical device from the configured * network's pool of devices, or resolve bridge device name * to the one defined in the network definition. */ if (networkAllocateActualDevice(def->nets[i]) < 0) - goto error_exit; + goto cleanup; switch (virDomainNetGetActualType(def->nets[i])) { - case VIR_DOMAIN_NET_TYPE_NETWORK: - { + case VIR_DOMAIN_NET_TYPE_NETWORK: { virNetworkPtr network; + char *brname = NULL; - network = virNetworkLookupByName(conn, - def->nets[i]->data.network.name); - if (!network) { - goto error_exit; - } - - bridge = virNetworkGetBridgeName(network); + if (!(network = virNetworkLookupByName(conn, + def->nets[i]->data.network.name))) + goto cleanup; + brname = virNetworkGetBridgeName(network); virNetworkFree(network); + if (!brname) + goto cleanup; + + if (lxcSetupInterfaceBridged(conn, + def->nets[i], + brname, + nveths, + veths) < 0) { + VIR_FREE(brname); + goto cleanup; + } + VIR_FREE(brname); break; } - case VIR_DOMAIN_NET_TYPE_BRIDGE: - bridge = virDomainNetGetActualBridgeName(def->nets[i]); - break; + case VIR_DOMAIN_NET_TYPE_BRIDGE: { + const char *brname = virDomainNetGetActualBridgeName(def->nets[i]); + if (!brname) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No bridge name specified")); + goto cleanup; + } + if (lxcSetupInterfaceBridged(conn, + def->nets[i], + brname, + nveths, + veths) < 0) + goto cleanup; + } break; case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_ETHERNET: @@ -1235,64 +1307,23 @@ static int lxcSetupInterfaces(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_LAST: - break; - } - - VIR_DEBUG("bridge: %s", bridge); - if (NULL == bridge) { lxcError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Failed to get bridge for interface")); - goto error_exit; - } - - VIR_DEBUG("calling vethCreate()"); - parentVeth = def->nets[i]->ifname; - if (virNetDevVethCreate(&parentVeth, &containerVeth) < 0) - goto error_exit; - VIR_DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth); - - if (NULL == def->nets[i]->ifname) { - def->nets[i]->ifname = parentVeth; - } - - if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) { - virReportOOMError(); - VIR_FREE(containerVeth); - goto error_exit; - } - (*veths)[(*nveths)] = containerVeth; - (*nveths)++; - - if (virNetDevSetMAC(containerVeth, def->nets[i]->mac) < 0) - goto error_exit; - - if (virNetDevBridgeAddPort(bridge, parentVeth) < 0) - goto error_exit; - - if (virNetDevSetOnline(parentVeth, true) < 0) - goto error_exit; - - if (virNetDevBandwidthSet(def->nets[i]->ifname, - virDomainNetGetActualBandwidth(def->nets[i])) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("cannot set bandwidth limits on %s"), - def->nets[i]->ifname); - goto error_exit; + _("Unsupported network type %s"), + virDomainNetTypeToString( + virDomainNetGetActualType(def->nets[i]) + )); + goto cleanup; } - - if (def->nets[i]->filter && - virDomainConfNWFilterInstantiate(conn, def->nets[i]) < 0) - goto error_exit; } - rc = 0; + ret= 0; -error_exit: - if (rc != 0) { +cleanup: + if (ret != 0) { for (i = 0 ; i < def->nnets ; i++) networkReleaseActualDevice(def->nets[i]); } - return rc; + return ret; } -- 1.7.6.4

On 11/10/2011 06:28 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange"<berrange@redhat.com>
The current lxcSetupInterfaces() method directly performs setup of the bridge devices. Since it will shortly need to also create macvlan devices, move the bridge related code into a separate method
* src/lxc/lxc_driver.c: Split lxcSetupInterfaces() to create a new lxcSetupInterfaceBridge() --- src/lxc/lxc_driver.c | 167 +++++++++++++++++++++++++++++-------------------- 1 files changed, 99 insertions(+), 68 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index ccd8bad..4f6807b 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1175,6 +1175,61 @@ static void lxcVmCleanup(lxc_driver_t *driver, } }
+ +static int lxcSetupInterfaceBridged(virConnectPtr conn, + virDomainNetDefPtr net, + const char *brname, + unsigned int *nveths, + char ***veths) +{ + int ret = -1; + char *parentVeth; + char *containerVeth = NULL; + + VIR_DEBUG("calling vethCreate()"); + parentVeth = net->ifname; + if (virNetDevVethCreate(&parentVeth,&containerVeth)< 0) + goto cleanup; + VIR_DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth); + + if (net->ifname == NULL) + net->ifname = parentVeth; + + if (VIR_REALLOC_N(*veths, (*nveths)+1)< 0) { + virReportOOMError(); + VIR_FREE(containerVeth); + goto cleanup; + } + (*veths)[(*nveths)] = containerVeth; + (*nveths)++; + + if (virNetDevSetMAC(containerVeth, net->mac)< 0) + goto cleanup; + + if (virNetDevBridgeAddPort(brname, parentVeth)< 0) + goto cleanup; + + if (virNetDevSetOnline(parentVeth, true)< 0) + goto cleanup; + + if (virNetDevBandwidthSet(net->ifname, + virDomainNetGetActualBandwidth(net))< 0) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("cannot set bandwidth limits on %s"), + net->ifname); + goto cleanup; + } + + if (net->filter&& + virDomainConfNWFilterInstantiate(conn, net)< 0) + goto cleanup; + + ret = 0; + +cleanup: + return ret; +} + /** * lxcSetupInterfaces: * @conn: pointer to connection @@ -1193,39 +1248,56 @@ static int lxcSetupInterfaces(virConnectPtr conn, unsigned int *nveths, char ***veths) { - int rc = -1, i; - char *bridge = NULL; + int ret = -1; + size_t i;
for (i = 0 ; i< def->nnets ; i++) { - char *parentVeth; - char *containerVeth = NULL; - /* If appropriate, grab a physical device from the configured * network's pool of devices, or resolve bridge device name * to the one defined in the network definition. */ if (networkAllocateActualDevice(def->nets[i])< 0) - goto error_exit; + goto cleanup;
switch (virDomainNetGetActualType(def->nets[i])) { - case VIR_DOMAIN_NET_TYPE_NETWORK: - { + case VIR_DOMAIN_NET_TYPE_NETWORK: { virNetworkPtr network; + char *brname = NULL;
- network = virNetworkLookupByName(conn, - def->nets[i]->data.network.name); - if (!network) { - goto error_exit; - } - - bridge = virNetworkGetBridgeName(network); + if (!(network = virNetworkLookupByName(conn, + def->nets[i]->data.network.name))) + goto cleanup;
+ brname = virNetworkGetBridgeName(network); virNetworkFree(network); + if (!brname) + goto cleanup; + + if (lxcSetupInterfaceBridged(conn, + def->nets[i], + brname, + nveths, + veths)< 0) { + VIR_FREE(brname); + goto cleanup; + } + VIR_FREE(brname); break; } - case VIR_DOMAIN_NET_TYPE_BRIDGE: - bridge = virDomainNetGetActualBridgeName(def->nets[i]); - break; + case VIR_DOMAIN_NET_TYPE_BRIDGE: { + const char *brname = virDomainNetGetActualBridgeName(def->nets[i]); + if (!brname) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No bridge name specified")); + goto cleanup; + } + if (lxcSetupInterfaceBridged(conn, + def->nets[i], + brname, + nveths, + veths)< 0) + goto cleanup; + } break;
case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_ETHERNET: @@ -1235,64 +1307,23 @@ static int lxcSetupInterfaces(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_LAST: - break; - } - - VIR_DEBUG("bridge: %s", bridge); - if (NULL == bridge) { lxcError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Failed to get bridge for interface")); - goto error_exit; - } - - VIR_DEBUG("calling vethCreate()"); - parentVeth = def->nets[i]->ifname; - if (virNetDevVethCreate(&parentVeth,&containerVeth)< 0) - goto error_exit; - VIR_DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth); - - if (NULL == def->nets[i]->ifname) { - def->nets[i]->ifname = parentVeth; - } - - if (VIR_REALLOC_N(*veths, (*nveths)+1)< 0) { - virReportOOMError(); - VIR_FREE(containerVeth); - goto error_exit; - } - (*veths)[(*nveths)] = containerVeth; - (*nveths)++; - - if (virNetDevSetMAC(containerVeth, def->nets[i]->mac)< 0) - goto error_exit; - - if (virNetDevBridgeAddPort(bridge, parentVeth)< 0) - goto error_exit; - - if (virNetDevSetOnline(parentVeth, true)< 0) - goto error_exit; - - if (virNetDevBandwidthSet(def->nets[i]->ifname, - virDomainNetGetActualBandwidth(def->nets[i]))< 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("cannot set bandwidth limits on %s"), - def->nets[i]->ifname); - goto error_exit; + _("Unsupported network type %s"), + virDomainNetTypeToString( + virDomainNetGetActualType(def->nets[i]) + )); + goto cleanup; } - - if (def->nets[i]->filter&& - virDomainConfNWFilterInstantiate(conn, def->nets[i])< 0) - goto error_exit; }
- rc = 0; + ret= 0;
-error_exit: - if (rc != 0) { +cleanup: + if (ret != 0) { for (i = 0 ; i< def->nnets ; i++) networkReleaseActualDevice(def->nets[i]); } - return rc; + return ret; }
ACK

From: "Daniel P. Berrange" <berrange@redhat.com> Update virNetDevMacVLanCreateWithVPortProfile to allow creation of plain macvlan devices, as well as macvtap devices. The former is useful for LXC containers * src/qemu/qemu_command.c: Explicitly request a macvtap device * src/util/virnetdevmacvlan.c, src/util/virnetdevmacvlan.h: Add new flag to allow switching between macvlan and macvtap creation --- src/qemu/qemu_command.c | 2 +- src/util/virnetdevmacvlan.c | 41 ++++++++++++++++++++++++++++------------- src/util/virnetdevmacvlan.h | 5 +++-- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 6df1f83..2f01436 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -154,7 +154,7 @@ qemuPhysIfaceConnect(virDomainDefPtr def, net->ifname, net->mac, virDomainNetGetActualDirectDev(net), virDomainNetGetActualDirectMode(net), - vnet_hdr, def->uuid, + true, vnet_hdr, def->uuid, virDomainNetGetActualDirectVirtPortProfile(net), &res_ifname, vmop, driver->stateDir, diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index fe2f383..98b0f9a 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -72,11 +72,14 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST, # define MACVTAP_NAME_PREFIX "macvtap" # define MACVTAP_NAME_PATTERN "macvtap%d" +# define MACVLAN_NAME_PREFIX "macvlan" +# define MACVLAN_NAME_PATTERN "macvlan%d" + /** * virNetDevMacVLanCreate: * * @ifname: The name the interface is supposed to have; optional parameter - * @type: The type of device, i.e., "macvtap" + * @type: The type of device, i.e., "macvtap", "macvlan" * @macaddress: The MAC address of the device * @srcdev: The name of the 'link' device * @macvlan_mode: The macvlan mode to use @@ -458,14 +461,14 @@ static const uint32_t modeMap[VIR_NETDEV_MACVLAN_MODE_LAST] = { * interface will be stored into if everything succeeded. It is up * to the caller to free the string. * - * Returns file descriptor of the tap device in case of success, - * negative value otherwise with error reported. - * + * Returns file descriptor of the tap device in case of success with @withTap, + * otherwise returns 0; returns -1 on error. */ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname, const unsigned char *macaddress, const char *linkdev, enum virNetDevMacVLanMode mode, + bool withTap, int vnet_hdr, const unsigned char *vmuuid, virNetDevVPortProfilePtr virtPortProfile, @@ -474,7 +477,9 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname, char *stateDir, virNetDevBandwidthPtr bandwidth) { - const char *type = "macvtap"; + const char *type = withTap ? "macvtap" : "macvlan"; + const char *prefix = withTap ? MACVTAP_NAME_PREFIX : MACVLAN_NAME_PREFIX; + const char *pattern = withTap ? MACVTAP_NAME_PATTERN : MACVLAN_NAME_PATTERN; int c, rc; char ifname[IFNAMSIZ]; int retries, do_retry = 0; @@ -505,8 +510,7 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname, return -1; if (ret) { - if (STRPREFIX(tgifname, - MACVTAP_NAME_PREFIX)) { + if (STRPREFIX(tgifname, prefix)) { goto create_name; } virReportSystemError(EEXIST, @@ -522,7 +526,7 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname, create_name: retries = 5; for (c = 0; c < 8192; c++) { - snprintf(ifname, sizeof(ifname), MACVTAP_NAME_PATTERN, c); + snprintf(ifname, sizeof(ifname), pattern, c); if ((ret = virNetDevExists(ifname)) < 0) return -1; if (!ret) { @@ -553,15 +557,26 @@ create_name: goto disassociate_exit; } - rc = virNetDevMacVLanTapOpen(cr_ifname, 10); - if (rc >= 0) { + if (withTap) { + if ((rc = virNetDevMacVLanTapOpen(cr_ifname, 10)) < 0) + goto disassociate_exit; + if (virNetDevMacVLanTapSetup(rc, vnet_hdr) < 0) { VIR_FORCE_CLOSE(rc); /* sets rc to -1 */ goto disassociate_exit; } - *res_ifname = strdup(cr_ifname); - } else - goto disassociate_exit; + if (!(*res_ifname = strdup(cr_ifname))) { + VIR_FORCE_CLOSE(rc); /* sets rc to -1 */ + virReportOOMError(); + goto disassociate_exit; + } + } else { + if (!(*res_ifname = strdup(cr_ifname))) { + virReportOOMError(); + goto disassociate_exit; + } + rc = 0; + } if (virNetDevBandwidthSet(cr_ifname, bandwidth) < 0) { virNetDevError(VIR_ERR_INTERNAL_ERROR, diff --git a/src/util/virnetdevmacvlan.h b/src/util/virnetdevmacvlan.h index 73918b8..130ecea 100644 --- a/src/util/virnetdevmacvlan.h +++ b/src/util/virnetdevmacvlan.h @@ -55,6 +55,7 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *ifname, const unsigned char *macaddress, const char *linkdev, enum virNetDevMacVLanMode mode, + bool withTap, int vnet_hdr, const unsigned char *vmuuid, virNetDevVPortProfilePtr virtPortProfile, @@ -62,8 +63,8 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *ifname, enum virNetDevVPortProfileOp vmop, char *stateDir, virNetDevBandwidthPtr bandwidth) - ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(6) - ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(10) ATTRIBUTE_RETURN_CHECK; + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(7) + ATTRIBUTE_NONNULL(9) ATTRIBUTE_NONNULL(11) ATTRIBUTE_RETURN_CHECK; int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname, const unsigned char *macaddress, -- 1.7.6.4

On 11/10/2011 06:28 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange"<berrange@redhat.com>
Update virNetDevMacVLanCreateWithVPortProfile to allow creation of plain macvlan devices, as well as macvtap devices. The former is useful for LXC containers
* src/qemu/qemu_command.c: Explicitly request a macvtap device * src/util/virnetdevmacvlan.c, src/util/virnetdevmacvlan.h: Add new flag to allow switching between macvlan and macvtap creation --- src/qemu/qemu_command.c | 2 +- src/util/virnetdevmacvlan.c | 41 ++++++++++++++++++++++++++++------------- src/util/virnetdevmacvlan.h | 5 +++-- 3 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 6df1f83..2f01436 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -154,7 +154,7 @@ qemuPhysIfaceConnect(virDomainDefPtr def, net->ifname, net->mac, virDomainNetGetActualDirectDev(net), virDomainNetGetActualDirectMode(net), - vnet_hdr, def->uuid, + true, vnet_hdr, def->uuid, virDomainNetGetActualDirectVirtPortProfile(net), &res_ifname, vmop, driver->stateDir, diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index fe2f383..98b0f9a 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -72,11 +72,14 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST, # define MACVTAP_NAME_PREFIX "macvtap" # define MACVTAP_NAME_PATTERN "macvtap%d"
+# define MACVLAN_NAME_PREFIX "macvlan" +# define MACVLAN_NAME_PATTERN "macvlan%d" + /** * virNetDevMacVLanCreate: * * @ifname: The name the interface is supposed to have; optional parameter - * @type: The type of device, i.e., "macvtap" + * @type: The type of device, i.e., "macvtap", "macvlan" * @macaddress: The MAC address of the device * @srcdev: The name of the 'link' device * @macvlan_mode: The macvlan mode to use @@ -458,14 +461,14 @@ static const uint32_t modeMap[VIR_NETDEV_MACVLAN_MODE_LAST] = { * interface will be stored into if everything succeeded. It is up * to the caller to free the string. * - * Returns file descriptor of the tap device in case of success, - * negative value otherwise with error reported. - * + * Returns file descriptor of the tap device in case of success with @withTap, + * otherwise returns 0; returns -1 on error. */ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname, const unsigned char *macaddress, const char *linkdev, enum virNetDevMacVLanMode mode, + bool withTap, int vnet_hdr, const unsigned char *vmuuid, virNetDevVPortProfilePtr virtPortProfile, @@ -474,7 +477,9 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname, char *stateDir, virNetDevBandwidthPtr bandwidth) { - const char *type = "macvtap"; + const char *type = withTap ? "macvtap" : "macvlan"; + const char *prefix = withTap ? MACVTAP_NAME_PREFIX : MACVLAN_NAME_PREFIX; + const char *pattern = withTap ? MACVTAP_NAME_PATTERN : MACVLAN_NAME_PATTERN; int c, rc; char ifname[IFNAMSIZ]; int retries, do_retry = 0; @@ -505,8 +510,7 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname, return -1;
if (ret) { - if (STRPREFIX(tgifname, - MACVTAP_NAME_PREFIX)) { + if (STRPREFIX(tgifname, prefix)) { goto create_name; } virReportSystemError(EEXIST, @@ -522,7 +526,7 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname, create_name: retries = 5; for (c = 0; c< 8192; c++) { - snprintf(ifname, sizeof(ifname), MACVTAP_NAME_PATTERN, c); + snprintf(ifname, sizeof(ifname), pattern, c); if ((ret = virNetDevExists(ifname))< 0) return -1; if (!ret) { @@ -553,15 +557,26 @@ create_name: goto disassociate_exit; }
- rc = virNetDevMacVLanTapOpen(cr_ifname, 10); - if (rc>= 0) { + if (withTap) { + if ((rc = virNetDevMacVLanTapOpen(cr_ifname, 10))< 0) + goto disassociate_exit; + if (virNetDevMacVLanTapSetup(rc, vnet_hdr)< 0) { VIR_FORCE_CLOSE(rc); /* sets rc to -1 */ goto disassociate_exit; } - *res_ifname = strdup(cr_ifname); - } else - goto disassociate_exit; + if (!(*res_ifname = strdup(cr_ifname))) { + VIR_FORCE_CLOSE(rc); /* sets rc to -1 */ + virReportOOMError(); + goto disassociate_exit; + } + } else { + if (!(*res_ifname = strdup(cr_ifname))) { + virReportOOMError(); + goto disassociate_exit; + } + rc = 0; + }
if (virNetDevBandwidthSet(cr_ifname, bandwidth)< 0) { virNetDevError(VIR_ERR_INTERNAL_ERROR, diff --git a/src/util/virnetdevmacvlan.h b/src/util/virnetdevmacvlan.h index 73918b8..130ecea 100644 --- a/src/util/virnetdevmacvlan.h +++ b/src/util/virnetdevmacvlan.h @@ -55,6 +55,7 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *ifname, const unsigned char *macaddress, const char *linkdev, enum virNetDevMacVLanMode mode, + bool withTap, int vnet_hdr, const unsigned char *vmuuid, virNetDevVPortProfilePtr virtPortProfile, @@ -62,8 +63,8 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *ifname, enum virNetDevVPortProfileOp vmop, char *stateDir, virNetDevBandwidthPtr bandwidth) - ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(6) - ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(10) ATTRIBUTE_RETURN_CHECK; + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(7) + ATTRIBUTE_NONNULL(9) ATTRIBUTE_NONNULL(11) ATTRIBUTE_RETURN_CHECK;
int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname, const unsigned char *macaddress, ACK

From: "Daniel P. Berrange" <berrange@redhat.com> Support creation of macvlan devices for LXC containers. Do not allow setting of network filters, bandwidth controls or vport profiles due to the complication that there is no host side visible device to work with. * src/lxc/lxc_driver.c: Support type=direct interfaces --- src/lxc/lxc_driver.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 105 insertions(+), 1 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 4f6807b..09752a3 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1230,6 +1230,102 @@ cleanup: return ret; } + +static int lxcSetupInterfaceDirect(virConnectPtr conn, + virDomainDefPtr def, + virDomainNetDefPtr net, + unsigned int *nveths, + char ***veths) +{ + int ret = 0; + char *res_ifname = NULL; + lxc_driver_t *driver = conn->privateData; + virNetDevBandwidthPtr bw; + virNetDevVPortProfilePtr prof; + + /* XXX how todo filtering ? + * Since the 'net-ifname' is about to be moved to a different + * namespace & renamed, there will be no host side visible + * interface for the container to attach rules to + */ + if (net->filter) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set network filters on direct interfaces")); + return -1; + } + + /* XXX how todo bandwidth controls ? + * Since the 'net-ifname' is about to be moved to a different + * namespace & renamed, there will be no host side visible + * interface for the container to attach rules to + */ + bw = virDomainNetGetActualBandwidth(net); + if (bw) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set network bandwidth on direct interfaces")); + return -1; + } + + /* XXX how todo port profiles ? + * Although we can do the association during container + * startup, at shutdown we are unable to disassociate + * because the macvlan device was moved to the container + * and automagically dies when the container dies. So + * we have no dev to perform disassociation with. + */ + prof = virDomainNetGetActualDirectVirtPortProfile(net); + if (prof) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set port profile on direct interfaces")); + return -1; + } + + if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) { + virReportOOMError(); + return -1; + } + (*veths)[(*nveths)] = NULL; + + if (virNetDevMacVLanCreateWithVPortProfile( + net->ifname, net->mac, + virDomainNetGetActualDirectDev(net), + virDomainNetGetActualDirectMode(net), + false, false, def->uuid, + virDomainNetGetActualDirectVirtPortProfile(net), + &res_ifname, + VIR_NETDEV_VPORT_PROFILE_OP_CREATE, + driver->stateDir, + virDomainNetGetActualBandwidth(net)) < 0) + goto cleanup; + + (*veths)[(*nveths)] = res_ifname; + (*nveths)++; + +#if 0 + if (rc >= 0) { + if ((net->filter) && (net->ifname)) { + err = virDomainConfNWFilterInstantiate(conn, net); + if (err) { + VIR_FORCE_CLOSE(rc); + ignore_value(virNetDevMacVLanDeleteWithVPortProfile( + net->ifname, net->mac, + virDomainNetGetActualDirectDev(net), + virDomainNetGetActualDirectMode(net), + virDomainNetGetActualDirectVirtPortProfile(net), + driver->stateDir)); + VIR_FREE(net->ifname); + } + } + } +#endif + + ret = 0; + +cleanup: + return ret; +} + + /** * lxcSetupInterfaces: * @conn: pointer to connection @@ -1299,13 +1395,21 @@ static int lxcSetupInterfaces(virConnectPtr conn, goto cleanup; } break; + case VIR_DOMAIN_NET_TYPE_DIRECT: + if (lxcSetupInterfaceDirect(conn, + def, + def->nets[i], + nveths, + veths) < 0) + goto cleanup; + break; + case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_ETHERNET: case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: case VIR_DOMAIN_NET_TYPE_INTERNAL: - case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_LAST: lxcError(VIR_ERR_INTERNAL_ERROR, _("Unsupported network type %s"), -- 1.7.6.4

On 11/10/2011 06:28 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange"<berrange@redhat.com>
Support creation of macvlan devices for LXC containers. Do not allow setting of network filters, bandwidth controls or vport profiles due to the complication that there is no host side visible device to work with.
* src/lxc/lxc_driver.c: Support type=direct interfaces --- src/lxc/lxc_driver.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 105 insertions(+), 1 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 4f6807b..09752a3 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1230,6 +1230,102 @@ cleanup: return ret; }
+ +static int lxcSetupInterfaceDirect(virConnectPtr conn, + virDomainDefPtr def, + virDomainNetDefPtr net, + unsigned int *nveths, + char ***veths) +{ + int ret = 0; + char *res_ifname = NULL; + lxc_driver_t *driver = conn->privateData; + virNetDevBandwidthPtr bw; + virNetDevVPortProfilePtr prof; + + /* XXX how todo filtering ? + * Since the 'net-ifname' is about to be moved to a different + * namespace& renamed, there will be no host side visible + * interface for the container to attach rules to + */ Afaik, filtering doesn't work on the direct interfaces anyway due to missing hooks in their kernel implementation. At least I have been told so about the macvtap type of device. + if (net->filter) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set network filters on direct interfaces")); + return -1; + } + + /* XXX how todo bandwidth controls ? + * Since the 'net-ifname' is about to be moved to a different + * namespace& renamed, there will be no host side visible + * interface for the container to attach rules to + */ + bw = virDomainNetGetActualBandwidth(net); + if (bw) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set network bandwidth on direct interfaces")); + return -1; + } + + /* XXX how todo port profiles ? + * Although we can do the association during container + * startup, at shutdown we are unable to disassociate + * because the macvlan device was moved to the container + * and automagically dies when the container dies. So + * we have no dev to perform disassociation with. + */ + prof = virDomainNetGetActualDirectVirtPortProfile(net); + if (prof) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set port profile on direct interfaces")); + return -1; + } + + if (VIR_REALLOC_N(*veths, (*nveths)+1)< 0) { + virReportOOMError(); + return -1; + } + (*veths)[(*nveths)] = NULL; + + if (virNetDevMacVLanCreateWithVPortProfile( + net->ifname, net->mac, + virDomainNetGetActualDirectDev(net), + virDomainNetGetActualDirectMode(net), + false, false, def->uuid, + virDomainNetGetActualDirectVirtPortProfile(net), +&res_ifname, + VIR_NETDEV_VPORT_PROFILE_OP_CREATE, + driver->stateDir, + virDomainNetGetActualBandwidth(net))< 0) + goto cleanup; + + (*veths)[(*nveths)] = res_ifname; + (*nveths)++; + +#if 0 + if (rc>= 0) { + if ((net->filter)&& (net->ifname)) { + err = virDomainConfNWFilterInstantiate(conn, net); + if (err) { + VIR_FORCE_CLOSE(rc); + ignore_value(virNetDevMacVLanDeleteWithVPortProfile( + net->ifname, net->mac, + virDomainNetGetActualDirectDev(net), + virDomainNetGetActualDirectMode(net), + virDomainNetGetActualDirectVirtPortProfile(net), + driver->stateDir)); + VIR_FREE(net->ifname); + } + } + } +#endif I think you can remove this block. + + ret = 0; + +cleanup: + return ret; +} + + /** * lxcSetupInterfaces: * @conn: pointer to connection @@ -1299,13 +1395,21 @@ static int lxcSetupInterfaces(virConnectPtr conn, goto cleanup; } break;
+ case VIR_DOMAIN_NET_TYPE_DIRECT: + if (lxcSetupInterfaceDirect(conn, + def, + def->nets[i], + nveths, + veths)< 0) + goto cleanup; + break; + case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_ETHERNET: case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: case VIR_DOMAIN_NET_TYPE_INTERNAL: - case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_LAST: lxcError(VIR_ERR_INTERNAL_ERROR, _("Unsupported network type %s"),
ACK , but see nits above.

On Thu, Nov 10, 2011 at 09:02:41AM -0500, Stefan Berger wrote:
On 11/10/2011 06:28 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange"<berrange@redhat.com>
Support creation of macvlan devices for LXC containers. Do not allow setting of network filters, bandwidth controls or vport profiles due to the complication that there is no host side visible device to work with.
* src/lxc/lxc_driver.c: Support type=direct interfaces --- src/lxc/lxc_driver.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 105 insertions(+), 1 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 4f6807b..09752a3 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1230,6 +1230,102 @@ cleanup: return ret; }
+ +static int lxcSetupInterfaceDirect(virConnectPtr conn, + virDomainDefPtr def, + virDomainNetDefPtr net, + unsigned int *nveths, + char ***veths) +{ + int ret = 0; + char *res_ifname = NULL; + lxc_driver_t *driver = conn->privateData; + virNetDevBandwidthPtr bw; + virNetDevVPortProfilePtr prof; + + /* XXX how todo filtering ? + * Since the 'net-ifname' is about to be moved to a different + * namespace& renamed, there will be no host side visible + * interface for the container to attach rules to + */ Afaik, filtering doesn't work on the direct interfaces anyway due to missing hooks in their kernel implementation. At least I have been told so about the macvtap type of device.
Oh, I wonder why the filtering controls are set for macvtap devices in the QEMU driver :-) Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 11/10/2011 09:32 AM, Daniel P. Berrange wrote:
On Thu, Nov 10, 2011 at 09:02:41AM -0500, Stefan Berger wrote:
On 11/10/2011 06:28 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange"<berrange@redhat.com>
Support creation of macvlan devices for LXC containers. Do not allow setting of network filters, bandwidth controls or vport profiles due to the complication that there is no host side visible device to work with.
* src/lxc/lxc_driver.c: Support type=direct interfaces --- src/lxc/lxc_driver.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 105 insertions(+), 1 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 4f6807b..09752a3 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1230,6 +1230,102 @@ cleanup: return ret; }
+ +static int lxcSetupInterfaceDirect(virConnectPtr conn, + virDomainDefPtr def, + virDomainNetDefPtr net, + unsigned int *nveths, + char ***veths) +{ + int ret = 0; + char *res_ifname = NULL; + lxc_driver_t *driver = conn->privateData; + virNetDevBandwidthPtr bw; + virNetDevVPortProfilePtr prof; + + /* XXX how todo filtering ? + * Since the 'net-ifname' is about to be moved to a different + * namespace& renamed, there will be no host side visible + * interface for the container to attach rules to + */ Afaik, filtering doesn't work on the direct interfaces anyway due to missing hooks in their kernel implementation. At least I have been told so about the macvtap type of device.
Oh, I wonder why the filtering controls are set for macvtap devices in the QEMU driver :-)
I will remove that. The parser already doesn't accept filters on direct interfaces. Stefan
Daniel
participants (2)
-
Daniel P. Berrange
-
Stefan Berger