[libvirt] [PATCH] network: Add bandwidth support to ethernet interface

Michal Privoznik mprivozn at redhat.com
Mon Nov 3 10:58:55 UTC 2014


On 30.10.2014 00:56, Anirban Chakraborty wrote:
> Ethernet interfaces in libvirt currently do not support bandwidth setting.
> For example, following xml file for an interface will not apply these
> settings to corresponding qdiscs.
>
>      <interface type="ethernet">
>        <mac address="02:36:1d:18:2a:e4"/>
>        <model type="virtio"/>
>        <script path=""/>
>        <target dev="tap361d182a-e4"/>
>        <bandwidth>
>          <inbound average="984" peak="1024" burst="64"/>
>          <outbound average="2000" peak="2048" burst="128"/>
>        </bandwidth>
>      </interface>
>
> Signed-off-by: Anirban Chakraborty <abchak at juniper.net>
> ---
>   src/conf/domain_conf.h      | 21 +++++++++++++++++++++
>   src/lxc/lxc_driver.c        |  3 +++
>   src/lxc/lxc_process.c       | 18 +++++++++---------
>   src/qemu/qemu_command.c     | 25 +++++++++++++++++++------
>   src/qemu/qemu_command.h     |  2 ++
>   src/qemu/qemu_driver.c      |  3 +++
>   src/qemu/qemu_hotplug.c     | 12 ++++++++++++
>   src/qemu/qemu_process.c     |  3 +++
>   src/util/virnetdevmacvlan.c | 10 ----------
>   src/util/virnetdevmacvlan.h |  1 -
>   10 files changed, 72 insertions(+), 26 deletions(-)
>
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 9908d88..40e85d9 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -2848,4 +2848,25 @@ int virDomainObjSetMetadata(virDomainObjPtr vm,
>   bool virDomainDefNeedsPlacementAdvice(virDomainDefPtr def)
>       ATTRIBUTE_NONNULL(1);
>
> +static inline bool virNetDevSupportBandwidth(virDomainNetType type)
> +{
> +    switch (type) {
> +    case VIR_DOMAIN_NET_TYPE_BRIDGE:
> +    case VIR_DOMAIN_NET_TYPE_NETWORK:
> +    case VIR_DOMAIN_NET_TYPE_DIRECT:
> +    case VIR_DOMAIN_NET_TYPE_ETHERNET:
> +        return true;
> +    case VIR_DOMAIN_NET_TYPE_USER:
> +    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
> +    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_HOSTDEV:
> +    case VIR_DOMAIN_NET_TYPE_LAST:
> +        break;
> +    }
> +    return false;
> +}
> +

I've got a feeling that this should go to src/util/virnetdevbandwidth* 
among with the rest of virNetDevBandwitdh functions.

>   #endif /* __DOMAIN_CONF_H */
> diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
> index 979382b..8a21af4 100644
> --- a/src/lxc/lxc_driver.c
> +++ b/src/lxc/lxc_driver.c
> @@ -72,6 +72,7 @@
>   #include "viraccessapicheck.h"
>   #include "viraccessapichecklxc.h"
>   #include "virhostdev.h"
> +#include "qemu/qemu_command.h"

This is not allowed. In case somebody is building with LXC but without 
QEMU ..

>
>   #define VIR_FROM_THIS VIR_FROM_LXC
>
> @@ -4634,6 +4635,8 @@ lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,
>
>       detach = vm->def->nets[detachidx];
>
> +    qemuDomainClearNetBandwidth(vm);
> +

.. this is going to be an undefined reference.

>       switch (virDomainNetGetActualType(detach)) {
>       case VIR_DOMAIN_NET_TYPE_BRIDGE:
>       case VIR_DOMAIN_NET_TYPE_NETWORK:
> diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
> index ed30c37..3192011 100644
> --- a/src/lxc/lxc_process.c
> +++ b/src/lxc/lxc_process.c
> @@ -274,11 +274,6 @@ char *virLXCProcessSetupInterfaceBridged(virConnectPtr conn,
>       if (virNetDevSetOnline(parentVeth, true) < 0)
>           goto cleanup;
>
> -    if (virNetDevBandwidthSet(net->ifname,
> -                              virDomainNetGetActualBandwidth(net),
> -                              false) < 0)
> -        goto cleanup;
> -


No, this function is called from two places:
1) when domain is starting up
2) on NIC hotplug

you are covering 1) but removing already working 2). We can't lose that 
functionality.

