diff options
-rw-r--r-- | docs/misc/xl-network-configuration.markdown | 29 | ||||
-rw-r--r-- | tools/libxl/Makefile | 2 | ||||
-rw-r--r-- | tools/libxl/libxl.c | 7 | ||||
-rw-r--r-- | tools/libxl/libxl_types.idl | 2 | ||||
-rw-r--r-- | tools/libxl/libxlu_internal.h | 2 | ||||
-rw-r--r-- | tools/libxl/libxlu_vif.c | 141 | ||||
-rw-r--r-- | tools/libxl/libxlutil.h | 7 | ||||
-rw-r--r-- | tools/libxl/xl_cmdimpl.c | 25 |
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; } |