[ovs-dev] netdev-linux: netem QoS support
diff mbox series

Message ID CALOndvsp7rgTyddJ6d9XMd5vtRM1zXxE18ziJoH4gVYWno_uZg@mail.gmail.com
State New
Headers show
Series
  • [ovs-dev] netdev-linux: netem QoS support
Related show

Commit Message

Sharon K March 14, 2019, 11:02 p.m. UTC
Signed-off-by: Sharon Krendel <thekafkaf@gmail.com>


           Linux ``No operation.''  By default, Open vSwitch manages quality of
@@ -4437,6 +4445,25 @@ ovs-vsctl add-port br0 p0 -- set Interface p0
type=patch options:peer=p1 \
       </column>
     </group>

+    <group title="Configuration for linux-netem">
+      <p>
+        The <code>linux-netem</code> QoS supports the following
key-value pairs:
+      </p>
+
+      <column name="other_config" key="latency" type='{"type": "integer"}'>
+        Adds the chosen delay to the packets outgoing to chosen network
+        interface. The latency value expressed in us.
+      </column>
+      <column name="other_config" key="limit" type='{"type": "integer"}'>
+        Maximum number of packets the qdisc may hold queued at a time.
+        The default value is 1000.
+      </column>
+      <column name="other_config" key="loss" type='{"type": "integer"}'>
+        Adds an independent loss probability to the packets outgoing from the
+        chosen network interface.
+      </column>
+    </group>
+
     <group title="Common Columns">
       The overall purpose of these columns is described under <code>Common
       Columns</code> at the beginning of this document.

Comments

0-day Robot March 14, 2019, 11:57 p.m. UTC | #1
Bleep bloop.  Greetings Sharon K, I am a robot and I have tried out your patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


git-am:
fatal: corrupt patch at line 72
Repository lacks necessary blobs to fall back on 3-way merge.
Cannot fall back to three-way merge.
Patch failed at 0001 netdev-linux: netem QoS support
The copy of the patch that failed is found in:
   /var/lib/jenkins/jobs/upstream_build_from_pw/workspace/.git/rebase-apply/patch
When you have resolved this problem, run "git am --resolved".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".


Please check this out.  If you feel there has been an error, please email aconole@bytheb.org

Thanks,
0-day Robot
Ben Pfaff March 15, 2019, 2:21 a.m. UTC | #2
On Fri, Mar 15, 2019 at 01:02:24AM +0200, Sharon K wrote:
> Signed-off-by: Sharon Krendel <thekafkaf@gmail.com>

Thanks!  I applied this to master.

Patch
diff mbox series

diff --git a/.gitignore b/.gitignore
index 60e7818c3..e28f6c9fc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,3 +77,4 @@  testsuite.tmp.orig
 /Documentation/_build
 /.venv
 /cxx-check
+.idea/
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 0d0d045f7..81dca5deb 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -24,6 +24,7 @@ 
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <inttypes.h>
+#include <math.h>
 #include <linux/filter.h>
 #include <linux/gen_stats.h>
 #include <linux/if_ether.h>
@@ -437,6 +438,7 @@  static const struct tc_ops tc_ops_hfsc;
 static const struct tc_ops tc_ops_codel;
 static const struct tc_ops tc_ops_fqcodel;
 static const struct tc_ops tc_ops_sfq;
+static const struct tc_ops tc_ops_netem;
 static const struct tc_ops tc_ops_default;
 static const struct tc_ops tc_ops_noop;
 static const struct tc_ops tc_ops_other;
