FQ CoDel is available as a module, sch_fq_codel.
This backports:
commit
4b549a2ef4bef9965d97cbd992ba67930cd3e0fe
Author: Eric Dumazet <edumazet@google.com>
Date: Fri May 11 09:30:50 2012 +0000
fq_codel: Fair Queue Codel AQM
Fair Queue Codel packet scheduler
Principles :
- Packets are classified (internal classifier or external) on flows.
- This is a Stochastic model (as we use a hash, several flows might
be hashed on same slot)
- Each flow has a CoDel managed queue.
- Flows are linked onto two (Round Robin) lists,
so that new flows have priority on old ones.
- For a given flow, packets are not reordered (CoDel uses a FIFO)
- head drops only.
- ECN capability is on by default.
- Very low memory footprint (64 bytes per flow)
I should note that this is different than CoDel. This code is GPL,
CoDel is Dual BSD/GPL licensed. 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>
obj-$(CONFIG_COMPAT_FIRMWARE_CLASS) += compat_firmware_class.o
obj-$(CONFIG_COMPAT_NET_SCH_CODEL) += sch_codel.o
+obj-$(CONFIG_COMPAT_NET_SCH_FQ_CODEL) += sch_fq_codel.o
compat-y += main.o
kstrtox.o
compat-$(CONFIG_COMPAT_KERNEL_3_0) += compat-3.0.o
compat-$(CONFIG_COMPAT_KERNEL_3_2) += compat-3.2.o
-compat-$(CONFIG_COMPAT_KERNEL_3_3) += compat-3.3.o
+compat-$(CONFIG_COMPAT_KERNEL_3_3) += \
+ compat-3.3.o \
+ flow_dissector.o
compat-$(CONFIG_COMPAT_KERNEL_3_4) += compat-3.4.o
compat-$(CONFIG_COMPAT_CORDIC) += cordic.o
return true;
}
-EXPORT_SYMBOL(skb_flow_dissect);
+EXPORT_SYMBOL_GPL(skb_flow_dissect);
struct list_head new_flows; /* list of new flows */
struct list_head old_flows; /* list of old flows */
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ u32 limit;
+#endif
};
static unsigned int fq_codel_hash(const struct fq_codel_sched_data *q,
flow->deficit = q->quantum;
flow->dropped = 0;
}
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ if (++sch->q.qlen < q->limit)
+#else
if (++sch->q.qlen < sch->limit)
+#endif
return NET_XMIT_SUCCESS;
q->drop_overlimit++;
}
if (tb[TCA_FQ_CODEL_LIMIT])
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ q->limit = nla_get_u32(tb[TCA_FQ_CODEL_LIMIT]);
+#else
sch->limit = nla_get_u32(tb[TCA_FQ_CODEL_LIMIT]);
+#endif
if (tb[TCA_FQ_CODEL_ECN])
q->cparams.ecn = !!nla_get_u32(tb[TCA_FQ_CODEL_ECN]);
if (tb[TCA_FQ_CODEL_QUANTUM])
q->quantum = max(256U, nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM]));
+#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 = fq_codel_dequeue(sch);
kfree_skb(skb);
{
struct fq_codel_sched_data *q = qdisc_priv(sch);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25))
tcf_destroy_chain(&q->filter_list);
+#else
+ tcf_destroy_chain(q->filter_list);
+#endif
fq_codel_free(q->backlogs);
fq_codel_free(q->flows);
}
struct fq_codel_sched_data *q = qdisc_priv(sch);
int i;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ q->limit = 10*1024;
+#else
sch->limit = 10*1024;
+#endif
q->flows_cnt = 1024;
q->quantum = psched_mtu(qdisc_dev(sch));
q->perturbation = net_random();
INIT_LIST_HEAD(&flow->flowchain);
}
}
+#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;
if (nla_put_u32(skb, TCA_FQ_CODEL_TARGET,
codel_time_to_us(q->cparams.target)) ||
nla_put_u32(skb, TCA_FQ_CODEL_LIMIT,
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ q->limit) ||
+#else
sch->limit) ||
+#endif
nla_put_u32(skb, TCA_FQ_CODEL_INTERVAL,
codel_time_to_us(q->cparams.interval)) ||
nla_put_u32(skb, TCA_FQ_CODEL_ECN,
.priv_size = sizeof(struct fq_codel_sched_data),
.enqueue = fq_codel_enqueue,
.dequeue = fq_codel_dequeue,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28))
.peek = qdisc_peek_dequeued,
+#endif
.drop = fq_codel_drop,
.init = fq_codel_init,
.reset = fq_codel_reset,
/*
* backports 2658fa803111dae1353602e7f586de8e537803e2
- * We skip proto_ports_offset() as I'm lazy.
*/
static inline bool ipv4_is_loopback(__be32 addr)
#include <net/sch_generic.h>
#include <linux/ethtool.h>
+static inline struct net_device *qdisc_dev(const struct Qdisc *qdisc)
+{
+ return qdisc->dev;
+}
+
+/*
+ * Backports 378a2f09 and c27f339a
+ * This may need a bit more work.
+ */
+enum net_xmit_qdisc_t {
+ __NET_XMIT_STOLEN = 0x00010000,
+ __NET_XMIT_BYPASS = 0x00020000,
+};
+
struct qdisc_skb_cb {
unsigned int pkt_len;
char data[];
#include <linux/skbuff.h>
#include <linux/leds.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+
+static inline int proto_ports_offset(int proto)
+{
+ switch (proto) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ case IPPROTO_DCCP:
+ case IPPROTO_ESP: /* SPI */
+ case IPPROTO_SCTP:
+ case IPPROTO_UDPLITE:
+ return 0;
+ case IPPROTO_AH: /* SPI */
+ return 4;
+ default:
+ return -EINVAL;
+ }
+}
#define SDIO_CLASS_BT_AMP 0x09 /* Type-A Bluetooth AMP interface */
#include <linux/security.h>
#include <linux/skbuff.h>
+#include <net/ip.h>
+
+/* Backports 56f8a75c */
+static inline bool ip_is_fragment(const struct iphdr *iph)
+{
+ return (iph->frag_off & htons(IP_MF | IP_OFFSET)) != 0;
+}
static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
unsigned int length, gfp_t gfp)
__u32 dropping; /* are we in dropping state ? */
};
+/* This backports:
+ *
+ * commit 4b549a2ef4bef9965d97cbd992ba67930cd3e0fe
+ * Author: Eric Dumazet <edumazet@google.com>
+ * Date: Fri May 11 09:30:50 2012 +0000
+ * fq_codel: Fair Queue Codel AQM
+ */
+
+/* FQ_CODEL */
+
+enum {
+ TCA_FQ_CODEL_UNSPEC,
+ TCA_FQ_CODEL_TARGET,
+ TCA_FQ_CODEL_LIMIT,
+ TCA_FQ_CODEL_INTERVAL,
+ TCA_FQ_CODEL_ECN,
+ TCA_FQ_CODEL_FLOWS,
+ TCA_FQ_CODEL_QUANTUM,
+ __TCA_FQ_CODEL_MAX
+};
+
+#define TCA_FQ_CODEL_MAX (__TCA_FQ_CODEL_MAX - 1)
+
+enum {
+ TCA_FQ_CODEL_XSTATS_QDISC,
+ TCA_FQ_CODEL_XSTATS_CLASS,
+};
+
+struct tc_fq_codel_qd_stats {
+ __u32 maxpacket; /* largest packet we've seen so far */
+ __u32 drop_overlimit; /* number of time max qdisc
+ * packet limit was hit
+ */
+ __u32 ecn_mark; /* number of packets we ECN marked
+ * instead of being dropped
+ */
+ __u32 new_flow_count; /* number of time packets
+ * created a 'new flow'
+ */
+ __u32 new_flows_len; /* count of flows in new list */
+ __u32 old_flows_len; /* count of flows in old list */
+};
+
+struct tc_fq_codel_cl_stats {
+ __s32 deficit;
+ __u32 ldelay; /* in-queue delay seen by most recently
+ * dequeued packet
+ */
+ __u32 count;
+ __u32 lastcount;
+ __u32 dropping;
+ __s32 drop_next;
+};
+
+struct tc_fq_codel_xstats {
+ __u32 type;
+ union {
+ struct tc_fq_codel_qd_stats qdisc_stats;
+ struct tc_fq_codel_cl_stats class_stats;
+ };
+};
+
+
/* Backports tty_lock: Localise the lock */
#define tty_lock(__tty) tty_lock()
#define tty_unlock(__tty) tty_unlock()
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
+#include_next <net/flow_keys.h>
+#else
+
#ifndef _NET_FLOW_KEYS_H
#define _NET_FLOW_KEYS_H
extern bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow);
#endif
+#endif
fi
if [[ ${CONFIG_COMPAT_KERNEL_3_5} = "y" ]]; then
- # We don't have 2.6.24 backport support yet for Codel
+ # We don't have 2.6.24 backport support yet for Codel / FQ CoDel
# For those who want to try this is what is required that I can tell
# so far:
# * struct Qdisc_ops
# - 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"
+ echo "export CONFIG_COMPAT_NET_SCH_FQ_CODEL=m"
fi
fi