>       if (net->filter &&
>           virDomainConfNWFilterInstantiate(conn, vm->uuid, net) < 0)
>           goto cleanup;
> @@ -300,6 +295,7 @@ char *virLXCProcessSetupInterfaceDirect(virConnectPtr conn,
>       virNetDevBandwidthPtr bw;
>       virNetDevVPortProfilePtr prof;
>       virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
> +    const char *linkdev = virDomainNetGetActualDirectDev(net);
>
>       /* XXX how todo bandwidth controls ?
>        * Since the 'net-ifname' is about to be moved to a different
> @@ -329,14 +325,13 @@ char *virLXCProcessSetupInterfaceDirect(virConnectPtr conn,
>
>       if (virNetDevMacVLanCreateWithVPortProfile(
>               net->ifname, &net->mac,
> -            virDomainNetGetActualDirectDev(net),
> +            linkdev,
>               virDomainNetGetActualDirectMode(net),
>               false, def->uuid,
> -            virDomainNetGetActualVirtPortProfile(net),
> +            prof,
>               &res_ifname,
>               VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
> -            cfg->stateDir,
> -            virDomainNetGetActualBandwidth(net), 0) < 0)
> +            cfg->stateDir, 0) < 0)
>           goto cleanup;
>

Same comment applies here.

>       ret = res_ifname;
> @@ -450,6 +445,11 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
>               goto cleanup;
>           }
>
> +        /* set network bandwidth */
> +        if (virNetDevBandwidthSet(def->nets[i]->ifname,
> +                virDomainNetGetActualBandwidth(def->nets[i]), false) < 0)
> +           goto cleanup;
> +

Shouldn't this be guarded with virNetDevSupportBandwidth()? The problem 
is, there's a switch() just before this where all the unsupported NIC 
types are rejected (ETHERNET is rejected too btw). What will come 
through is DIRECT type. I'm not saying that we should not set bandwidth 
there, but this patch aims at ethernet.

>           (*veths)[(*nveths)-1] = veth;
>
>           /* Make sure all net definitions will have a name in the container */
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 2e5af4f..7922672 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -191,7 +191,6 @@ qemuPhysIfaceConnect(virDomainDefPtr def,
>           virDomainNetGetActualVirtPortProfile(net),
>           &res_ifname,
>           vmop, cfg->stateDir,
> -        virDomainNetGetActualBandwidth(net),
>           macvlan_create_flags);
>       if (rc >= 0) {
>           virDomainAuditNetDevice(def, net, res_ifname, true);
> @@ -371,11 +370,6 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
>                                     &net->mac) < 0)
>           goto cleanup;
>
> -    if (virNetDevBandwidthSet(net->ifname,
> -                              virDomainNetGetActualBandwidth(net),
> -                              false) < 0)
> -        goto cleanup;
> -
>       if (net->filter &&
>           virDomainConfNWFilterInstantiate(conn, def->uuid, net) < 0) {
>           goto cleanup;
> @@ -7427,6 +7421,13 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
>               goto cleanup;
>       }
>
> +    /* Set Bandwidth */
> +    if (virNetDevSupportBandwidth(actualType) &&
> +           virNetDevBandwidthSet(net->ifname,
> +           virDomainNetGetActualBandwidth(net),
> +           false) < 0)
> +        goto cleanup;

There's no guarantee that net->ifname is filled in here:

virsh # start migt10
error: Failed to start domain migt10
error: internal error: Child process (/sbin/tc qdisc add dev) unexpected 
exit status 255: Command line is not complete. Try option "help"

And I have to mention weird code formatting.

