[libvirt] [PATCH 4/9] bridge_driver: Introduce networkBandwidthUpdate

John Ferlan jferlan at redhat.com
Tue Aug 11 01:01:02 UTC 2015



On 08/03/2015 02:39 AM, Michal Privoznik wrote:
> So, if a domain vNIC's bandwidth has been successfully set, it's
> possible that because @floor is set on network's bridge, this
> part may need updating too. And that's exactly what this function
> does. While the previous commit introduced a function to check if
> @floor can be satisfied, this does all the hard work. In general,
> there may be three, well four possibilities:
> 
>   1) No change in @floor value (either it remain unset, or its
>   value hasn't changed)
> 
>   2) The @floor value has changed from a non-zero to a non-zero
>   value
> 
>   3) New @floor is to be set
> 
>   4) Old @floor must be cleared out
> 
> The difference between 2), 3) and 4) is, that while in 2) the QoS
> tree on the network's bridge already has a special class for the
> vNIC, in 3) the class must be created from scratch. In 4) it must
> be removed. Fortunately, we have helpers for all three
> interesting cases.
> 
> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
> ---
>  src/network/bridge_driver.c | 160 ++++++++++++++++++++++++++++++++++++--------
>  src/network/bridge_driver.h |  10 +++
>  2 files changed, 142 insertions(+), 28 deletions(-)
> 
> diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
> index fa60ba4..5fad015 100644
> --- a/src/network/bridge_driver.c
> +++ b/src/network/bridge_driver.c
> @@ -4792,38 +4792,17 @@ networkNextClassID(virNetworkObjPtr net)
>      return ret;
>  }
>  
> +
>  static int
> -networkPlugBandwidth(virNetworkObjPtr net,
> -                     virDomainNetDefPtr iface)
> +networkPlugBandwidthImpl(virNetworkObjPtr net,
> +                         virDomainNetDefPtr iface,
> +                         virNetDevBandwidthPtr ifaceBand,
> +                         unsigned long long new_rate)
>  {
>      virNetworkDriverStatePtr driver = networkGetDriver();
> -    int ret = -1;
> -    int plug_ret;
> -    unsigned long long new_rate = 0;
>      ssize_t class_id = 0;
> -    char ifmac[VIR_MAC_STRING_BUFLEN];
> -    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
> -
> -    if ((plug_ret = networkCheckBandwidth(net, ifaceBand, NULL,
> -                                          iface->mac, &new_rate)) < 0) {
> -        /* helper reported error */
> -        goto cleanup;
> -    }
> -
> -    if (plug_ret > 0) {
> -        /* no QoS needs to be set; claim success */
> -        ret = 0;
> -        goto cleanup;
> -    }
> -
> -    virMacAddrFormat(&iface->mac, ifmac);
> -    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK ||
> -        !iface->data.network.actual) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("Cannot set bandwidth on interface '%s' of type %d"),
> -                       ifmac, iface->type);
> -        goto cleanup;
> -    }
> +    int plug_ret;
> +    int ret = -1;
>  
>      /* generate new class_id */
>      if ((class_id = networkNextClassID(net)) < 0) {
> @@ -4859,6 +4838,46 @@ networkPlugBandwidth(virNetworkObjPtr net,
>                   net->def->bridge);
>  
>      ret = 0;
> + cleanup:
> +    return ret;
> +}
> +
> +
> +static int
> +networkPlugBandwidth(virNetworkObjPtr net,
> +                     virDomainNetDefPtr iface)
> +{
> +    int ret = -1;
> +    int plug_ret;
> +    unsigned long long new_rate = 0;
> +    char ifmac[VIR_MAC_STRING_BUFLEN];
> +    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
> +
> +    if ((plug_ret = networkCheckBandwidth(net, ifaceBand, NULL,
> +                                          iface->mac, &new_rate)) < 0) {
> +        /* helper reported error */
> +        goto cleanup;
> +    }
> +
> +    if (plug_ret > 0) {
> +        /* no QoS needs to be set; claim success */
> +        ret = 0;
> +        goto cleanup;
> +    }
> +
> +    virMacAddrFormat(&iface->mac, ifmac);
> +    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK ||
> +        !iface->data.network.actual) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Cannot set bandwidth on interface '%s' of type %d"),
> +                       ifmac, iface->type);
> +        goto cleanup;
> +    }
> +
> +    if (networkPlugBandwidthImpl(net, iface, ifaceBand, new_rate) < 0)
> +        goto cleanup;
> +
> +    ret = 0;
>  
>   cleanup:
>      return ret;
> @@ -4939,6 +4958,9 @@ networkBandwidthGenericChecks(virDomainNetDefPtr iface,
>      virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);

^^
'iface' is used here... but !iface checked below...

>      unsigned long long old_floor, new_floor;
>  
> +    if (!iface && !newBandwidth)
> +        return false;
> +

Adding this !iface check causes Coverity issues for the following usage
of 'iface' (especially if 'newBandwidth' is non NULL)...

Checking the two (eventual) callers - networkBandwidthChangeAllowed
already has ATTRIBUTE_NONNULL(1) (2) checks and it seems logically at
least that networkBandwidthUpdate should have it.

Thus I don't think it's necessary (although I may have read things wrong
too ;-))

