]> xenbits.xensource.com Git - xen.git/commitdiff
xl: add support for vif rate limiting
authorMathieu Gagne <mgagne@iweb.com>
Tue, 24 Apr 2012 16:09:22 +0000 (17:09 +0100)
committerMathieu Gagne <mgagne@iweb.com>
Tue, 24 Apr 2012 16:09:22 +0000 (17:09 +0100)
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>
docs/misc/xl-network-configuration.markdown
tools/libxl/Makefile
tools/libxl/libxl.c
tools/libxl/libxl_types.idl
tools/libxl/libxlu_internal.h
tools/libxl/libxlu_vif.c [new file with mode: 0644]
tools/libxl/libxlutil.h
tools/libxl/xl_cmdimpl.c

index bafcd6d6de5e4c50f52a0a0ab6c1a12589d51050..e2a5bc60c53f7f20a8f2dcc4377fd07c90c4a2e3 100644 (file)
@@ -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
index e5ea86767870f335ef6766f8ed7aeeafed0214e0..2f63a671de154f914b9f8606f729960fa6fa4395 100644 (file)
@@ -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
index 60dbfdc47d78d0d56a9a4d2a5d660aaa1bd74972..5617060e2237715b54abe08377643bd4ba1ad784 100644 (file)
@@ -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");
index 5cf9708c4c3d8e2761f78fc5b81c5b1fa5fbb92c..068f3783cd7509276a14c473cbd7aad2676cc33a 100644 (file)
@@ -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", [
index 1653c162b5c94edac2df1079d0847b96da5839ba..c7026854bf07d29e9053aadc8c491fd40518d2c1 100644 (file)
 #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 (file)
index 0000000..e3f78a3
--- /dev/null
@@ -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:
+ */
index 1b05f4c343095e244b1fcb3b4fffe3eac85ed2d4..0333e55ba71f736a5287dca7bb9fd3045dbc8e85 100644 (file)
@@ -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 */
 
 /*
index 5703512d24d43ff2832a4ee5ff8c5710b5bca885..b9e7688cd95278f476fd9bd2b3c6fa215f19ba1a 100644 (file)
@@ -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;
 }