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:
Michal Privoznik 2011-07-22 16:07:27 +02:00 committed by Daniel Veillard
parent aaa98b08ff
commit 90074ecfa7
9 changed files with 212 additions and 4 deletions

View File

@ -170,6 +170,8 @@ AC_PATH_PROG([RADVD], [radvd], [radvd],
[/sbin:/usr/sbin:/usr/local/sbin:$PATH]) [/sbin:/usr/sbin:/usr/local/sbin:$PATH])
AC_PATH_PROG([BRCTL], [brctl], [brctl], AC_PATH_PROG([BRCTL], [brctl], [brctl],
[/sbin:/usr/sbin:/usr/local/sbin:$PATH]) [/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], [], AC_PATH_PROG([UDEVADM], [udevadm], [],
[/sbin:/usr/sbin:/usr/local/sbin:$PATH]) [/sbin:/usr/sbin:/usr/local/sbin:$PATH])
AC_PATH_PROG([UDEVSETTLE], [udevsettle], [], AC_PATH_PROG([UDEVSETTLE], [udevsettle], [],
@ -183,6 +185,8 @@ AC_DEFINE_UNQUOTED([RADVD],["$RADVD"],
[Location or name of the radvd program]) [Location or name of the radvd program])
AC_DEFINE_UNQUOTED([BRCTL],["$BRCTL"], AC_DEFINE_UNQUOTED([BRCTL],["$BRCTL"],
[Location or name of the brctl program (see bridge-utils)]) [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 if test -n "$UDEVADM"; then
AC_DEFINE_UNQUOTED([UDEVADM],["$UDEVADM"], AC_DEFINE_UNQUOTED([UDEVADM],["$UDEVADM"],
[Location or name of the udevadm program]) [Location or name of the udevadm program])

View File

@ -250,7 +250,7 @@ Requires: %{name}-client = %{version}-%{release}
Requires: bridge-utils Requires: bridge-utils
# for modprobe of pci devices # for modprobe of pci devices
Requires: module-init-tools Requires: module-init-tools
# for /sbin/ip # for /sbin/ip & /sbin/tc
Requires: iproute Requires: iproute
%endif %endif
%if %{with_network} %if %{with_network}

View File

@ -713,6 +713,8 @@ nlComm;
virBandwidthDefFormat; virBandwidthDefFormat;
virBandwidthDefFree; virBandwidthDefFree;
virBandwidthDefParseNode; virBandwidthDefParseNode;
virBandwidthDisable;
virBandwidthEnable;
virSocketAddrBroadcast; virSocketAddrBroadcast;
virSocketAddrBroadcastByPrefix; virSocketAddrBroadcastByPrefix;
virSocketAddrIsNetmask; virSocketAddrIsNetmask;

View File

@ -1822,10 +1822,23 @@ networkStartNetworkVirtual(struct network_driver *driver,
if (v6present && networkStartRadvd(network) < 0) if (v6present && networkStartRadvd(network) < 0)
goto err4; 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); VIR_FREE(macTapIfName);
return 0; return 0;
err5:
if (virBandwidthDisable(network->def->bridge, true) < 0) {
VIR_WARN("Failed to disable QoS on %s",
network->def->bridge);
}
err4: err4:
if (!save_err) if (!save_err)
save_err = virSaveLastError(); save_err = virSaveLastError();
@ -1883,6 +1896,11 @@ static int networkShutdownNetworkVirtual(struct network_driver *driver,
int err; int err;
char ebuf[1024]; 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) { if (network->radvdPid > 0) {
char *radvdpidbase; char *radvdpidbase;

View File

@ -132,7 +132,7 @@ qemuPhysIfaceConnect(virDomainDefPtr def,
vnet_hdr, def->uuid, vnet_hdr, def->uuid,
virDomainNetGetActualDirectVirtPortProfile(net), virDomainNetGetActualDirectVirtPortProfile(net),
&res_ifname, &res_ifname,
vmop, driver->stateDir); vmop, driver->stateDir, net->bandwidth);
if (rc >= 0) { if (rc >= 0) {
virDomainAuditNetDevice(def, net, res_ifname, true); virDomainAuditNetDevice(def, net, res_ifname, true);
VIR_FREE(net->ifname); 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 (tapfd >= 0) {
if ((net->filter) && (net->ifname)) { if ((net->filter) && (net->ifname)) {
err = virDomainConfNWFilterInstantiate(conn, net); err = virDomainConfNWFilterInstantiate(conn, net);

View File

@ -267,7 +267,8 @@ openMacvtapTap(const char *tgifname,
virVirtualPortProfileParamsPtr virtPortProfile, virVirtualPortProfileParamsPtr virtPortProfile,
char **res_ifname, char **res_ifname,
enum virVMOperationType vmOp, enum virVMOperationType vmOp,
char *stateDir) char *stateDir,
virBandwidthPtr bandwidth)
{ {
const char *type = "macvtap"; const char *type = "macvtap";
int c, rc; int c, rc;
@ -361,6 +362,15 @@ create_name:
} else } else
goto disassociate_exit; 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; return rc;
disassociate_exit: disassociate_exit:

View File

@ -62,7 +62,8 @@ int openMacvtapTap(const char *ifname,
virVirtualPortProfileParamsPtr virtPortProfile, virVirtualPortProfileParamsPtr virtPortProfile,
char **res_ifname, char **res_ifname,
enum virVMOperationType vmop, enum virVMOperationType vmop,
char *stateDir); char *stateDir,
virBandwidthPtr bandwidth);
void delMacvtap(const char *ifname, void delMacvtap(const char *ifname,
const unsigned char *macaddress, const unsigned char *macaddress,

View File

@ -16,6 +16,7 @@
#include "network.h" #include "network.h"
#include "util.h" #include "util.h"
#include "virterror_internal.h" #include "virterror_internal.h"
#include "command.h"
#define VIR_FROM_THIS VIR_FROM_NONE #define VIR_FROM_THIS VIR_FROM_NONE
#define virSocketError(code, ...) \ #define virSocketError(code, ...) \
@ -1102,3 +1103,163 @@ virBandwidthDefFormat(virBufferPtr buf,
cleanup: cleanup:
return ret; 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;
}

View File

@ -155,4 +155,7 @@ void virBandwidthDefFree(virBandwidthPtr def);
int virBandwidthDefFormat(virBufferPtr buf, int virBandwidthDefFormat(virBufferPtr buf,
virBandwidthPtr def, virBandwidthPtr def,
const char *indent); const char *indent);
int virBandwidthEnable(virBandwidthPtr bandwidth, const char *iface);
int virBandwidthDisable(const char *iface, bool may_fail);
#endif /* __VIR_NETWORK_H__ */ #endif /* __VIR_NETWORK_H__ */