@@ -447,6 +449,7 @@  static const struct tc_ops *const tcs[] = {
     &tc_ops_codel,              /* Controlled delay */
     &tc_ops_fqcodel,            /* Fair queue controlled delay */
     &tc_ops_sfq,                /* Stochastic fair queueing */
+    &tc_ops_netem,              /* Network Emulator */
     &tc_ops_noop,               /* Non operating qos type. */
     &tc_ops_default,            /* Default qdisc (see tc-pfifo_fast(8)). */
     &tc_ops_other,              /* Some other qdisc. */
@@ -456,6 +459,7 @@  static const struct tc_ops *const tcs[] = {
 static unsigned int tc_ticks_to_bytes(unsigned int rate, unsigned int ticks);
 static unsigned int tc_bytes_to_ticks(unsigned int rate, unsigned int size);
 static unsigned int tc_buffer_per_jiffy(unsigned int rate);
+static uint32_t tc_time_to_ticks(uint32_t time);

 static struct tcmsg *netdev_linux_tc_make_request(const struct netdev *,
                                                   int type,
@@ -3956,7 +3960,178 @@  static const struct tc_ops tc_ops_sfq = {
     .qdisc_get = sfq_qdisc_get,
     .qdisc_set = sfq_qdisc_set,
 };
-
+
+/* netem traffic control class. */
+
+#define NETEM_N_QUEUES 0x0000
+
+struct netem {
+    struct tc tc;
+    uint32_t latency;
+    uint32_t limit;
+    uint32_t loss;
+};
+
+static struct netem *
+netem_get__(const struct netdev *netdev_)
+{
+    struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    return CONTAINER_OF(netdev->tc, struct netem, tc);
+}
+
+static void
+netem_install__(struct netdev *netdev_, uint32_t latency, uint32_t
limit, uint32_t loss)
+{
+    struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    struct netem *netem;
+
+    netem = xmalloc(sizeof *netem);
+    tc_init(&netem->tc, &tc_ops_netem);
+    netem->latency = latency;
+    netem->limit = limit;
+    netem->loss = loss;
+
+    netdev->tc = &netem->tc;
+}
+
+static int
+netem_setup_qdisc__(struct netdev *netdev, uint32_t latency, uint32_t
limit, uint32_t loss)
+{
+    struct tc_netem_qopt opt;
+    struct ofpbuf request;
+    struct tcmsg *tcmsg;
+    int error;
+
+    tc_del_qdisc(netdev);
+
+    tcmsg = netdev_linux_tc_make_request(netdev, RTM_NEWQDISC,
+                                         NLM_F_EXCL | NLM_F_CREATE, &request);
+    if (!tcmsg) {
+        return ENODEV;
+    }
+    tcmsg->tcm_handle = tc_make_handle(1, 0);
+    tcmsg->tcm_parent = TC_H_ROOT;
+
+    memset(&opt, 0, sizeof opt);
+
+    if (!limit) {
+        opt.limit = 1000;
+    } else {
+        opt.limit = limit;
+    }
+
+    if (loss) {
+        if (loss > 100) {
+            VLOG_WARN_RL(&rl, "loss should be a percentage value
between 0 to 100, "
+                              "loss was %u", loss);
+            return EINVAL;
+        }
+        opt.loss = floor(UINT32_MAX * (loss / 100.0));
+    }
+
+    opt.latency = tc_time_to_ticks(latency);
+
+    nl_msg_put_string(&request, TCA_KIND, "netem");
+    nl_msg_put_unspec(&request, TCA_OPTIONS, &opt, sizeof opt);
+
+    error = tc_transact(&request, NULL);
+    if (error) {
+        VLOG_WARN_RL(&rl, "failed to replace %s qdisc, "
+                          "latency %u, limit %u, loss %u error %d(%s)",
+                     netdev_get_name(netdev),
+                     opt.latency, opt.limit, opt.loss,
+                     error, ovs_strerror(error));
+    }
+    return error;
+}
+
+static void
+netem_parse_qdisc_details__(struct netdev *netdev OVS_UNUSED,
+                          const struct smap *details, struct netem *netem)
+{
+    netem->latency = smap_get_ullong(details, "latency", 0);
+    netem->limit = smap_get_ullong(details, "limit", 0);
+    netem->loss = smap_get_ullong(details, "loss", 0);
+
+    if(!netem->limit) {
+        netem->limit = 1000;
+    }
+}
+
+static int
+netem_tc_install(struct netdev *netdev, const struct smap *details)
+{
+    int error;
+    struct netem netem;
+
+    netem_parse_qdisc_details__(netdev, details, &netem);
+    error = netem_setup_qdisc__(netdev, netem.latency, netem.limit,
netem.loss);
+    if (!error) {
+        netem_install__(netdev, netem.latency, netem.limit, netem.loss);
+    }
+    return error;
+}
+
+static int
+netem_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg)
+{
+    const struct tc_netem_qopt *netem;
+    struct nlattr *nlattr;
+    const char * kind;
+    int error;
+
+    error = tc_parse_qdisc(nlmsg, &kind, &nlattr);
+    if (error == 0) {
+        netem = nl_attr_get(nlattr);
+        netem_install__(netdev, netem->latency, netem->limit, netem->loss);
+        return 0;
+    }
+
+    return error;
+}
+
+static void
+netem_tc_destroy(struct tc *tc)
+{
+    struct netem *netem = CONTAINER_OF(tc, struct netem, tc);
+    tc_destroy(tc);
+    free(netem);
+}
+
+static int
+netem_qdisc_get(const struct netdev *netdev, struct smap *details)
+{
+    const struct netem *netem = netem_get__(netdev);
+    smap_add_format(details, "latency", "%u", netem->latency);
+    smap_add_format(details, "limit", "%u", netem->limit);
+    smap_add_format(details, "loss", "%u", netem->loss);
+    return 0;
+}
+
+static int
+netem_qdisc_set(struct netdev *netdev, const struct smap *details)
+{
+    struct netem netem;
+
+    netem_parse_qdisc_details__(netdev, details, &netem);
+    netem_install__(netdev, netem.latency, netem.limit, netem.loss);
+    netem_get__(netdev)->latency = netem.latency;
+    netem_get__(netdev)->limit = netem.limit;
+    netem_get__(netdev)->loss = netem.loss;
+    return 0;
+}
+
+static const struct tc_ops tc_ops_netem = {
+        .linux_name = "netem",
+        .ovs_name = "linux-netem",
+        .n_queues = NETEM_N_QUEUES,
+        .tc_install = netem_tc_install,
+        .tc_load = netem_tc_load,
+        .tc_destroy = netem_tc_destroy,
+        .qdisc_get = netem_qdisc_get,
+        .qdisc_set = netem_qdisc_set,
+};
+
 /* HTB traffic control class. */

 #define HTB_N_QUEUES 0xf000
@@ -5240,6 +5415,12 @@  tc_buffer_per_jiffy(unsigned int rate)
     return rate / buffer_hz;
 }

+static uint32_t
+tc_time_to_ticks(uint32_t time) {
+    read_psched();
+    return time * (ticks_per_s / 1000000);
+}
+
 /* Given Netlink 'msg' that describes a qdisc, extracts the name of the qdisc,
  * e.g. "htb", into '*kind' (if it is nonnull).  If 'options' is nonnull,
  * extracts 'msg''s TCA_OPTIONS attributes into '*options' if it is present or
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 654b5f8c9..56318ec21 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -4327,6 +4327,14 @@  ovs-vsctl add-port br0 p0 -- set Interface p0
type=patch options:peer=p1 \
           for information on how this classifier works.
         </dd>

+        <dt><code>linux-netem</code></dt>
+        <dd>
+          Linux ``Network Emulator'' classifier. See
+          <code>tc-netem</code>(8) (also at
+          <code>http://man7.org/linux/man-pages/man8/tc-netem.8.html</code>)
+          for information on how this classifier works.
+        </dd>
+
         <dt><code>linux-noop</code></dt>
         <dd>