aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxl
diff options
context:
space:
mode:
authorMathieu Gagne <mgagne@iweb.com>2012-04-24 17:09:22 +0100
committerMathieu Gagne <mgagne@iweb.com>2012-04-24 17:09:22 +0100
commitdeaed905dac4f87a08d35c0358fcf7657d817ad5 (patch)
tree0df710361097354badd55ea1e9e650475e5ea390 /tools/libxl
parent9684ac597a610155a19a7a33038cb874b4d8de23 (diff)
downloadxen-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')
-rw-r--r--tools/libxl/Makefile2
-rw-r--r--tools/libxl/libxl.c7
-rw-r--r--tools/libxl/libxl_types.idl2
-rw-r--r--tools/libxl/libxlu_internal.h2
-rw-r--r--tools/libxl/libxlu_vif.c141
-rw-r--r--tools/libxl/libxlutil.h7
-rw-r--r--tools/libxl/xl_cmdimpl.c25
7 files changed, 184 insertions, 2 deletions
diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index e5ea867678..2f63a671de 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -61,7 +61,7 @@ $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_lib
AUTOINCS= libxlu_cfg_y.h libxlu_cfg_l.h _libxl_list.h
AUTOSRCS= libxlu_cfg_y.c libxlu_cfg_l.c
LIBXLU_OBJS = libxlu_cfg_y.o libxlu_cfg_l.o libxlu_cfg.o \
- libxlu_disk_l.o libxlu_disk.o libxlu_pci.o
+ libxlu_disk_l.o libxlu_disk.o libxlu_vif.o libxlu_pci.o
$(LIBXLU_OBJS): CFLAGS += $(CFLAGS_libxenctrl) # For xentoollog.h
CLIENTS = xl testidl
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 60dbfdc47d..5617060e22 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1854,6 +1854,13 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
flexarray_append(back, libxl__strdup(gc, nic->ip));
}
+ if (nic->rate_interval_usecs > 0) {
+ flexarray_append(back, "rate");
+ flexarray_append(back, libxl__sprintf(gc, "%"PRIu64",%"PRIu32"",
+ nic->rate_bytes_per_interval,
+ nic->rate_interval_usecs));
+ }
+
flexarray_append(back, "bridge");
flexarray_append(back, libxl__strdup(gc, nic->bridge));
flexarray_append(back, "handle");
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 5cf9708c4c..068f3783cd 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -343,6 +343,8 @@ libxl_device_nic = Struct("device_nic", [
("ifname", string),
("script", string),
("nictype", libxl_nic_type),
+ ("rate_bytes_per_interval", uint64),
+ ("rate_interval_usecs", uint32),
])
libxl_device_pci = Struct("device_pci", [
diff --git a/tools/libxl/libxlu_internal.h b/tools/libxl/libxlu_internal.h
index 1653c162b5..c7026854bf 100644
--- a/tools/libxl/libxlu_internal.h
+++ b/tools/libxl/libxlu_internal.h
@@ -17,9 +17,11 @@
#define LIBXLU_INTERNAL_H
#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
+#include <regex.h>
#define XLU_ConfigList XLU_ConfigSetting
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:
+ */
diff --git a/tools/libxl/libxlutil.h b/tools/libxl/libxlutil.h
index 1b05f4c343..0333e55ba7 100644
--- a/tools/libxl/libxlutil.h
+++ b/tools/libxl/libxlutil.h
@@ -94,6 +94,13 @@ int xlu_disk_parse(XLU_Config *cfg, int nspecs, const char *const *specs,
int xlu_pci_parse_bdf(XLU_Config *cfg, libxl_device_pci *pcidev, const char *str);
+/*
+ * Vif rate parsing.
+ */
+
+int xlu_vif_parse_rate(XLU_Config *cfg, const char *rate,
+ libxl_device_nic *nic);
+
#endif /* LIBXLUTIL_H */
/*
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 5703512d24..b9e7688cd9 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -403,6 +403,19 @@ static void parse_disk_config(XLU_Config **config, const char *spec,
parse_disk_config_multistring(config, 1, &spec, disk);
}
+static void parse_vif_rate(XLU_Config **config, const char *rate,
+ libxl_device_nic *nic)
+{
+ int e;
+
+ e = xlu_vif_parse_rate(*config, rate, nic);
+ if (e == EINVAL || e == EOVERFLOW) exit(-1);
+ if (e) {
+ fprintf(stderr,"xlu_vif_parse_rate failed: %s\n",strerror(errno));
+ exit(-1);
+ }
+}
+
static void split_string_into_string_list(const char *str,
const char *delim,
libxl_string_list *psl)
@@ -906,7 +919,7 @@ static void parse_config_data(const char *configfile_filename_report,
nic->backend_domid = 0;
}
} else if (!strcmp(p, "rate")) {
- fprintf(stderr, "the rate parameter for vifs is currently not supported\n");
+ parse_vif_rate(&config, (p2 + 1), nic);
} else if (!strcmp(p, "accel")) {
fprintf(stderr, "the accel parameter for vifs is currently not supported\n");
}
@@ -4855,6 +4868,7 @@ int main_networkattach(int argc, char **argv)
{
int opt;
libxl_device_nic nic;
+ XLU_Config *config = 0;
char *endptr, *oparg;
const char *tok;
int i;
@@ -4872,6 +4886,13 @@ int main_networkattach(int argc, char **argv)
fprintf(stderr, "%s is an invalid domain identifier\n", argv[optind]);
return 1;
}
+
+ config= xlu_cfg_init(stderr, "command line");
+ if (!config) {
+ fprintf(stderr, "Failed to allocate for configuration\n");
+ return 1;
+ }
+
libxl_device_nic_init(&nic);
for (argv += optind+1, argc -= optind+1; argc > 0; ++argv, --argc) {
if (MATCH_OPTION("type", *argv, oparg)) {
@@ -4910,6 +4931,7 @@ int main_networkattach(int argc, char **argv)
} else if (MATCH_OPTION("model", *argv, oparg)) {
replace_string(&nic.model, oparg);
} else if (MATCH_OPTION("rate", *argv, oparg)) {
+ parse_vif_rate(&config, oparg, &nic);
} else if (MATCH_OPTION("accel", *argv, oparg)) {
} else {
fprintf(stderr, "unrecognized argument `%s'\n", *argv);
@@ -4931,6 +4953,7 @@ int main_networkattach(int argc, char **argv)
return 1;
}
libxl_device_nic_dispose(&nic);
+ xlu_cfg_destroy(config);
return 0;
}