xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: "Mathieu Gagné" <mgagne@iweb.com>
To: xen-devel@lists.xensource.com
Cc: ian.jackson@eu.citrix.com, stefano.stabellini@eu.citrix.com
Subject: [PATCH 3 of 4 v3] xl: add support for vif rate limiting
Date: Mon, 16 Apr 2012 23:51:25 -0400	[thread overview]
Message-ID: <4130bb154f3436a9adf4.1334634685@mgagne.users.dev.iweb.com> (raw)
In-Reply-To: <patchbomb.1334634682@mgagne.users.dev.iweb.com>

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 Gagné <mgagne@iweb.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>

diff --git a/docs/misc/xl-network-configuration.markdown b/docs/misc/xl-network-configuration.markdown
--- a/docs/misc/xl-network-configuration.markdown
+++ b/docs/misc/xl-network-configuration.markdown
@@ -122,5 +122,34 @@ Specifies the backend domain which 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
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -61,7 +61,7 @@ LIBXL_OBJS += _libxl_types.o libxl_flask
 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
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1854,6 +1854,13 @@ int libxl_device_nic_add(libxl_ctx *ctx,
         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
--- 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
--- 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
--- /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
--- a/tools/libxl/libxlutil.h
+++ b/tools/libxl/libxlutil.h
@@ -94,6 +94,13 @@ int xlu_disk_parse(XLU_Config *cfg, int 
 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
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -403,6 +403,19 @@ static void parse_disk_config(XLU_Config
     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
                         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 **
 {
     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 **
         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 **
         } 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 **
         return 1;
     }
     libxl_device_nic_dispose(&nic);
+    xlu_cfg_destroy(config);
     return 0;
 }
 
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

  parent reply	other threads:[~2012-04-17  3:51 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-17  3:51 [PATCH 0 of 4 v3] xl: add support for vif rate limiting Mathieu Gagné
2012-04-17  3:51 ` [PATCH 1 of 4 v3] xl: cleanup indentation Mathieu Gagné
2012-04-17  3:51 ` [PATCH 2 of 4 v3] xl: xl network-attach -N (dry run) option Mathieu Gagné
2012-04-17  3:51 ` Mathieu Gagné [this message]
2012-04-17  3:51 ` [PATCH 4 of 4 v3] xl: add "check-xl-vif-parse" test script Mathieu Gagné
2012-04-24 16:14 ` [PATCH 0 of 4 v3] xl: add support for vif rate limiting Ian Jackson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4130bb154f3436a9adf4.1334634685@mgagne.users.dev.iweb.com \
    --to=mgagne@iweb.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=stefano.stabellini@eu.citrix.com \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).