diff options
author | Mathieu Gagne <mgagne@iweb.com> | 2012-04-24 17:09:22 +0100 |
---|---|---|
committer | Mathieu Gagne <mgagne@iweb.com> | 2012-04-24 17:09:22 +0100 |
commit | deaed905dac4f87a08d35c0358fcf7657d817ad5 (patch) | |
tree | 0df710361097354badd55ea1e9e650475e5ea390 /tools/libxl/libxlu_vif.c | |
parent | 9684ac597a610155a19a7a33038cb874b4d8de23 (diff) | |
download | xen-deaed905dac4f87a08d35c0358fcf7657d817ad5.tar.gz xen-deaed905dac4f87a08d35c0358fcf7657d817ad5.tar.bz2 xen-deaed905dac4f87a08d35c0358fcf7657d817ad5.zip |
xl: add support for vif rate limiting
The `rate` keyword specifies the rate at which the outgoing traffic
will be limited to. The default if this keyword is not specified
is unlimited.
The `rate` keyword supports an optional replenishment interval
parameter for specifying the granularity of credit replenishment.
It determines the frequency at which the vif transmission credit
is replenished. The default interval is 50ms.
For example:
'rate=10Mb/s'
'rate=250KB/s'
'rate=1MB/s@20ms'
Signed-off-by: Mathieu Gagne <mgagne@iweb.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
Diffstat (limited to 'tools/libxl/libxlu_vif.c')
-rw-r--r-- | tools/libxl/libxlu_vif.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/tools/libxl/libxlu_vif.c b/tools/libxl/libxlu_vif.c new file mode 100644 index 0000000000..e3f78a3f8d --- /dev/null +++ b/tools/libxl/libxlu_vif.c @@ -0,0 +1,141 @@ +#include "libxl_osdeps.h" /* must come before any other headers */ +#include "libxlu_internal.h" + +static const char *vif_bytes_per_sec_re = "^[0-9]+[GMK]?[Bb]/s$"; +static const char *vif_internal_usec_re = "^[0-9]+[mu]?s?$"; + +static void xlu__vif_err(XLU_Config *cfg, const char *msg, const char *rate) { + fprintf(cfg->report, + "%s: config parsing error in vif: %s in `%s'\n", + cfg->filename, msg, rate); +} + +static int vif_parse_rate_bytes_per_sec(XLU_Config *cfg, const char *bytes, + uint64_t *bytes_per_sec) +{ + regex_t rec; + uint64_t tmp = 0; + const char *p; + int rc = 0; + + regcomp(&rec, vif_bytes_per_sec_re, REG_EXTENDED|REG_NOSUB); + if (regexec(&rec, bytes, 0, NULL, 0)) { + xlu__vif_err(cfg, "invalid rate", bytes); + rc = EINVAL; + goto out; + } + + p = bytes; + tmp = strtoull(p, (char**)&p, 0); + if (tmp == 0 || tmp > UINT32_MAX || errno == ERANGE) { + xlu__vif_err(cfg, "rate overflow", bytes); + rc = EOVERFLOW; + goto out; + } + + if (*p == 'G') + tmp *= 1000 * 1000 * 1000; + else if (*p == 'M') + tmp *= 1000 * 1000; + else if (*p == 'K') + tmp *= 1000; + if (*p == 'b' || *(p+1) == 'b') + tmp /= 8; + + *bytes_per_sec = tmp; + +out: + regfree(&rec); + return rc; +} + +static int vif_parse_rate_interval_usecs(XLU_Config *cfg, const char *interval, + uint32_t *interval_usecs) +{ + regex_t rec; + uint64_t tmp = 0; + const char *p; + int rc = 0; + + regcomp(&rec, vif_internal_usec_re, REG_EXTENDED|REG_NOSUB); + if (regexec(&rec, interval, 0, NULL, 0)) { + xlu__vif_err(cfg, "invalid replenishment interval", interval); + rc = EINVAL; + goto out; + } + + p = interval; + tmp = strtoull(p, (char**)&p, 0); + if (tmp == 0 || tmp > UINT32_MAX || errno == ERANGE) { + xlu__vif_err(cfg, "replenishment interval overflow", interval); + rc = EOVERFLOW; + goto out; + } + + if (*p == 's' || *p == '\0') + tmp *= 1000 * 1000; + else if (*p == 'm') + tmp *= 1000; + + if (tmp > UINT32_MAX) { + xlu__vif_err(cfg, "replenishment interval overflow", interval); + rc = EOVERFLOW; + goto out; + } + + *interval_usecs = (uint32_t) tmp; + +out: + regfree(&rec); + return rc; +} + +int xlu_vif_parse_rate(XLU_Config *cfg, const char *rate, libxl_device_nic *nic) +{ + uint64_t bytes_per_sec = 0; + uint64_t bytes_per_interval = 0; + uint32_t interval_usecs = 50000UL; /* Default to 50ms */ + char *ratetok, *tmprate; + int rc = 0; + + tmprate = strdup(rate); + if (!strcmp(tmprate,"")) { + xlu__vif_err(cfg, "no rate specified", rate); + rc = EINVAL; + goto out; + } + + ratetok = strtok(tmprate, "@"); + rc = vif_parse_rate_bytes_per_sec(cfg, ratetok, &bytes_per_sec); + if (rc) goto out; + + ratetok = strtok(NULL, "@"); + if (ratetok != NULL) { + rc = vif_parse_rate_interval_usecs(cfg, ratetok, &interval_usecs); + if (rc) goto out; + } + + if (interval_usecs != 0 && (bytes_per_sec > (UINT64_MAX / interval_usecs))) { + xlu__vif_err(cfg, "rate overflow", rate); + rc = EOVERFLOW; + goto out; + } + + bytes_per_interval = + (((uint64_t) bytes_per_sec * (uint64_t) interval_usecs) / 1000000UL); + + nic->rate_interval_usecs = interval_usecs; + nic->rate_bytes_per_interval = bytes_per_interval; + +out: + free(tmprate); + return rc; +} + +/* + * Local variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ |