|
|
7a3408 |
From b80365f3a798bfc245d3db7d7586d2e82b38f68e Mon Sep 17 00:00:00 2001
|
|
|
7a3408 |
Message-Id: <b80365f3a798bfc245d3db7d7586d2e82b38f68e@dist-git>
|
|
|
7a3408 |
From: Michal Privoznik <mprivozn@redhat.com>
|
|
|
7a3408 |
Date: Fri, 14 Aug 2015 16:06:32 +0200
|
|
|
7a3408 |
Subject: [PATCH] bridge_driver: Introduce networkBandwidthUpdate
|
|
|
7a3408 |
|
|
|
7a3408 |
https://bugzilla.redhat.com/show_bug.cgi?id=1252473
|
|
|
7a3408 |
|
|
|
7a3408 |
So, if a domain vNIC's bandwidth has been successfully set, it's
|
|
|
7a3408 |
possible that because @floor is set on network's bridge, this
|
|
|
7a3408 |
part may need updating too. And that's exactly what this function
|
|
|
7a3408 |
does. While the previous commit introduced a function to check if
|
|
|
7a3408 |
@floor can be satisfied, this does all the hard work. In general,
|
|
|
7a3408 |
there may be three, well four possibilities:
|
|
|
7a3408 |
|
|
|
7a3408 |
1) No change in @floor value (either it remain unset, or its
|
|
|
7a3408 |
value hasn't changed)
|
|
|
7a3408 |
|
|
|
7a3408 |
2) The @floor value has changed from a non-zero to a non-zero
|
|
|
7a3408 |
value
|
|
|
7a3408 |
|
|
|
7a3408 |
3) New @floor is to be set
|
|
|
7a3408 |
|
|
|
7a3408 |
4) Old @floor must be cleared out
|
|
|
7a3408 |
|
|
|
7a3408 |
The difference between 2), 3) and 4) is, that while in 2) the QoS
|
|
|
7a3408 |
tree on the network's bridge already has a special class for the
|
|
|
7a3408 |
vNIC, in 3) the class must be created from scratch. In 4) it must
|
|
|
7a3408 |
be removed. Fortunately, we have helpers for all three
|
|
|
7a3408 |
interesting cases.
|
|
|
7a3408 |
|
|
|
7a3408 |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
7a3408 |
(cherry picked from commit 812932bea2c703d4031f947096f8efaf21b662bf)
|
|
|
7a3408 |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
7a3408 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
7a3408 |
---
|
|
|
7a3408 |
src/network/bridge_driver.c | 163 ++++++++++++++++++++++++++++++++++++--------
|
|
|
7a3408 |
src/network/bridge_driver.h | 11 +++
|
|
|
7a3408 |
2 files changed, 145 insertions(+), 29 deletions(-)
|
|
|
7a3408 |
|
|
|
7a3408 |
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
|
|
|
7a3408 |
index 04602ed..666078c 100644
|
|
|
7a3408 |
--- a/src/network/bridge_driver.c
|
|
|
7a3408 |
+++ b/src/network/bridge_driver.c
|
|
|
7a3408 |
@@ -4794,38 +4794,17 @@ networkNextClassID(virNetworkObjPtr net)
|
|
|
7a3408 |
return ret;
|
|
|
7a3408 |
}
|
|
|
7a3408 |
|
|
|
7a3408 |
+
|
|
|
7a3408 |
static int
|
|
|
7a3408 |
-networkPlugBandwidth(virNetworkObjPtr net,
|
|
|
7a3408 |
- virDomainNetDefPtr iface)
|
|
|
7a3408 |
+networkPlugBandwidthImpl(virNetworkObjPtr net,
|
|
|
7a3408 |
+ virDomainNetDefPtr iface,
|
|
|
7a3408 |
+ virNetDevBandwidthPtr ifaceBand,
|
|
|
7a3408 |
+ unsigned long long new_rate)
|
|
|
7a3408 |
{
|
|
|
7a3408 |
virNetworkDriverStatePtr driver = networkGetDriver();
|
|
|
7a3408 |
- int ret = -1;
|
|
|
7a3408 |
- int plug_ret;
|
|
|
7a3408 |
- unsigned long long new_rate = 0;
|
|
|
7a3408 |
ssize_t class_id = 0;
|
|
|
7a3408 |
- char ifmac[VIR_MAC_STRING_BUFLEN];
|
|
|
7a3408 |
- virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
|
|
|
7a3408 |
-
|
|
|
7a3408 |
- if ((plug_ret = networkCheckBandwidth(net, ifaceBand, NULL,
|
|
|
7a3408 |
- iface->mac, &new_rate)) < 0) {
|
|
|
7a3408 |
- /* helper reported error */
|
|
|
7a3408 |
- goto cleanup;
|
|
|
7a3408 |
- }
|
|
|
7a3408 |
-
|
|
|
7a3408 |
- if (plug_ret > 0) {
|
|
|
7a3408 |
- /* no QoS needs to be set; claim success */
|
|
|
7a3408 |
- ret = 0;
|
|
|
7a3408 |
- goto cleanup;
|
|
|
7a3408 |
- }
|
|
|
7a3408 |
-
|
|
|
7a3408 |
- virMacAddrFormat(&iface->mac, ifmac);
|
|
|
7a3408 |
- if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
|
7a3408 |
- !iface->data.network.actual) {
|
|
|
7a3408 |
- virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
7a3408 |
- _("Cannot set bandwidth on interface '%s' of type %d"),
|
|
|
7a3408 |
- ifmac, iface->type);
|
|
|
7a3408 |
- goto cleanup;
|
|
|
7a3408 |
- }
|
|
|
7a3408 |
+ int plug_ret;
|
|
|
7a3408 |
+ int ret = -1;
|
|
|
7a3408 |
|
|
|
7a3408 |
/* generate new class_id */
|
|
|
7a3408 |
if ((class_id = networkNextClassID(net)) < 0) {
|
|
|
7a3408 |
@@ -4861,6 +4840,46 @@ networkPlugBandwidth(virNetworkObjPtr net,
|
|
|
7a3408 |
net->def->bridge);
|
|
|
7a3408 |
|
|
|
7a3408 |
ret = 0;
|
|
|
7a3408 |
+ cleanup:
|
|
|
7a3408 |
+ return ret;
|
|
|
7a3408 |
+}
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+static int
|
|
|
7a3408 |
+networkPlugBandwidth(virNetworkObjPtr net,
|
|
|
7a3408 |
+ virDomainNetDefPtr iface)
|
|
|
7a3408 |
+{
|
|
|
7a3408 |
+ int ret = -1;
|
|
|
7a3408 |
+ int plug_ret;
|
|
|
7a3408 |
+ unsigned long long new_rate = 0;
|
|
|
7a3408 |
+ char ifmac[VIR_MAC_STRING_BUFLEN];
|
|
|
7a3408 |
+ virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if ((plug_ret = networkCheckBandwidth(net, ifaceBand, NULL,
|
|
|
7a3408 |
+ iface->mac, &new_rate)) < 0) {
|
|
|
7a3408 |
+ /* helper reported error */
|
|
|
7a3408 |
+ goto cleanup;
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if (plug_ret > 0) {
|
|
|
7a3408 |
+ /* no QoS needs to be set; claim success */
|
|
|
7a3408 |
+ ret = 0;
|
|
|
7a3408 |
+ goto cleanup;
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ virMacAddrFormat(&iface->mac, ifmac);
|
|
|
7a3408 |
+ if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
|
7a3408 |
+ !iface->data.network.actual) {
|
|
|
7a3408 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
7a3408 |
+ _("Cannot set bandwidth on interface '%s' of type %d"),
|
|
|
7a3408 |
+ ifmac, iface->type);
|
|
|
7a3408 |
+ goto cleanup;
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if (networkPlugBandwidthImpl(net, iface, ifaceBand, new_rate) < 0)
|
|
|
7a3408 |
+ goto cleanup;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ ret = 0;
|
|
|
7a3408 |
|
|
|
7a3408 |
cleanup:
|
|
|
7a3408 |
return ret;
|
|
|
7a3408 |
@@ -4938,15 +4957,19 @@ static bool
|
|
|
7a3408 |
networkBandwidthGenericChecks(virDomainNetDefPtr iface,
|
|
|
7a3408 |
virNetDevBandwidthPtr newBandwidth)
|
|
|
7a3408 |
{
|
|
|
7a3408 |
- virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
|
|
|
7a3408 |
+ virNetDevBandwidthPtr ifaceBand;
|
|
|
7a3408 |
unsigned long long old_floor, new_floor;
|
|
|
7a3408 |
|
|
|
7a3408 |
+ if (!iface && !newBandwidth)
|
|
|
7a3408 |
+ return false;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
if (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_NETWORK) {
|
|
|
7a3408 |
/* This is not an interface that's plugged into a network.
|
|
|
7a3408 |
* We don't care. Thus from our POV bandwidth change is allowed. */
|
|
|
7a3408 |
return false;
|
|
|
7a3408 |
}
|
|
|
7a3408 |
|
|
|
7a3408 |
+ ifaceBand = virDomainNetGetActualBandwidth(iface);
|
|
|
7a3408 |
old_floor = new_floor = 0;
|
|
|
7a3408 |
|
|
|
7a3408 |
if (ifaceBand && ifaceBand->in)
|
|
|
7a3408 |
@@ -4987,3 +5010,85 @@ networkBandwidthChangeAllowed(virDomainNetDefPtr iface,
|
|
|
7a3408 |
virNetworkObjEndAPI(&network);
|
|
|
7a3408 |
return ret;
|
|
|
7a3408 |
}
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+int
|
|
|
7a3408 |
+networkBandwidthUpdate(virDomainNetDefPtr iface,
|
|
|
7a3408 |
+ virNetDevBandwidthPtr newBandwidth)
|
|
|
7a3408 |
+{
|
|
|
7a3408 |
+ virNetworkDriverStatePtr driver = networkGetDriver();
|
|
|
7a3408 |
+ virNetworkObjPtr network = NULL;
|
|
|
7a3408 |
+ virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
|
|
|
7a3408 |
+ unsigned long long new_rate = 0;
|
|
|
7a3408 |
+ int plug_ret;
|
|
|
7a3408 |
+ int ret = -1;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if (!networkBandwidthGenericChecks(iface, newBandwidth))
|
|
|
7a3408 |
+ return 0;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ network = virNetworkObjFindByName(driver->networks, iface->data.network.name);
|
|
|
7a3408 |
+ if (!network) {
|
|
|
7a3408 |
+ virReportError(VIR_ERR_NO_NETWORK,
|
|
|
7a3408 |
+ _("no network with matching name '%s'"),
|
|
|
7a3408 |
+ iface->data.network.name);
|
|
|
7a3408 |
+ return ret;
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if ((plug_ret = networkCheckBandwidth(network, newBandwidth, ifaceBand,
|
|
|
7a3408 |
+ iface->mac, &new_rate)) < 0) {
|
|
|
7a3408 |
+ /* helper reported error */
|
|
|
7a3408 |
+ goto cleanup;
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if (plug_ret > 0) {
|
|
|
7a3408 |
+ /* no QoS needs to be set; claim success */
|
|
|
7a3408 |
+ ret = 0;
|
|
|
7a3408 |
+ goto cleanup;
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ /* Okay, there are three possible scenarios: */
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if (ifaceBand->in && ifaceBand->in->floor &&
|
|
|
7a3408 |
+ newBandwidth->in && newBandwidth->in->floor) {
|
|
|
7a3408 |
+ /* Either we just need to update @floor .. */
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if (virNetDevBandwidthUpdateRate(network->def->bridge,
|
|
|
7a3408 |
+ iface->data.network.actual->class_id,
|
|
|
7a3408 |
+ network->def->bandwidth,
|
|
|
7a3408 |
+ newBandwidth->in->floor) < 0)
|
|
|
7a3408 |
+ goto cleanup;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ network->floor_sum -= ifaceBand->in->floor;
|
|
|
7a3408 |
+ network->floor_sum += newBandwidth->in->floor;
|
|
|
7a3408 |
+ new_rate -= network->floor_sum;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if (virNetDevBandwidthUpdateRate(network->def->bridge, 2,
|
|
|
7a3408 |
+ network->def->bandwidth, new_rate) < 0 ||
|
|
|
7a3408 |
+ virNetworkSaveStatus(driver->stateDir, network) < 0) {
|
|
|
7a3408 |
+ /* Ouch, rollback */
|
|
|
7a3408 |
+ network->floor_sum -= newBandwidth->in->floor;
|
|
|
7a3408 |
+ network->floor_sum += ifaceBand->in->floor;
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ ignore_value(virNetDevBandwidthUpdateRate(network->def->bridge,
|
|
|
7a3408 |
+ iface->data.network.actual->class_id,
|
|
|
7a3408 |
+ network->def->bandwidth,
|
|
|
7a3408 |
+ ifaceBand->in->floor));
|
|
|
7a3408 |
+ goto cleanup;
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
+ } else if (newBandwidth->in && newBandwidth->in->floor) {
|
|
|
7a3408 |
+ /* .. or we need to plug in new .. */
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if (networkPlugBandwidthImpl(network, iface, newBandwidth, new_rate) < 0)
|
|
|
7a3408 |
+ goto cleanup;
|
|
|
7a3408 |
+ } else {
|
|
|
7a3408 |
+ /* .. or unplug old. */
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ if (networkUnplugBandwidth(network, iface) < 0)
|
|
|
7a3408 |
+ goto cleanup;
|
|
|
7a3408 |
+ }
|
|
|
7a3408 |
+
|
|
|
7a3408 |
+ ret = 0;
|
|
|
7a3408 |
+ cleanup:
|
|
|
7a3408 |
+ virNetworkObjEndAPI(&network);
|
|
|
7a3408 |
+ return ret;
|
|
|
7a3408 |
+}
|
|
|
7a3408 |
diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h
|
|
|
7a3408 |
index cce9237..7db2c90 100644
|
|
|
7a3408 |
--- a/src/network/bridge_driver.h
|
|
|
7a3408 |
+++ b/src/network/bridge_driver.h
|
|
|
7a3408 |
@@ -57,6 +57,10 @@ bool networkBandwidthChangeAllowed(virDomainNetDefPtr iface,
|
|
|
7a3408 |
virNetDevBandwidthPtr newBandwidth)
|
|
|
7a3408 |
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
|
|
7a3408 |
|
|
|
7a3408 |
+int networkBandwidthUpdate(virDomainNetDefPtr iface,
|
|
|
7a3408 |
+ virNetDevBandwidthPtr newBandwidth)
|
|
|
7a3408 |
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
|
|
7a3408 |
+
|
|
|
7a3408 |
# else
|
|
|
7a3408 |
/* Define no-op replacements that don't drag in any link dependencies. */
|
|
|
7a3408 |
# define networkAllocateActualDevice(dom, iface) 0
|
|
|
7a3408 |
@@ -85,6 +89,13 @@ networkBandwidthChangeAllowed(virDomainNetDefPtr iface ATTRIBUTE_UNUSED,
|
|
|
7a3408 |
return true;
|
|
|
7a3408 |
}
|
|
|
7a3408 |
|
|
|
7a3408 |
+static inline int
|
|
|
7a3408 |
+networkBandwidthUpdate(virDomainNetDefPtr iface ATTRIBUTE_UNUSED,
|
|
|
7a3408 |
+ virNetDevBandwidthPtr newBandwidth ATTRIBUTE_UNUSED)
|
|
|
7a3408 |
+{
|
|
|
7a3408 |
+ return 0;
|
|
|
7a3408 |
+}
|
|
|
7a3408 |
+
|
|
|
7a3408 |
# endif
|
|
|
7a3408 |
|
|
|
7a3408 |
typedef char *(*networkDnsmasqLeaseFileNameFunc)(const char *netname);
|
|
|
7a3408 |
--
|
|
|
7a3408 |
2.5.0
|
|
|
7a3408 |
|