aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/misc/xl-network-configuration.markdown29
-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
8 files changed, 213 insertions, 2 deletions
diff --git a/docs/misc/xl-network-configuration.markdown b/docs/misc/xl-network-configuration.markdown
index bafcd6d6de..e2a5bc60c5 100644
--- a/docs/misc/xl-network-configuration.markdown
+++ b/docs/misc/xl-network-configuration.markdown
@@ -122,5 +122,34 @@ Specifies the backend domain which this device should attach to. This
defaults to domain 0. Specifying another domain requires setting up a
driver domain which is outside the scope of this document.
+### rate
+
+Specifies the rate at which the outgoing traffic will be limited to.
+The default if this keyword is not specified is unlimited.
+
+The rate may be specified as "<RATE>/s" or optionally "<RATE>/s@<INTERVAL>".
+
+ * `RATE` is in bytes and can accept suffixes:
+ * GB, MB, KB, B for bytes.
+ * Gb, Mb, Kb, b for bits.
+ * `INTERVAL` is in microseconds and can accept suffixes: ms, us, s.
+ It determines the frequency at which the vif transmission credit
+ is replenished. The default is 50ms.
+
+Vif rate limiting is credit-based. It means that for "1MB/s@20ms", the
+available credit will be equivalent of the traffic you would have done
+at "1MB/s" during 20ms. This will results in a credit of 20,000 bytes
+replenished every 20,000 us.
+
+For example:
+
+ 'rate=10Mb/s' -- meaning up to 10 megabits every second
+ 'rate=250KB/s' -- meaning up to 250 kilobytes every second
+ 'rate=1MB/s@20ms' -- meaning 20,000 bytes in every 20 millisecond period
+
+NOTE: The actual underlying limits of rate limiting are dependent
+on the underlying netback implementation.
+
+
[oui]: http://en.wikipedia.org/wiki/Organizationally_Unique_Identifier
[net]: http://wiki.xen.org/wiki/HostConfiguration/Networking
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;
}