diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index f0ff703269..ddfa77cb92 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -129,6 +129,8 @@
numbers, The units for average
and peak
attributes
are kilobytes per second, and for the burst
just kilobytes.
The rate is shared equally within domains connected to the network.
+ Moreover, bandwidth
element can be included in
+ portgroup
element.
Since 0.9.4
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 072c970e7d..f99294cc1c 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -753,6 +753,8 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def)
break;
}
+ virBandwidthDefFree(def->bandwidth);
+
VIR_FREE(def);
}
@@ -2621,6 +2623,7 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
virDomainActualNetDefPtr actual = NULL;
int ret = -1;
xmlNodePtr save_ctxt = ctxt->node;
+ xmlNodePtr bandwidth_node = NULL;
char *type = NULL;
char *mode = NULL;
@@ -2677,6 +2680,11 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
}
}
+ bandwidth_node = virXPathNode("./bandwidth", ctxt);
+ if (bandwidth_node &&
+ !(actual->bandwidth = virBandwidthDefParseNode(bandwidth_node)))
+ goto error;
+
*def = actual;
actual = NULL;
ret = 0;
@@ -8713,6 +8721,10 @@ virDomainActualNetDefFormat(virBufferPtr buf,
default:
break;
}
+
+ if (virBandwidthDefFormat(buf, def->bandwidth, " ") < 0)
+ goto error;
+
virBufferAddLit(buf, " \n");
ret = 0;
@@ -11383,3 +11395,13 @@ virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface)
return NULL;
return iface->data.network.actual->data.direct.virtPortProfile;
}
+
+virBandwidthPtr
+virDomainNetGetActualBandwidth(virDomainNetDefPtr iface)
+{
+ if ((iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) &&
+ iface->data.network.actual && iface->data.network.actual->bandwidth) {
+ return iface->data.network.actual->bandwidth;
+ }
+ return iface->bandwidth;
+}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 212f0c5f0f..715d99572e 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -362,6 +362,7 @@ struct _virDomainActualNetDef {
virVirtualPortProfileParamsPtr virtPortProfile;
} direct;
} data;
+ virBandwidthPtr bandwidth;
};
/* Stores the virtual network interface configuration */
@@ -1490,6 +1491,8 @@ char *virDomainNetGetActualDirectDev(virDomainNetDefPtr iface);
int virDomainNetGetActualDirectMode(virDomainNetDefPtr iface);
virVirtualPortProfileParamsPtr
virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface);
+virBandwidthPtr
+virDomainNetGetActualBandwidth(virDomainNetDefPtr iface);
int virDomainControllerInsert(virDomainDefPtr def,
virDomainControllerDefPtr controller);
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 1ef80dc01d..6714c209a7 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -92,6 +92,8 @@ virPortGroupDefClear(virPortGroupDefPtr def)
{
VIR_FREE(def->name);
VIR_FREE(def->virtPortProfile);
+ virBandwidthDefFree(def->bandwidth);
+ def->bandwidth = NULL;
}
static void
@@ -771,6 +773,7 @@ virNetworkPortGroupParseXML(virPortGroupDefPtr def,
xmlNodePtr save;
xmlNodePtr virtPortNode;
+ xmlNodePtr bandwidth_node;
char *isDefault = NULL;
int result = -1;
@@ -790,6 +793,12 @@ virNetworkPortGroupParseXML(virPortGroupDefPtr def,
goto error;
}
+ bandwidth_node = virXPathNode("./bandwidth", ctxt);
+ if (bandwidth_node &&
+ !(def->bandwidth = virBandwidthDefParseNode(bandwidth_node))) {
+ goto error;
+ }
+
result = 0;
error:
if (result < 0) {
@@ -1257,6 +1266,7 @@ virPortGroupDefFormat(virBufferPtr buf,
}
virBufferAddLit(buf, ">\n");
virVirtualPortProfileFormat(buf, def->virtPortProfile, " ");
+ virBandwidthDefFormat(buf, def->bandwidth, " ");
virBufferAddLit(buf, " \n");
}
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 6d0845e36c..869085e0bd 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -123,6 +123,7 @@ struct _virPortGroupDef {
char *name;
bool isDefault;
virVirtualPortProfileParamsPtr virtPortProfile;
+ virBandwidthPtr bandwidth;
};
typedef struct _virNetworkDef virNetworkDef;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 853ee628f1..a40610093c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -337,6 +337,7 @@ virDomainLoadAllConfigs;
virDomainMemballoonModelTypeFromString;
virDomainMemballoonModelTypeToString;
virDomainNetDefFree;
+virDomainNetGetActualBandwidth;
virDomainNetGetActualBridgeName;
virDomainNetGetActualDirectDev;
virDomainNetGetActualDirectMode;
@@ -710,6 +711,7 @@ nlComm;
# network.h
+virBandwidthCopy;
virBandwidthDefFormat;
virBandwidthDefFree;
virBandwidthDefParseNode;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index b1c6b12bf3..b8c6c97507 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -2811,6 +2811,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface)
(netdef->forwardType == VIR_NETWORK_FORWARD_VEPA) ||
(netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH)) {
virVirtualPortProfileParamsPtr virtport = NULL;
+ virPortGroupDefPtr portgroup = NULL;
/* are all
* VIR_DOMAIN_NET_TYPE_DIRECT.
@@ -2839,11 +2840,10 @@ networkAllocateActualDevice(virDomainNetDefPtr iface)
}
/* Find the most specific virtportprofile and copy it */
+ portgroup = virPortGroupFindByName(netdef, iface->data.network.portgroup);
if (iface->data.network.virtPortProfile) {
virtport = iface->data.network.virtPortProfile;
} else {
- virPortGroupDefPtr portgroup
- = virPortGroupFindByName(netdef, iface->data.network.portgroup);
if (portgroup)
virtport = portgroup->virtPortProfile;
else
@@ -2859,6 +2859,21 @@ networkAllocateActualDevice(virDomainNetDefPtr iface)
*/
*iface->data.network.actual->data.direct.virtPortProfile = *virtport;
}
+
+ /* Find the most specific bandwidth config and copy it */
+ if (iface->bandwidth) {
+ if (virBandwidthCopy(&iface->data.network.actual->bandwidth,
+ iface->bandwidth) < 0) {
+ goto cleanup;
+ }
+ } else {
+ if (portgroup &&
+ virBandwidthCopy(&iface->data.network.actual->bandwidth,
+ portgroup->bandwidth) < 0) {
+ goto cleanup;
+ }
+ }
+
/* If there is only a single device, just return it (caller will detect
* any error if exclusive use is required but could not be acquired).
*/
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index f8fd4eee9a..35d6b1e021 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -132,7 +132,8 @@ qemuPhysIfaceConnect(virDomainDefPtr def,
vnet_hdr, def->uuid,
virDomainNetGetActualDirectVirtPortProfile(net),
&res_ifname,
- vmop, driver->stateDir, net->bandwidth);
+ vmop, driver->stateDir,
+ virDomainNetGetActualBandwidth(net));
if (rc >= 0) {
virDomainAuditNetDevice(def, net, res_ifname, true);
VIR_FREE(net->ifname);
@@ -299,7 +300,8 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
}
if (tapfd >= 0 &&
- virBandwidthEnable(net->bandwidth, net->ifname) < 0) {
+ virBandwidthEnable(virDomainNetGetActualBandwidth(net),
+ net->ifname) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot set bandwidth limits on %s"),
net->ifname);
diff --git a/src/util/network.c b/src/util/network.c
index 5561012ada..6fcdab2bba 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -1263,3 +1263,61 @@ cleanup:
virCommandFree(cmd);
return ret;
}
+
+/*
+ * virBandwidthCopy:
+ * @dest: destination
+ * @src: source
+ *
+ * Returns -1 on OOM error (which gets reported),
+ * 0 otherwise.
+ */
+int
+virBandwidthCopy(virBandwidthPtr *dest,
+ const virBandwidthPtr src)
+{
+ int ret = -1;
+
+ if (!dest) {
+ virSocketError(VIR_ERR_INVALID_ARG, "%s",
+ _("invalid argument supplied"));
+ return -1;
+ }
+
+ *dest = NULL;
+ if (!src) {
+ /* nothing to be copied */
+ return 0;
+ }
+
+ if (VIR_ALLOC(*dest) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (src->in) {
+ if (VIR_ALLOC((*dest)->in) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ memcpy((*dest)->in, src->in, sizeof(*src->in));
+ }
+
+ if (src->out) {
+ if (VIR_ALLOC((*dest)->out) < 0) {
+ virReportOOMError();
+ VIR_FREE((*dest)->in);
+ goto cleanup;
+ }
+ memcpy((*dest)->out, src->out, sizeof(*src->out));
+ }
+
+ ret = 0;
+
+cleanup:
+ if (ret < 0) {
+ virBandwidthDefFree(*dest);
+ *dest = NULL;
+ }
+ return ret;
+}
diff --git a/src/util/network.h b/src/util/network.h
index 139f6ccb8b..6ceaa6d5b9 100644
--- a/src/util/network.h
+++ b/src/util/network.h
@@ -158,4 +158,6 @@ int virBandwidthDefFormat(virBufferPtr buf,
int virBandwidthEnable(virBandwidthPtr bandwidth, const char *iface);
int virBandwidthDisable(const char *iface, bool may_fail);
+int virBandwidthCopy(virBandwidthPtr *dest, const virBandwidthPtr src);
+
#endif /* __VIR_NETWORK_H__ */