compat: backport CoDel support down to 2.6.25
authorLuis R. Rodriguez <mcgrof@frijolero.org>
Fri, 25 May 2012 00:33:39 +0000 (17:33 -0700)
committerLuis R. Rodriguez <mcgrof@frijolero.org>
Fri, 25 May 2012 00:53:04 +0000 (17:53 -0700)
This is available as a module called sch_codel.
For details on CoDel see:

http://lwn.net/Articles/496509/

This goes only compile tested against all the below kernels,
run time test results would be appreciated.

mcgrof@tux ~/compat (git::master)$ ckmake
Trying kernel                  3.4.0-030400rc1-generic  [OK]
Trying kernel                     3.3.7-030307-generic  [OK]
Trying kernel                     3.2.2-030202-generic  [OK]
Trying kernel                    3.1.10-030110-generic  [OK]
Trying kernel                    3.0.18-030018-generic  [OK]
Trying kernel                  2.6.39-02063904-generic  [OK]
Trying kernel                  2.6.38-02063808-generic  [OK]
Trying kernel                  2.6.37-02063706-generic  [OK]
Trying kernel                  2.6.36-02063604-generic  [OK]
Trying kernel                  2.6.35-02063512-generic  [OK]
Trying kernel                  2.6.34-02063410-generic  [OK]
Trying kernel                  2.6.33-02063305-generic  [OK]
Trying kernel                  2.6.32-02063255-generic  [OK]
Trying kernel                  2.6.31-02063113-generic  [OK]
Trying kernel                  2.6.30-02063010-generic  [OK]
Trying kernel                  2.6.29-02062906-generic  [OK]
Trying kernel                  2.6.28-02062810-generic  [OK]
Trying kernel                    2.6.27-020627-generic  [OK]
Trying kernel                    2.6.26-020626-generic  [OK]
Trying kernel                    2.6.25-020625-generic  [OK]
Trying kernel                    2.6.24-020624-generic  [OK]

Signed-off-by: Luis R. Rodriguez <mcgrof@frijolero.org>
compat/Makefile
compat/sch_codel.c
include/linux/compat-2.6.27.h
include/linux/compat-2.6.32.h
include/linux/compat-2.6.38.h
include/linux/compat-3.3.h
include/linux/compat-3.5.h
include/net/codel.h
scripts/gen-compat-config.sh

index 667e727..8397714 100644 (file)
@@ -2,6 +2,7 @@ obj-m += compat.o
 #compat-objs :=
 
 obj-$(CONFIG_COMPAT_FIRMWARE_CLASS) += compat_firmware_class.o
+obj-$(CONFIG_COMPAT_NET_SCH_CODEL) += sch_codel.o
 
 compat-y += main.o
 
