mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-07 17:28:15 +00:00
bandwidth: Create (un)plug functions
These set bridge part of QoS when bringing domain's interface up. Long story short, if there's a 'floor' set, a new QoS class is created. ClassID MUST be unique within the bridge and should be kept for unplug phase.
This commit is contained in:
parent
67159f1c60
commit
7cdbacb472
@ -160,6 +160,7 @@ src/util/virinitctl.c
|
|||||||
src/util/virkeyfile.c
|
src/util/virkeyfile.c
|
||||||
src/util/virlockspace.c
|
src/util/virlockspace.c
|
||||||
src/util/virnetdev.c
|
src/util/virnetdev.c
|
||||||
|
src/util/virnetdevbandwidth.c
|
||||||
src/util/virnetdevbridge.c
|
src/util/virnetdevbridge.c
|
||||||
src/util/virnetdevmacvlan.c
|
src/util/virnetdevmacvlan.c
|
||||||
src/util/virnetdevopenvswitch.c
|
src/util/virnetdevopenvswitch.c
|
||||||
|
@ -352,3 +352,185 @@ virNetDevBandwidthEqual(virNetDevBandwidthPtr a,
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* virNetDevBandwidthPlug:
|
||||||
|
* @brname: name of the bridge
|
||||||
|
* @net_bandwidth: QoS settings on @brname
|
||||||
|
* @ifmac: MAC of interface
|
||||||
|
* @bandwidth: QoS settings for interface
|
||||||
|
* @id: unique ID (MUST be greater than 2)
|
||||||
|
*
|
||||||
|
* Set bridge part of interface QoS settings, e.g. guaranteed
|
||||||
|
* bandwidth. @id is an unique ID (among @brname) from which
|
||||||
|
* other identifiers for class, qdisc and filter are derived.
|
||||||
|
* However, two classes were already set up (by
|
||||||
|
* virNetDevBandwidthSet). That's why this @id MUST be greater
|
||||||
|
* than 2. You may want to keep passed @id, as it is used later
|
||||||
|
* by virNetDevBandwidthUnplug.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 if QoS set successfully
|
||||||
|
* -1 otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
virNetDevBandwidthPlug(const char *brname,
|
||||||
|
virNetDevBandwidthPtr net_bandwidth,
|
||||||
|
const virMacAddrPtr ifmac_ptr,
|
||||||
|
virNetDevBandwidthPtr bandwidth,
|
||||||
|
unsigned int id)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
virCommandPtr cmd = NULL;
|
||||||
|
char *class_id = NULL;
|
||||||
|
char *qdisc_id = NULL;
|
||||||
|
char *filter_id = NULL;
|
||||||
|
char *floor = NULL;
|
||||||
|
char *ceil = NULL;
|
||||||
|
unsigned char ifmac[VIR_MAC_BUFLEN];
|
||||||
|
char ifmacStr[VIR_MAC_STRING_BUFLEN];
|
||||||
|
char *mac[2] = {NULL, NULL};
|
||||||
|
|
||||||
|
if (id <= 2) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid class ID %d"), id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
virMacAddrGetRaw(ifmac_ptr, ifmac);
|
||||||
|
virMacAddrFormat(ifmac_ptr, ifmacStr);
|
||||||
|
|
||||||
|
if (!net_bandwidth || !net_bandwidth->in) {
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
|
_("Bridge '%s' has no QoS set, therefore "
|
||||||
|
"unable to set 'floor' on '%s'"),
|
||||||
|
brname, ifmacStr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virAsprintf(&class_id, "1:%x", id) < 0 ||
|
||||||
|
virAsprintf(&qdisc_id, "%x:", id) < 0 ||
|
||||||
|
virAsprintf(&filter_id, "%u", id) < 0 ||
|
||||||
|
virAsprintf(&mac[0], "0x%02x%02x%02x%02x", ifmac[2],
|
||||||
|
ifmac[3], ifmac[4], ifmac[5]) < 0 ||
|
||||||
|
virAsprintf(&mac[1], "0x%02x%02x", ifmac[0], ifmac[1]) < 0 ||
|
||||||
|
virAsprintf(&floor, "%llukbps", bandwidth->in->floor) < 0 ||
|
||||||
|
virAsprintf(&ceil, "%llukbps", net_bandwidth->in->peak ?
|
||||||
|
net_bandwidth->in->peak :
|
||||||
|
net_bandwidth->in->average) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = virCommandNew(TC);
|
||||||
|
virCommandAddArgList(cmd, "class", "add", "dev", brname, "parent", "1:1",
|
||||||
|
"classid", class_id, "htb", "rate", floor,
|
||||||
|
"ceil", ceil, NULL);
|
||||||
|
|
||||||
|
if (virCommandRun(cmd, NULL) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
virCommandFree(cmd);
|
||||||
|
cmd = virCommandNew(TC);
|
||||||
|
virCommandAddArgList(cmd, "qdisc", "add", "dev", brname, "parent",
|
||||||
|
class_id, "handle", qdisc_id, "sfq", "perturb",
|
||||||
|
"10", NULL);
|
||||||
|
|
||||||
|
if (virCommandRun(cmd, NULL) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
virCommandFree(cmd);
|
||||||
|
cmd = virCommandNew(TC);
|
||||||
|
/* Okay, this not nice. But since libvirt does not know anything about
|
||||||
|
* interface IP address(es), and tc fw filter simply refuse to use ebtables
|
||||||
|
* marks, we need to use u32 selector to match MAC address.
|
||||||
|
* If libvirt will ever know something, remove this FIXME
|
||||||
|
*/
|
||||||
|
virCommandAddArgList(cmd, "filter", "add", "dev", brname, "protocol", "ip",
|
||||||
|
"prio", filter_id, "u32",
|
||||||
|
"match", "u16", "0x0800", "0xffff", "at", "-2",
|
||||||
|
"match", "u32", mac[0], "0xffffffff", "at", "-12",
|
||||||
|
"match", "u16", mac[1], "0xffff", "at", "-14",
|
||||||
|
"flowid", class_id, NULL);
|
||||||
|
|
||||||
|
if (virCommandRun(cmd, NULL) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(mac[1]);
|
||||||
|
VIR_FREE(mac[0]);
|
||||||
|
VIR_FREE(ceil);
|
||||||
|
VIR_FREE(floor);
|
||||||
|
VIR_FREE(filter_id);
|
||||||
|
VIR_FREE(qdisc_id);
|
||||||
|
VIR_FREE(class_id);
|
||||||
|
virCommandFree(cmd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* virNetDevBandwidthUnplug:
|
||||||
|
* @brname: from which bridge are we unplugging
|
||||||
|
* @id: unique identifier (MUST be greater than 2)
|
||||||
|
*
|
||||||
|
* Remove QoS settings from bridge.
|
||||||
|
*
|
||||||
|
* Returns 0 on success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
virNetDevBandwidthUnplug(const char *brname,
|
||||||
|
unsigned int id)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
int cmd_ret = 0;
|
||||||
|
virCommandPtr cmd = NULL;
|
||||||
|
char *class_id = NULL;
|
||||||
|
char *qdisc_id = NULL;
|
||||||
|
char *filter_id = NULL;
|
||||||
|
|
||||||
|
if (id <= 2) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid class ID %d"), id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virAsprintf(&class_id, "1:%x", id) < 0 ||
|
||||||
|
virAsprintf(&qdisc_id, "%x:", id) < 0 ||
|
||||||
|
virAsprintf(&filter_id, "%u", id) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = virCommandNew(TC);
|
||||||
|
virCommandAddArgList(cmd, "qdisc", "del", "dev", brname,
|
||||||
|
"handle", qdisc_id, NULL);
|
||||||
|
|
||||||
|
/* Don't threat tc errors as fatal, but
|
||||||
|
* try to remove as much as possible */
|
||||||
|
if (virCommandRun(cmd, &cmd_ret) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
virCommandFree(cmd);
|
||||||
|
cmd = virCommandNew(TC);
|
||||||
|
virCommandAddArgList(cmd, "filter", "del", "dev", brname,
|
||||||
|
"prio", filter_id, NULL);
|
||||||
|
|
||||||
|
if (virCommandRun(cmd, &cmd_ret) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
cmd = virCommandNew(TC);
|
||||||
|
virCommandAddArgList(cmd, "class", "del", "dev", brname,
|
||||||
|
"classid", class_id, NULL);
|
||||||
|
|
||||||
|
if (virCommandRun(cmd, &cmd_ret) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(filter_id);
|
||||||
|
VIR_FREE(qdisc_id);
|
||||||
|
VIR_FREE(class_id);
|
||||||
|
virCommandFree(cmd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
# define __VIR_NETDEV_BANDWIDTH_H__
|
# define __VIR_NETDEV_BANDWIDTH_H__
|
||||||
|
|
||||||
# include "internal.h"
|
# include "internal.h"
|
||||||
|
# include "virmacaddr.h"
|
||||||
|
|
||||||
typedef struct _virNetDevBandwidthRate virNetDevBandwidthRate;
|
typedef struct _virNetDevBandwidthRate virNetDevBandwidthRate;
|
||||||
typedef virNetDevBandwidthRate *virNetDevBandwidthRatePtr;
|
typedef virNetDevBandwidthRate *virNetDevBandwidthRatePtr;
|
||||||
@ -53,4 +54,17 @@ int virNetDevBandwidthCopy(virNetDevBandwidthPtr *dest, const virNetDevBandwidth
|
|||||||
|
|
||||||
bool virNetDevBandwidthEqual(virNetDevBandwidthPtr a, virNetDevBandwidthPtr b);
|
bool virNetDevBandwidthEqual(virNetDevBandwidthPtr a, virNetDevBandwidthPtr b);
|
||||||
|
|
||||||
|
int virNetDevBandwidthPlug(const char *brname,
|
||||||
|
virNetDevBandwidthPtr net_bandwidth,
|
||||||
|
const virMacAddrPtr ifmac_ptr,
|
||||||
|
virNetDevBandwidthPtr bandwidth,
|
||||||
|
unsigned int id)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
|
||||||
|
ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
|
||||||
|
ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
int virNetDevBandwidthUnplug(const char *brname,
|
||||||
|
unsigned int id)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
#endif /* __VIR_NETDEV_BANDWIDTH_H__ */
|
#endif /* __VIR_NETDEV_BANDWIDTH_H__ */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user