>      if (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_NETWORK) {
>          /* This is not an interface that's plugged into a network.
>           * We don't care. Thus from our POV bandwidth change is allowed. */
> @@ -4985,3 +5007,85 @@ networkBandwidthChangeAllowed(virDomainNetDefPtr iface,
>      virNetworkObjEndAPI(&network);
>      return ret;
>  }
> +
> +
> +int
> +networkBandwidthUpdate(virDomainNetDefPtr iface,
> +                       virNetDevBandwidthPtr newBandwidth)
> +{
> +    virNetworkDriverStatePtr driver = networkGetDriver();
> +    virNetworkObjPtr network = NULL;
> +    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);

^^
'iface' is used unconditionally here  So arg1 can have the ATTRIBUTE_NONNULL

'newBandwidth' is used below, so it too can have ATTRIBUTE_NONNULL

Which means check in GenericChecks is unnecessary - although to be safe
we could add the ATTRIBUTE_NONNULL to the static decl too.

> +    unsigned long long new_rate = 0;
> +    int plug_ret;
> +    int ret = -1;
> +
> +    if (!networkBandwidthGenericChecks(iface, newBandwidth))
> +        return 0;
> +
> +    network = virNetworkObjFindByName(driver->networks, iface->data.network.name);
> +    if (!network) {
> +        virReportError(VIR_ERR_NO_NETWORK,
> +                       _("no network with matching name '%s'"),
> +                       iface->data.network.name);
> +        return ret;
> +    }
> +
> +    if ((plug_ret = networkCheckBandwidth(network, ifaceBand, NULL,
> +                                          iface->mac, &new_rate)) < 0) {
> +        /* helper reported error */
> +        goto cleanup;
> +    }
> +
> +    if (plug_ret > 0) {
> +        /* no QoS needs to be set; claim success */
> +        ret = 0;
> +        goto cleanup;
> +    }
> +
> +    /* Okay, there are three possible scenarios: */
> +
> +    if (ifaceBand->in && ifaceBand->in->floor &&
> +        newBandwidth->in && newBandwidth->in->floor) {
> +        /* Either we just need to update @floor .. */
> +
> +        if (virNetDevBandwidthUpdateRate(network->def->bridge,
> +                                         iface->data.network.actual->class_id,
> +                                         network->def->bandwidth,
> +                                         newBandwidth->in->floor) < 0)
> +            goto cleanup;
> +
> +        network->floor_sum -= ifaceBand->in->floor;
> +        network->floor_sum += newBandwidth->in->floor;
> +        new_rate -= network->floor_sum;
> +
> +        if (virNetDevBandwidthUpdateRate(network->def->bridge, 2,
> +                                         network->def->bandwidth, new_rate) < 0 ||
> +            virNetworkSaveStatus(driver->stateDir, network) < 0) {
> +            /* Ouch, rollback */
> +            network->floor_sum -= newBandwidth->in->floor;
> +            network->floor_sum += ifaceBand->in->floor;
> +
> +            ignore_value(virNetDevBandwidthUpdateRate(network->def->bridge,
> +                                                      iface->data.network.actual->class_id,
> +                                                      network->def->bandwidth,
> +                                                      ifaceBand->in->floor));
> +            goto cleanup;
> +        }
> +    } else if (newBandwidth->in && newBandwidth->in->floor) {
> +        /* .. or we need to plug in new .. */
> +
> +        if (networkPlugBandwidthImpl(network, iface, newBandwidth, new_rate) < 0)
> +            goto cleanup;
> +    } else {
> +        /* .. or unplug old. */
> +
> +        if (networkUnplugBandwidth(network, iface) < 0)
> +            goto cleanup;
> +    }
> +
> +    ret = 0;
> + cleanup:
> +    virNetworkObjEndAPI(&network);
> +    return ret;
> +}
> diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h
> index cce9237..3a9f22d 100644
> --- a/src/network/bridge_driver.h
> +++ b/src/network/bridge_driver.h
> @@ -57,6 +57,9 @@ bool networkBandwidthChangeAllowed(virDomainNetDefPtr iface,
>                                     virNetDevBandwidthPtr newBandwidth)
>      ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
>  
> +int networkBandwidthUpdate(virDomainNetDefPtr iface,
> +                           virNetDevBandwidthPtr newBandwidth);
> +

I would think based on code ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
would be need to be added.  Additionally, networkBandwidthChangeAllowed
has them and this is called after that...

Beyond that I think things look OK

ACK with some adjustments

John
>  # else
>  /* Define no-op replacements that don't drag in any link dependencies.  */
>  #  define networkAllocateActualDevice(dom, iface) 0
> @@ -85,6 +88,13 @@ networkBandwidthChangeAllowed(virDomainNetDefPtr iface ATTRIBUTE_UNUSED,
>      return true;
>  }
>  
> +static inline int
> +networkBandwidthUpdate(virDomainNetDefPtr iface ATTRIBUTE_UNUSED,
> +                       virNetDevBandwidthPtr newBandwidth ATTRIBUTE_UNUSED)
> +{
> +    return 0;
> +}
> +
>  # endif
>  
>  typedef char *(*networkDnsmasqLeaseFileNameFunc)(const char *netname);
> 




More information about the libvir-list mailing list