/*
* Copyright (C) 2009-2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authors:
* Michal Privoznik
* Daniel P. Berrange
*/
#include
#include "virnetdevbandwidth.h"
#include "command.h"
#include "memory.h"
#include "virterror_internal.h"
#define VIR_FROM_THIS VIR_FROM_NONE
void
virNetDevBandwidthFree(virNetDevBandwidthPtr def)
{
if (!def)
return;
VIR_FREE(def->in);
VIR_FREE(def->out);
VIR_FREE(def);
}
/**
* virNetDevBandwidthSet:
* @ifname: on which interface
* @bandwidth: rates to set (may be NULL)
*
* 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
virNetDevBandwidthSet(const char *ifname,
virNetDevBandwidthPtr bandwidth)
{
int ret = -1;
virCommandPtr cmd = NULL;
char *average = NULL;
char *peak = NULL;
char *burst = NULL;
if (!bandwidth) {
/* nothing to be enabled */
ret = 0;
goto cleanup;
}
virNetDevBandwidthClear(ifname);
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", ifname, "root",
"handle", "1:", "htb", "default", "1", NULL);
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
virCommandFree(cmd);
cmd = virCommandNew(TC);
virCommandAddArgList(cmd,"class", "add", "dev", ifname, "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", ifname, "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", ifname,
"ingress", NULL);
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
virCommandFree(cmd);
cmd = virCommandNew(TC);
virCommandAddArgList(cmd, "filter", "add", "dev", ifname, "parent",
"ffff:", "protocol", "ip", "u32", "match", "ip",
"src", "0.0.0.0/0", "police", "rate", average,
"burst", burst, "mtu", "64kb", "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;
}
/**
* virNetDevBandwidthClear:
* @ifname: on which interface
*
* 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
virNetDevBandwidthClear(const char *ifname)
{
int ret = 0;
int dummy; /* for ignoring the exit status */
virCommandPtr cmd = NULL;
cmd = virCommandNew(TC);
virCommandAddArgList(cmd, "qdisc", "del", "dev", ifname, "root", NULL);
if (virCommandRun(cmd, &dummy) < 0)
ret = -1;
virCommandFree(cmd);
cmd = virCommandNew(TC);
virCommandAddArgList(cmd, "qdisc", "del", "dev", ifname, "ingress", NULL);
if (virCommandRun(cmd, &dummy) < 0)
ret = -1;
virCommandFree(cmd);
return ret;
}
/*
* virNetDevBandwidthCopy:
* @dest: destination
* @src: source (may be NULL)
*
* Returns -1 on OOM error (which gets reported),
* 0 otherwise.
*/
int
virNetDevBandwidthCopy(virNetDevBandwidthPtr *dest,
const virNetDevBandwidthPtr src)
{
int ret = -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) {
virNetDevBandwidthFree(*dest);
*dest = NULL;
}
return ret;
}
bool
virNetDevBandwidthEqual(virNetDevBandwidthPtr a,
virNetDevBandwidthPtr b)
{
if (!a && !b)
return true;
if (!a || !b)
return false;
/* in */
if (a->in->average != b->in->average ||
a->in->peak != b->in->peak ||
a->in->burst != b->in->burst)
return false;
/*out*/
if (a->out->average != b->out->average ||
a->out->peak != b->out->peak ||
a->out->burst != b->out->burst)
return false;
return true;
}