mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-09-08 16:54:49 +00:00
bandwidth: Implement functions to enable and disable QoS
These function executes 'tc' with appropriate arguments to set desired QoS setting on interface or bridge during its creation.
This commit is contained in:
parent
aaa98b08ff
commit
90074ecfa7
@ -170,6 +170,8 @@ AC_PATH_PROG([RADVD], [radvd], [radvd],
|
||||
[/sbin:/usr/sbin:/usr/local/sbin:$PATH])
|
||||
AC_PATH_PROG([BRCTL], [brctl], [brctl],
|
||||
[/sbin:/usr/sbin:/usr/local/sbin:$PATH])
|
||||
AC_PATH_PROG([TC], [tc], [tc],
|
||||
[/sbin:/usr/sbin:/usr/local/sbin:$PATH])
|
||||
AC_PATH_PROG([UDEVADM], [udevadm], [],
|
||||
[/sbin:/usr/sbin:/usr/local/sbin:$PATH])
|
||||
AC_PATH_PROG([UDEVSETTLE], [udevsettle], [],
|
||||
@ -183,6 +185,8 @@ AC_DEFINE_UNQUOTED([RADVD],["$RADVD"],
|
||||
[Location or name of the radvd program])
|
||||
AC_DEFINE_UNQUOTED([BRCTL],["$BRCTL"],
|
||||
[Location or name of the brctl program (see bridge-utils)])
|
||||
AC_DEFINE_UNQUOTED([TC],["$TC"],
|
||||
[Location or name of the tc profram (see iproute2)])
|
||||
if test -n "$UDEVADM"; then
|
||||
AC_DEFINE_UNQUOTED([UDEVADM],["$UDEVADM"],
|
||||
[Location or name of the udevadm program])
|
||||
|
@ -250,7 +250,7 @@ Requires: %{name}-client = %{version}-%{release}
|
||||
Requires: bridge-utils
|
||||
# for modprobe of pci devices
|
||||
Requires: module-init-tools
|
||||
# for /sbin/ip
|
||||
# for /sbin/ip & /sbin/tc
|
||||
Requires: iproute
|
||||
%endif
|
||||
%if %{with_network}
|
||||
|
@ -713,6 +713,8 @@ nlComm;
|
||||
virBandwidthDefFormat;
|
||||
virBandwidthDefFree;
|
||||
virBandwidthDefParseNode;
|
||||
virBandwidthDisable;
|
||||
virBandwidthEnable;
|
||||
virSocketAddrBroadcast;
|
||||
virSocketAddrBroadcastByPrefix;
|
||||
virSocketAddrIsNetmask;
|
||||
|
@ -1822,10 +1822,23 @@ networkStartNetworkVirtual(struct network_driver *driver,
|
||||
if (v6present && networkStartRadvd(network) < 0)
|
||||
goto err4;
|
||||
|
||||
if (virBandwidthEnable(network->def->bandwidth, network->def->bridge) < 0) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot set bandwidth limits on %s"),
|
||||
network->def->bridge);
|
||||
goto err5;
|
||||
}
|
||||
|
||||
VIR_FREE(macTapIfName);
|
||||
|
||||
return 0;
|
||||
|
||||
err5:
|
||||
if (virBandwidthDisable(network->def->bridge, true) < 0) {
|
||||
VIR_WARN("Failed to disable QoS on %s",
|
||||
network->def->bridge);
|
||||
}
|
||||
|
||||
err4:
|
||||
if (!save_err)
|
||||
save_err = virSaveLastError();
|
||||
@ -1883,6 +1896,11 @@ static int networkShutdownNetworkVirtual(struct network_driver *driver,
|
||||
int err;
|
||||
char ebuf[1024];
|
||||
|
||||
if (virBandwidthDisable(network->def->bridge, true) < 0) {
|
||||
VIR_WARN("Failed to disable QoS on %s",
|
||||
network->def->name);
|
||||
}
|
||||
|
||||
if (network->radvdPid > 0) {
|
||||
char *radvdpidbase;
|
||||
|
||||
|
@ -132,7 +132,7 @@ qemuPhysIfaceConnect(virDomainDefPtr def,
|
||||
vnet_hdr, def->uuid,
|
||||
virDomainNetGetActualDirectVirtPortProfile(net),
|
||||
&res_ifname,
|
||||
vmop, driver->stateDir);
|
||||
vmop, driver->stateDir, net->bandwidth);
|
||||
if (rc >= 0) {
|
||||
virDomainAuditNetDevice(def, net, res_ifname, true);
|
||||
VIR_FREE(net->ifname);
|
||||
@ -298,6 +298,15 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
|
||||
}
|
||||
}
|
||||
|
||||
if (tapfd >= 0 &&
|
||||
virBandwidthEnable(net->bandwidth, net->ifname) < 0) {
|
||||
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot set bandwidth limits on %s"),
|
||||
net->ifname);
|
||||
VIR_FORCE_CLOSE(tapfd);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (tapfd >= 0) {
|
||||
if ((net->filter) && (net->ifname)) {
|
||||
err = virDomainConfNWFilterInstantiate(conn, net);
|
||||
|
@ -267,7 +267,8 @@ openMacvtapTap(const char *tgifname,
|
||||
virVirtualPortProfileParamsPtr virtPortProfile,
|
||||
char **res_ifname,
|
||||
enum virVMOperationType vmOp,
|
||||
char *stateDir)
|
||||
char *stateDir,
|
||||
virBandwidthPtr bandwidth)
|
||||
{
|
||||
const char *type = "macvtap";
|
||||
int c, rc;
|
||||
@ -361,6 +362,15 @@ create_name:
|
||||
} else
|
||||
goto disassociate_exit;
|
||||
|
||||
if (virBandwidthEnable(bandwidth, cr_ifname) < 0) {
|
||||
macvtapError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot set bandwidth limits on %s"),
|
||||
cr_ifname);
|
||||
rc = -1;
|
||||
goto disassociate_exit;
|
||||
}
|
||||
|
||||
|
||||
return rc;
|
||||
|
||||
disassociate_exit:
|
||||
|
@ -62,7 +62,8 @@ int openMacvtapTap(const char *ifname,
|
||||
virVirtualPortProfileParamsPtr virtPortProfile,
|
||||
char **res_ifname,
|
||||
enum virVMOperationType vmop,
|
||||
char *stateDir);
|
||||
char *stateDir,
|
||||
virBandwidthPtr bandwidth);
|
||||
|
||||
void delMacvtap(const char *ifname,
|
||||
const unsigned char *macaddress,
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "network.h"
|
||||
#include "util.h"
|
||||
#include "virterror_internal.h"
|
||||
#include "command.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||
#define virSocketError(code, ...) \
|
||||
@ -1102,3 +1103,163 @@ virBandwidthDefFormat(virBufferPtr buf,
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* virBandwidthEnable:
|
||||
* @bandwidth: rates to set
|
||||
* @iface: on which interface
|
||||
*
|
||||
* This function enables QoS on specified interface
|
||||
* and set given traffic limits for both, incoming
|
||||
* and outgoing traffic. Any previous setting get
|
||||
* overwritten.
|
||||
*
|
||||
* Return 0 on success, -1 otherwise.
|
||||
*/
|
||||
int
|
||||
virBandwidthEnable(virBandwidthPtr bandwidth,
|
||||
const char *iface)
|
||||
{
|
||||
int ret = -1;
|
||||
virCommandPtr cmd = NULL;
|
||||
char *average = NULL;
|
||||
char *peak = NULL;
|
||||
char *burst = NULL;
|
||||
|
||||
if (!iface)
|
||||
return -1;
|
||||
|
||||
if (!bandwidth) {
|
||||
/* nothing to be enabled */
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virBandwidthDisable(iface, true) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (bandwidth->in) {
|
||||
if (virAsprintf(&average, "%llukbps", bandwidth->in->average) < 0)
|
||||
goto cleanup;
|
||||
if (bandwidth->in->peak &&
|
||||
(virAsprintf(&peak, "%llukbps", bandwidth->in->peak) < 0))
|
||||
goto cleanup;
|
||||
if (bandwidth->in->burst &&
|
||||
(virAsprintf(&burst, "%llukb", bandwidth->in->burst) < 0))
|
||||
goto cleanup;
|
||||
|
||||
cmd = virCommandNew(TC);
|
||||
virCommandAddArgList(cmd, "qdisc", "add", "dev", iface, "root",
|
||||
"handle", "1:", "htb", "default", "1", NULL);
|
||||
if (virCommandRun(cmd, NULL) < 0)
|
||||
goto cleanup;
|
||||
|
||||
virCommandFree(cmd);
|
||||
cmd = virCommandNew(TC);
|
||||
virCommandAddArgList(cmd,"class", "add", "dev", iface, "parent",
|
||||
"1:", "classid", "1:1", "htb", NULL);
|
||||
virCommandAddArgList(cmd, "rate", average, NULL);
|
||||
|
||||
if (peak)
|
||||
virCommandAddArgList(cmd, "ceil", peak, NULL);
|
||||
if (burst)
|
||||
virCommandAddArgList(cmd, "burst", burst, NULL);
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0)
|
||||
goto cleanup;
|
||||
|
||||
virCommandFree(cmd);
|
||||
cmd = virCommandNew(TC);
|
||||
virCommandAddArgList(cmd,"filter", "add", "dev", iface, "parent",
|
||||
"1:0", "protocol", "ip", "handle", "1", "fw",
|
||||
"flowid", "1", NULL);
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0)
|
||||
goto cleanup;
|
||||
|
||||
VIR_FREE(average);
|
||||
VIR_FREE(peak);
|
||||
VIR_FREE(burst);
|
||||
}
|
||||
|
||||
if (bandwidth->out) {
|
||||
if (virAsprintf(&average, "%llukbps", bandwidth->out->average) < 0)
|
||||
goto cleanup;
|
||||
if (virAsprintf(&burst, "%llukb", bandwidth->out->burst ?
|
||||
bandwidth->out->burst : bandwidth->out->average) < 0)
|
||||
goto cleanup;
|
||||
|
||||
virCommandFree(cmd);
|
||||
cmd = virCommandNew(TC);
|
||||
virCommandAddArgList(cmd, "qdisc", "add", "dev", iface,
|
||||
"ingress", NULL);
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0)
|
||||
goto cleanup;
|
||||
|
||||
virCommandFree(cmd);
|
||||
cmd = virCommandNew(TC);
|
||||
virCommandAddArgList(cmd, "filter", "add", "dev", iface, "parent",
|
||||
"ffff:", "protocol", "ip", "u32", "match", "ip",
|
||||
"src", "0.0.0.0/0", "police", "rate", average,
|
||||
"burst", burst, "mtu", burst, "drop", "flowid",
|
||||
":1", NULL);
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virCommandFree(cmd);
|
||||
VIR_FREE(average);
|
||||
VIR_FREE(peak);
|
||||
VIR_FREE(burst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* virBandwidthDisable:
|
||||
* @iface: on which interface
|
||||
* @may_fail: should be unsuccessful disable considered fatal?
|
||||
*
|
||||
* This function tries to disable QoS on specified interface
|
||||
* by deleting root and ingress qdisc. However, this may fail
|
||||
* if we try to remove the default one.
|
||||
*
|
||||
* Return 0 on success, -1 otherwise.
|
||||
*/
|
||||
int
|
||||
virBandwidthDisable(const char *iface,
|
||||
bool may_fail)
|
||||
{
|
||||
int ret = -1;
|
||||
int status;
|
||||
virCommandPtr cmd = NULL;
|
||||
|
||||
if (!iface)
|
||||
return -1;
|
||||
|
||||
cmd = virCommandNew(TC);
|
||||
virCommandAddArgList(cmd, "qdisc", "del", "dev", iface, "root", NULL);
|
||||
|
||||
if ((virCommandRun(cmd, &status) < 0) ||
|
||||
(!may_fail && status))
|
||||
goto cleanup;
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
cmd = virCommandNew(TC);
|
||||
virCommandAddArgList(cmd, "qdisc", "del", "dev", iface, "ingress", NULL);
|
||||
|
||||
if ((virCommandRun(cmd, &status) < 0) ||
|
||||
(!may_fail && status))
|
||||
goto cleanup;
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virCommandFree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
@ -155,4 +155,7 @@ void virBandwidthDefFree(virBandwidthPtr def);
|
||||
int virBandwidthDefFormat(virBufferPtr buf,
|
||||
virBandwidthPtr def,
|
||||
const char *indent);
|
||||
|
||||
int virBandwidthEnable(virBandwidthPtr bandwidth, const char *iface);
|
||||
int virBandwidthDisable(const char *iface, bool may_fail);
|
||||
#endif /* __VIR_NETWORK_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user