netem: add ECN capability
authorEric Dumazet <edumazet@google.com>
Mon, 30 Apr 2012 23:11:05 +0000 (23:11 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 1 May 2012 13:39:48 +0000 (09:39 -0400)
Add ECN (Explicit Congestion Notification) marking capability to netem

tc qdisc add dev eth0 root netem drop 0.5 ecn

Instead of dropping packets, try to ECN mark them.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
Cc: Tom Herbert <therbert@google.com>
Cc: Hagen Paul Pfeifer <hagen@jauu.net>
Cc: Stephen Hemminger <shemminger@vyatta.com>
Acked-by: Hagen Paul Pfeifer <hagen@jauu.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/pkt_sched.h
net/sched/sch_netem.c

index 410b33d014d2dfc3fb0c8ad0c6bb0c20a68ddbc2..ffe975c3f1d89907610f3d6a44ea5b1ccd14e605 100644 (file)
@@ -509,6 +509,7 @@ enum {
        TCA_NETEM_CORRUPT,
        TCA_NETEM_LOSS,
        TCA_NETEM_RATE,
+       TCA_NETEM_ECN,
        __TCA_NETEM_MAX,
 };
 
index 110973145a4bcd4a25d0521df8afa667790ed79f..231cd11aa6e225371b697cc9cdc16456d32764de 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
+#include <net/inet_ecn.h>
 
 #define VERSION "1.3"
 
@@ -78,6 +79,7 @@ struct netem_sched_data {
        psched_tdiff_t jitter;
 
        u32 loss;
+       u32 ecn;
        u32 limit;
        u32 counter;
        u32 gap;
@@ -374,9 +376,12 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                ++count;
 
        /* Drop packet? */
-       if (loss_event(q))
-               --count;
-
+       if (loss_event(q)) {
+               if (q->ecn && INET_ECN_set_ce(skb))
+                       sch->qstats.drops++; /* mark packet */
+               else
+                       --count;
+       }
        if (count == 0) {
                sch->qstats.drops++;
                kfree_skb(skb);
@@ -706,6 +711,7 @@ static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
        [TCA_NETEM_CORRUPT]     = { .len = sizeof(struct tc_netem_corrupt) },
        [TCA_NETEM_RATE]        = { .len = sizeof(struct tc_netem_rate) },
        [TCA_NETEM_LOSS]        = { .type = NLA_NESTED },
+       [TCA_NETEM_ECN]         = { .type = NLA_U32 },
 };
 
 static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
@@ -776,6 +782,9 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
        if (tb[TCA_NETEM_RATE])
                get_rate(sch, tb[TCA_NETEM_RATE]);
 
+       if (tb[TCA_NETEM_ECN])
+               q->ecn = nla_get_u32(tb[TCA_NETEM_ECN]);
+
        q->loss_model = CLG_RANDOM;
        if (tb[TCA_NETEM_LOSS])
                ret = get_loss_clg(sch, tb[TCA_NETEM_LOSS]);
@@ -902,6 +911,9 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
        if (nla_put(skb, TCA_NETEM_RATE, sizeof(rate), &rate))
                goto nla_put_failure;
 
+       if (q->ecn && nla_put_u32(skb, TCA_NETEM_ECN, q->ecn))
+               goto nla_put_failure;
+
        if (dump_loss_model(q, skb) != 0)
                goto nla_put_failure;