> +
>       if ((actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
>            actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
>            actualType == VIR_DOMAIN_NET_TYPE_ETHERNET ||
> @@ -12463,3 +12464,15 @@ virDomainDefPtr qemuParseCommandLinePid(virCapsPtr qemuCaps,
>       virStringFreeList(progenv);
>       return def;
>   }
> +
> +void qemuDomainClearNetBandwidth(virDomainObjPtr vm)
> +{
> +    size_t i;
> +    virDomainNetType type;
> +
> +    for (i = 0; i < vm->def->nnets; i++) {
> +        type = virDomainNetGetActualType(vm->def->nets[i]);
> +        if (virNetDevSupportBandwidth(type))
> +            virNetDevBandwidthClear(vm->def->nets[i]->ifname);
> +    }
> +}

Having this in qemu specific code feels strange, esp. when the code is 
to be called from other drivers too. How about moving it under 
src/util/virnetdevbandwidth*?

> diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
> index aa40c9e..7963a91 100644
> --- a/src/qemu/qemu_command.h
> +++ b/src/qemu/qemu_command.h
> @@ -277,4 +277,6 @@ int qemuCheckDiskConfig(virDomainDiskDefPtr disk);
>
>   bool
>   qemuCheckFips(void);
> +
> +void qemuDomainClearNetBandwidth(virDomainObjPtr vm);
>   #endif /* __QEMU_COMMAND_H__*/
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 2eaf77d..6ef1132 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -2196,6 +2196,9 @@ qemuDomainDestroyFlags(virDomainPtr dom,
>       if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
>           goto cleanup;
>
> +    /* Clear network bandwidth */
> +    qemuDomainClearNetBandwidth(vm);
> +

This is not needed. qemuProcessStop() will take care of that.

>       qemuDomainSetFakeReboot(driver, vm, false);
>
>
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index 33241fb..9eb125f 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -50,6 +50,7 @@
>   #include "virstring.h"
>   #include "virtime.h"
>   #include "storage/storage_driver.h"
> +#include "domain_conf.h"
>
>   #define VIR_FROM_THIS VIR_FROM_QEMU
>
> @@ -948,6 +949,12 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
>               goto cleanup;
>       }
>
> +    /* Set Bandwidth */
> +    if (virNetDevSupportBandwidth(actualType) &&
> +            virNetDevBandwidthSet(net->ifname,
> +            virDomainNetGetActualBandwidth(net), false) < 0)
> +        goto cleanup;
> +
>       for (i = 0; i < tapfdSize; i++) {
>           if (virSecurityManagerSetTapFDLabel(driver->securityManager,
>                                               vm->def, tapfd[i]) < 0)
> @@ -3536,6 +3543,11 @@ qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
>               goto cleanup;
>       }
>
> +    if (virNetDevSupportBandwidth(virDomainNetGetActualType(detach)) &&
> +            virNetDevBandwidthClear(detach->ifname) < 0)
> +        VIR_WARN("cannot clear bandwidth setting for device : %s",
> +                       detach->ifname);
> +
>       qemuDomainMarkDeviceForRemoval(vm, &detach->info);
>
>       qemuDomainObjEnterMonitor(driver, vm);
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index ef258cf..21448a5 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -4825,6 +4825,9 @@ void qemuProcessStop(virQEMUDriverPtr driver,
>                         virStrerror(errno, ebuf, sizeof(ebuf)));
>       }
>
> +    /* Clear network bandwidth */
> +    qemuDomainClearNetBandwidth(vm);
> +
>       virDomainConfVMNWFilterTeardown(vm);
>
>       if (cfg->macFilter) {
> diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
> index c83341c..956a96b 100644
> --- a/src/util/virnetdevmacvlan.c
> +++ b/src/util/virnetdevmacvlan.c
> @@ -811,7 +811,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname,
>                                              char **res_ifname,
>                                              virNetDevVPortProfileOp vmOp,
>                                              char *stateDir,
> -                                           virNetDevBandwidthPtr bandwidth,
>                                              unsigned int flags)
>   {
>       const char *type = (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) ?
> @@ -925,14 +924,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname,
>           rc = 0;
>       }
>
> -    if (virNetDevBandwidthSet(cr_ifname, bandwidth, false) < 0) {
> -        if (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP)
> -            VIR_FORCE_CLOSE(rc); /* sets rc to -1 */
> -        else
> -            rc = -1;
> -        goto disassociate_exit;
> -    }
> -
>       if (vmOp == VIR_NETDEV_VPORT_PROFILE_OP_CREATE ||
>           vmOp == VIR_NETDEV_VPORT_PROFILE_OP_RESTORE) {
>           /* Only directly register upon a create or restore (restarting
> @@ -1076,7 +1067,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *ifname ATTRIBUTE_UNUSED,
>                                              char **res_ifname ATTRIBUTE_UNUSED,
>                                              virNetDevVPortProfileOp vmop ATTRIBUTE_UNUSED,
>                                              char *stateDir ATTRIBUTE_UNUSED,
> -                                           virNetDevBandwidthPtr bandwidth ATTRIBUTE_UNUSED,
>                                              unsigned int flags)
>   {
>       virCheckFlags(0, -1);
> diff --git a/src/util/virnetdevmacvlan.h b/src/util/virnetdevmacvlan.h
> index 41aa4e2..f08d32b 100644
> --- a/src/util/virnetdevmacvlan.h
> +++ b/src/util/virnetdevmacvlan.h
> @@ -68,7 +68,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *ifname,
>                                              char **res_ifname,
>                                              virNetDevVPortProfileOp vmop,
>                                              char *stateDir,
> -                                           virNetDevBandwidthPtr bandwidth,
>                                              unsigned int flags)
>       ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(6)
>       ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(10) ATTRIBUTE_RETURN_CHECK;
>

BTW: it would be nice if you can version you patches. I mean, this is 
what, 4th or 5th version? Say that in subject explicitly please. You 
know, in the prefix: [PATCH v5] network: ...

Michal




More information about the libvir-list mailing list