index 2f9ab17..5ad66fb 100644 (file)
@@ -58,6 +58,9 @@ struct codel_sched_data {
        struct codel_vars       vars;
        struct codel_stats      stats;
        u32                     drop_overlimit;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+       u32 limit;
+#endif
 };
 
 /* This is the specific function called from codel_dequeue()
@@ -95,11 +98,16 @@ static int codel_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct codel_sched_data *q;
 
+       q = qdisc_priv(sch);
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+       if (likely(qdisc_qlen(sch) < q->limit)) {
+#else
        if (likely(qdisc_qlen(sch) < sch->limit)) {
+#endif
                codel_set_enqueue_time(skb);
                return qdisc_enqueue_tail(skb, sch);
        }
-       q = qdisc_priv(sch);
        q->drop_overlimit++;
        return qdisc_drop(skb, sch);
 }
@@ -140,13 +148,21 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt)
        }
 
        if (tb[TCA_CODEL_LIMIT])
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+               q->limit = nla_get_u32(tb[TCA_CODEL_LIMIT]);
+#else
                sch->limit = nla_get_u32(tb[TCA_CODEL_LIMIT]);
+#endif
 
        if (tb[TCA_CODEL_ECN])
                q->params.ecn = !!nla_get_u32(tb[TCA_CODEL_ECN]);
 
        qlen = sch->q.qlen;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+       while (sch->q.qlen > q->limit) {
+#else
        while (sch->q.qlen > sch->limit) {
+#endif
                struct sk_buff *skb = __skb_dequeue(&sch->q);
 
                sch->qstats.backlog -= qdisc_pkt_len(skb);
@@ -162,7 +178,11 @@ static int codel_init(struct Qdisc *sch, struct nlattr *opt)
 {
        struct codel_sched_data *q = qdisc_priv(sch);
 
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+       q->limit = DEFAULT_CODEL_LIMIT;
+#else
        sch->limit = DEFAULT_CODEL_LIMIT;
+#endif
 
        codel_params_init(&q->params);
        codel_vars_init(&q->vars);
@@ -175,7 +195,11 @@ static int codel_init(struct Qdisc *sch, struct nlattr *opt)
                        return err;
        }
 
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+       if (q->limit >= 1)
+#else
        if (sch->limit >= 1)
+#endif
                sch->flags |= TCQ_F_CAN_BYPASS;
        else
                sch->flags &= ~TCQ_F_CAN_BYPASS;
@@ -195,7 +219,11 @@ static int codel_dump(struct Qdisc *sch, struct sk_buff *skb)
        if (nla_put_u32(skb, TCA_CODEL_TARGET,
                        codel_time_to_us(q->params.target)) ||
            nla_put_u32(skb, TCA_CODEL_LIMIT,
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+                       q->limit) ||
+#else
                        sch->limit) ||
+#endif
            nla_put_u32(skb, TCA_CODEL_INTERVAL,
                        codel_time_to_us(q->params.interval)) ||
            nla_put_u32(skb, TCA_CODEL_ECN,
@@ -248,7 +276,9 @@ static struct Qdisc_ops codel_qdisc_ops __read_mostly = {
 
        .enqueue        =       codel_qdisc_enqueue,
        .dequeue        =       codel_qdisc_dequeue,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28))
        .peek           =       qdisc_peek_dequeued,
+#endif
        .init           =       codel_init,
        .reset          =       codel_reset,
        .change         =       codel_change,
index 1e2af80..106e7ee 100644 (file)
 #include <net/sch_generic.h>
 #include <linux/ethtool.h>
 
+struct qdisc_skb_cb {
+       unsigned int            pkt_len;
+       char                    data[];
+};
+
+static inline struct qdisc_skb_cb *qdisc_skb_cb(struct sk_buff *skb)
+{
+       return (struct qdisc_skb_cb *)skb->cb;
+}
+
+static inline unsigned int qdisc_pkt_len(struct sk_buff *skb)
+{
+       return qdisc_skb_cb(skb)->pkt_len;
+}
+
 #define PCI_PM_CAP_PME_SHIFT   11
 
 /* I can't find a more suitable replacement... */
index b0c699a..9d41fc8 100644 (file)
 #include <net/iw_handler.h>
 #include <linux/workqueue.h>
 #include <net/genetlink.h>
+#include <net/sch_generic.h>
+
+#define TCQ_F_CAN_BYPASS        4
+
+static inline int qdisc_qlen(const struct Qdisc *q)
+{
+       return q->q.qlen;
+}
 
 #define SDIO_VENDOR_ID_INTEL                   0x0089
 #define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX     0x1402
index 63f9dd6..0a86468 100644 (file)
@@ -8,6 +8,38 @@
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
 #include <linux/etherdevice.h>
+#include <net/sch_generic.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30))
+static inline void bstats_update(struct gnet_stats_basic_packed *bstats,
+                                const struct sk_buff *skb)
+{
+       bstats->bytes += qdisc_pkt_len((struct sk_buff *) skb);
+       bstats->packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
+}
+static inline void qdisc_bstats_update(struct Qdisc *sch,
+                                      const struct sk_buff *skb)
+{
+       bstats_update(&sch->bstats, skb);
+}
+#else
+/*
+ * kernels <= 2.6.30 do not pass a const skb to qdisc_pkt_len, and
+ * gnet_stats_basic_packed did not exist (see c1a8f1f1c8)
+ */
+static inline void bstats_update(struct gnet_stats_basic *bstats,
+                                struct sk_buff *skb)
+{
+       bstats->bytes += qdisc_pkt_len(skb);
+       bstats->packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
+}
+static inline void qdisc_bstats_update(struct Qdisc *sch,
+                                      struct sk_buff *skb)
+{
+       bstats_update(&sch->bstats, skb);
+}
+#endif
+
 
 /* rename member in struct mmc_host in include/linux/mmc/host.h */
 #define max_segs       max_hw_segs
index 69bdcd0..1eb873d 100644 (file)
@@ -8,6 +8,19 @@
 /* include to override NL80211_FEATURE_SK_TX_STATUS */
 #include <linux/nl80211.h>
 #include <linux/skbuff.h>
+#include <net/sch_generic.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37))
+static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
+{
+       BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct qdisc_skb_cb) + sz);
+}
+#else
+static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
+{
+       /* XXX ? */
+}
+#endif
 
 extern struct sk_buff *__pskb_copy(struct sk_buff *skb,
                                   int headroom, gfp_t gfp_mask);
index 0bb35bb..c6d478e 100644 (file)
@@ -8,6 +8,43 @@
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0))
 
+#include <linux/pkt_sched.h>
+
+/*
+ * This backports:
+ *
+ *   From 76e3cc126bb223013a6b9a0e2a51238d1ef2e409 Mon Sep 17 00:00:00 2001
+ *   From: Eric Dumazet <edumazet@google.com>
+ *   Date: Thu, 10 May 2012 07:51:25 +0000
+ *   Subject: [PATCH] codel: Controlled Delay AQM
+ */
+
+/* CODEL */
+
+enum {
+       TCA_CODEL_UNSPEC,
+       TCA_CODEL_TARGET,
+       TCA_CODEL_LIMIT,
+       TCA_CODEL_INTERVAL,
+       TCA_CODEL_ECN,
+       __TCA_CODEL_MAX
+};
+
+#define TCA_CODEL_MAX  (__TCA_CODEL_MAX - 1)
+
+struct tc_codel_xstats {
+       __u32   maxpacket; /* largest packet we've seen so far */
+       __u32   count;     /* how many drops we've done since the last time we
+                           * entered dropping state
+                           */
+       __u32   lastcount; /* count at entry to dropping state */
+       __u32   ldelay;    /* in-queue delay seen by most recently dequeued packet */
+       __s32   drop_next; /* time to drop next packet */
+       __u32   drop_overlimit; /* number of time max qdisc packet limit was hit */
+       __u32   ecn_mark;  /* number of packets we ECN marked instead of dropped */
+       __u32   dropping;  /* are we in dropping state ? */
+};
+
 /* Backports tty_lock: Localise the lock */
 #define tty_lock(__tty) tty_lock()
 #define tty_unlock(__tty) tty_unlock()
index 550debf..128082e 100644 (file)
@@ -1,3 +1,9 @@
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0))
+#include_next <net/codel.h>
+#else
+
 #ifndef __NET_SCHED_CODEL_H
 #define __NET_SCHED_CODEL_H
 
@@ -85,7 +91,11 @@ struct codel_skb_cb {
 static struct codel_skb_cb *get_codel_cb(const struct sk_buff *skb)
 {
        qdisc_cb_private_validate(skb, sizeof(struct codel_skb_cb));
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37))
+       return (struct codel_skb_cb *)qdisc_skb_cb((struct sk_buff *) skb)->data;
+#else
        return (struct codel_skb_cb *)qdisc_skb_cb(skb)->data;
+#endif
 }
 
 static codel_time_t codel_get_enqueue_time(const struct sk_buff *skb)
@@ -219,10 +229,19 @@ static bool codel_should_drop(const struct sk_buff *skb,
        }
 
        vars->ldelay = now - codel_get_enqueue_time(skb);
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37))
+       sch->qstats.backlog -= qdisc_pkt_len((struct sk_buff *)skb);
+#else
        sch->qstats.backlog -= qdisc_pkt_len(skb);
+#endif
 
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37))
+       if (unlikely(qdisc_pkt_len((struct sk_buff *)skb) > stats->maxpacket))
+               stats->maxpacket = qdisc_pkt_len((struct sk_buff *)skb);
+#else
        if (unlikely(qdisc_pkt_len(skb) > stats->maxpacket))
                stats->maxpacket = qdisc_pkt_len(skb);
+#endif
 
        if (codel_time_before(vars->ldelay, params->target) ||
            sch->qstats.backlog <= stats->maxpacket) {
@@ -340,3 +359,4 @@ end:
        return skb;
 }
 #endif
+#endif
index f56cbfc..be90fdb 100755 (executable)
@@ -62,3 +62,15 @@ fi
 if [[ ${CONFIG_COMPAT_KERNEL_2_6_36} = "y" ]]; then
        echo "export CONFIG_COMPAT_KFIFO=y"
 fi
+
+if [[ ${CONFIG_COMPAT_KERNEL_3_5} = "y" ]]; then
+       # We don't have 2.6.24 backport support yet for Codel
+       # For those who want to try this is what is required that I can tell
+       # so far:
+       #  * struct Qdisc_ops
+       #       - init and change callback ops use a different argument dataype
+       #       - you need to parse data received from userspace differently
+       if [[ ${CONFIG_COMPAT_KERNEL_2_6_25} != "y" ]]; then
+               echo "export CONFIG_COMPAT_NET_SCH_CODEL=m"
+       fi
+fi