From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ob0-x22e.google.com (mail-ob0-x22e.google.com [IPv6:2607:f8b0:4003:c01::22e]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority G2" (verified OK)) by huchra.bufferbloat.net (Postfix) with ESMTPS id 549D521F2B8 for ; Sat, 2 May 2015 01:49:24 -0700 (PDT) Received: by obfe9 with SMTP id e9so78701569obf.1 for ; Sat, 02 May 2015 01:49:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=yUR9fFlV2F7w3029qxam8Q+xs7xIQYclmrycoiQDM0c=; b=Y3VAiSiaWAPpoTtlKa1SzXH3fU2qqNbTLuMi7K0EtawvSCMbtpcam7JkNrLAKSJ52E arU4e2o8hJmMs/uqp+afdBRqkRxJebqKWiYbq+Sjeeh4eiiezarjorMwn8T6QVopSFQ5 4XczcawxQrrM0M7kjrrpe3t6KD5rMGgyagCzLau2x+uXB+ziDxEiFdWKvcYIl/h73eF/ /yRtOcjJV+drySE9DaMtz93A3qXL2lCeaFWI04O++AAsfpIv513iz5+UOYTK3oIf2+Ei i4+rL9gli1/tnpNDyyuQffZj/E9cXjF8caWPT+6kIxXA/0d+pzNOzRwTb/QGPmCWuiaD yStA== MIME-Version: 1.0 X-Received: by 10.60.103.36 with SMTP id ft4mr10865013oeb.39.1430556563812; Sat, 02 May 2015 01:49:23 -0700 (PDT) Received: by 10.202.71.139 with HTTP; Sat, 2 May 2015 01:49:23 -0700 (PDT) Date: Sat, 2 May 2015 01:49:23 -0700 Message-ID: From: Dave Taht To: Kevin Darbyshire-Bryant , "cerowrt-devel@lists.bufferbloat.net" , Felix Fietkau Content-Type: multipart/alternative; boundary=089e0112cb34d139f105151567ed Subject: [Cerowrt-devel] openwrt package overriding issues on iproute2 X-BeenThere: cerowrt-devel@lists.bufferbloat.net X-Mailman-Version: 2.1.13 Precedence: list List-Id: Development issues regarding the cerowrt test router project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 02 May 2015 08:49:53 -0000 --089e0112cb34d139f105151567ed Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable I had figured I could override the default iproute2 with the one in ceropackages with: ./scripts/feeds install -f -p cero iproute2 But so far no luck. Tried removing and installing, no luck either. ? Aside from that I have kmod-sched-fq_pie and kmod-sched-cake building, at least, and everything else wrapped up for a test build of chaos calmer with all the new stuff. Will try harder in the morning, brute forcing if I have to. On Fri, May 1, 2015 at 9:09 AM, Kevin Darbyshire-Bryant < kevin@darbyshire-bryant.me.uk> wrote: > Hi Dave, > > Forwarding to you in case it helps. Replied to the list but my emails > appear to stuck somewhere. > > Kevin > > > -------- Forwarded Message -------- Subject: Re: [Cerowrt-devel] [Cake] > documentation review request and out of tree cake builds for openwrt/etc.= Date: > Fri, 01 May 2015 10:50:25 +0100 From: Kevin Darbyshire-Bryant > To: > cerowrt-devel@lists.bufferbloat.net > > On 30/04/2015 16:17, Dave Taht wrote: > > On Thu, Apr 30, 2015 at 7:38 AM, Jonathan Morton wrote: > >> It took me a while to get around to thinking about this, partly becaus= e my > >> phone inexplicably refuses to believe snapon exists. > > It has an old dnssec signed dns tree, using the isc dlv, which turned > > out to somewhat break older versions of dnsmasq, if that helps any. > OpenWrt CC trunk is now up to dnsmasq2.73rc7 - the latest fix was for a d= nssec fallback to tcp > problem. Highly recommended. > > So the next step for me is to get cake working in openwrt on hardware f= ast enough to run at 110Mbit and returning to the yurtlab to try it... but = that won't be til sunday at best. Tho I almost got it built, at least, last= night. Still sorting through patches.... > I have no idea if this will help you guys. I was fiddling with getting c= ake into CC a little earlier > based on the web page instructions. My totally unsubtle approach was to = basically copy over > relevant cerowrt-3.10 packages into the CC build tree: > > ceropackages-3.10/net/sqm-scripts openwrt/package/feeds/packages/sqm-scri= pts > ceropackages-3.10/net/kmod-sched-cake openwrt/feeds/packages/net/kmod-sch= ed-cake * > > ceropackages-3.10/luci/luci-app-sqm openwrt/package/feeds/packages/luci-a= pp-sqm > > iproute2 140&141 patches to openwrt/package/network/utils/iproute2/patche= s > > You'll need to put a symlink from openwrt/package/feeds/packages/kmod-sch= ed-cake to > openwrt/feeds/packages/net/kmod-sched-cake > > * note different directory! > > Also to get iproute2 tc to understand cake I basically did a git diff on = toke's iproute-cake > vs iproute 4.0.0 which is where CC currently is: Result 2 patches, 140 &= 141, 1st is to get > cake in, the 2nd is to do the required tc makefile tweak. CC builds, run= s on Archer C7, > nothing obviously exploded or broken...yet... your mileage may vary! VER= Y VERY > UNTESTED, DRAGONS LURK, I'M AN IDIOT AND DON'T REALLY KNOW WHAT I'M DOING= . > Is that clear enough? :-) > > Maybe it helps. What I will say is that a dslreports test appears less j= ittery for me. > > Kevin > > > > 141-cake-disable-sfq-codel.patch > > diff --git a/tc/Makefile b/tc/Makefile > index e503c8a..3dce533 100644 > --- a/tc/Makefile > +++ b/tc/Makefile > @@ -61,7 +61,7 @@ TCMODULES +=3D q_codel.o > TCMODULES +=3D q_fq_codel.o > TCMODULES +=3D q_nfq_codel.o > TCMODULES +=3D q_efq_codel.o > -TCMODULES +=3D q_sfq_codel.o > +#TCMODULES +=3D q_sfq_codel.o > TCMODULES +=3D q_pfq_codel.o > TCMODULES +=3D q_ns2_codel.o > TCMODULES +=3D q_ns4_codel.o > > > 140-cake-add-support.patch > > diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h > index 534b847..a1d7b67 100644 > --- a/include/linux/pkt_sched.h > +++ b/include/linux/pkt_sched.h > @@ -845,4 +845,38 @@ struct tc_pie_xstats { > __u32 maxq; /* maximum queue size */ > __u32 ecn_mark; /* packets marked with ecn*/ > }; > + > +/* CAKE */ > +enum { > + TCA_CAKE_UNSPEC, > + TCA_CAKE_BASE_RATE, > + TCA_CAKE_DIFFSERV_MODE, > + TCA_CAKE_ATM, > + TCA_CAKE_FLOW_MODE, > + __TCA_CAKE_MAX > +}; > +#define TCA_CAKE_MAX (__TCA_CAKE_MAX - 1) > + > +struct tc_cake_xstats { > + __u16 type; /* constant magic 0xCAFE */ > + __u16 class_cnt; > + struct { > + __u32 rate; > + __u32 target_us; > + __u32 packets; > + __u32 interval_us; > + __u64 bytes; > + __u32 dropped; > + __u32 ecn_marked; > + __u32 way_indirect_hits; > + __u32 way_misses; > + __u32 way_collisions; > + __u32 backlog_bytes; > + __u32 peak_delay; /* delay to fat flows */ > + __u32 avge_delay; > + __u32 base_delay; /* delay to sparse flows */ > + __u32 dummy2; > + } cls[8]; > +}; > + > #endif > diff --git a/tc/Makefile b/tc/Makefile > index d831a15..e503c8a 100644 > --- a/tc/Makefile > +++ b/tc/Makefile > @@ -59,8 +59,17 @@ TCMODULES +=3D em_meta.o > TCMODULES +=3D q_mqprio.o > TCMODULES +=3D q_codel.o > TCMODULES +=3D q_fq_codel.o > +TCMODULES +=3D q_nfq_codel.o > +TCMODULES +=3D q_efq_codel.o > +TCMODULES +=3D q_sfq_codel.o > +TCMODULES +=3D q_pfq_codel.o > +TCMODULES +=3D q_ns2_codel.o > +TCMODULES +=3D q_ns4_codel.o > TCMODULES +=3D q_fq.o > TCMODULES +=3D q_pie.o > +TCMODULES +=3D q_cake.o > +TCMODULES +=3D q_cake0.o > +TCMODULES +=3D q_cake2.o > TCMODULES +=3D q_hhf.o > > ifeq ($(TC_CONFIG_IPSET), y) > diff --git a/tc/q_cake.c b/tc/q_cake.c > new file mode 100644 > index 0000000..d9415d3 > --- /dev/null > +++ b/tc/q_cake.c > @@ -0,0 +1,333 @@ > +/* > + * Common Applications Kept Enhanced -- CAKE > + * > + * Copyright (C) 2014-2015 Jonathan Morton > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions, and the following disclaimer, > + * without modification. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in th= e > + * documentation and/or other materials provided with the distributio= n. > + * 3. The names of the authors may not be used to endorse or promote pro= ducts > + * derived from this software without specific prior written permissi= on. > + * > + * Alternatively, provided that this notice is retained in full, this > + * software may be distributed under the terms of the GNU General > + * Public License ("GPL") version 2, in which case the provisions of the > + * GPL apply INSTEAD OF those given above. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > + * DAMAGE. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "utils.h" > +#include "tc_util.h" > + > +static void explain(void) > +{ > + fprintf(stderr, "Usage: ... cake [ bandwidth RATE | unlimited ]\n" > + " [ besteffort | precedence | diffser= v8 | diffserv4 ]\n" > + " [ flowblind | srchost | dsthost | h= osts | flows ]\n" > + " [ atm ]\n"); > +} > + > +static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv, > + struct nlmsghdr *n) > +{ > + int unlimited =3D 0; > + unsigned bandwidth =3D 0; > + unsigned diffserv =3D 0; > + int flowmode =3D -1; > + int atm =3D -1; > + struct rtattr *tail; > + > + while (argc > 0) { > + if (strcmp(*argv, "bandwidth") =3D=3D 0) { > + NEXT_ARG(); > + if (get_rate(&bandwidth, *argv)) { > + fprintf(stderr, "Illegal \"bandwidth\"\n"); > + return -1; > + } > + unlimited =3D 0; > + } else if (strcmp(*argv, "unlimited") =3D=3D 0) { > + bandwidth =3D 0; > + unlimited =3D 1; > + > + } else if (strcmp(*argv, "besteffort") =3D=3D 0) { > + diffserv =3D 1; > + } else if (strcmp(*argv, "precedence") =3D=3D 0) { > + diffserv =3D 2; > + } else if (strcmp(*argv, "diffserv8") =3D=3D 0) { > + diffserv =3D 3; > + } else if (strcmp(*argv, "diffserv4") =3D=3D 0) { > + diffserv =3D 4; > + } else if (strcmp(*argv, "diffserv") =3D=3D 0) { > + diffserv =3D 4; > + > + } else if (strcmp(*argv, "flowblind") =3D=3D 0) { > + flowmode =3D 0; > + } else if (strcmp(*argv, "srchost") =3D=3D 0) { > + flowmode =3D 1; > + } else if (strcmp(*argv, "dsthost") =3D=3D 0) { > + flowmode =3D 2; > + } else if (strcmp(*argv, "hosts") =3D=3D 0) { > + flowmode =3D 3; > + } else if (strcmp(*argv, "flows") =3D=3D 0) { > + flowmode =3D 4; > + > + } else if (strcmp(*argv, "atm") =3D=3D 0) { > + atm =3D 1; > + } else if (strcmp(*argv, "noatm") =3D=3D 0) { > + atm =3D 0; > + > + } else if (strcmp(*argv, "help") =3D=3D 0) { > + explain(); > + return -1; > + } else { > + fprintf(stderr, "What is \"%s\"?\n", *argv); > + explain(); > + return -1; > + } > + argc--; argv++; > + } > + > + tail =3D NLMSG_TAIL(n); > + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); > + if (bandwidth || unlimited) > + addattr_l(n, 1024, TCA_CAKE_BASE_RATE, &bandwidth, sizeof(bandwi= dth)); > + if (diffserv) > + addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(dif= fserv)); > + if (atm !=3D -1) > + addattr_l(n, 1024, TCA_CAKE_ATM, &atm, sizeof(atm)); > + if (flowmode !=3D -1) > + addattr_l(n, 1024, TCA_CAKE_FLOW_MODE, &flowmode, sizeof(flowmod= e)); > + tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail; > + return 0; > +} > + > +static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr = *opt) > +{ > + struct rtattr *tb[TCA_CAKE_MAX + 1]; > + unsigned bandwidth =3D 0; > + unsigned diffserv =3D 0; > + unsigned flowmode =3D 0; > + int atm =3D -1; > + SPRINT_BUF(b1); > + > + if (opt =3D=3D NULL) > + return 0; > + > + parse_rtattr_nested(tb, TCA_CAKE_MAX, opt); > + > + if (tb[TCA_CAKE_BASE_RATE] && > + RTA_PAYLOAD(tb[TCA_CAKE_BASE_RATE]) >=3D sizeof(__u32)) { > + bandwidth =3D rta_getattr_u32(tb[TCA_CAKE_BASE_RATE]); > + if(bandwidth) > + fprintf(f, "bandwidth %s ", sprint_rate(bandwidth, b1)); > + else > + fprintf(f, "unlimited "); > + } > + if (tb[TCA_CAKE_DIFFSERV_MODE] && > + RTA_PAYLOAD(tb[TCA_CAKE_DIFFSERV_MODE]) >=3D sizeof(__u32)) { > + diffserv =3D rta_getattr_u32(tb[TCA_CAKE_DIFFSERV_MODE]); > + switch(diffserv) { > + case 1: > + fprintf(f, "besteffort "); > + break; > + case 2: > + fprintf(f, "precedence "); > + break; > + case 3: > + fprintf(f, "diffserv8 "); > + break; > + case 4: > + fprintf(f, "diffserv4 "); > + break; > + default: > + fprintf(f, "(?diffserv?) "); > + break; > + }; > + } > + if (tb[TCA_CAKE_FLOW_MODE] && > + RTA_PAYLOAD(tb[TCA_CAKE_FLOW_MODE]) >=3D sizeof(__u32)) { > + flowmode =3D rta_getattr_u32(tb[TCA_CAKE_FLOW_MODE]); > + switch(flowmode) { > + case 0: > + fprintf(f, "flowblind "); > + break; > + case 1: > + fprintf(f, "srchost "); > + break; > + case 2: > + fprintf(f, "dsthost "); > + break; > + case 3: > + fprintf(f, "hosts "); > + break; > + case 4: > + fprintf(f, "flows "); > + break; > + default: > + fprintf(f, "(?flowmode?) "); > + break; > + }; > + } > + if (tb[TCA_CAKE_ATM] && > + RTA_PAYLOAD(tb[TCA_CAKE_ATM]) >=3D sizeof(__u32)) { > + atm =3D rta_getattr_u32(tb[TCA_CAKE_ATM]); > + if (atm) > + fprintf(f, "atm "); > + } > + > + return 0; > +} > + > +static int cake_print_xstats(struct qdisc_util *qu, FILE *f, > + struct rtattr *xstats) > +{ > + /* fq_codel stats format borrowed */ > + struct tc_fq_codel_xstats *st; > + struct tc_cake_xstats *stc; > + SPRINT_BUF(b1); > + > + if (xstats =3D=3D NULL) > + return 0; > + > + if (RTA_PAYLOAD(xstats) < sizeof(st->type)) > + return -1; > + > + st =3D RTA_DATA(xstats); > + stc =3D RTA_DATA(xstats); > + > + if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC && RTA_PAYLOAD(xstats)= >=3D sizeof(*st)) { > + fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u e= cn_mark %u", > + st->qdisc_stats.maxpacket, > + st->qdisc_stats.drop_overlimit, > + st->qdisc_stats.new_flow_count, > + st->qdisc_stats.ecn_mark); > + fprintf(f, "\n new_flows_len %u old_flows_len %u", > + st->qdisc_stats.new_flows_len, > + st->qdisc_stats.old_flows_len); > + } else if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS && RTA_PAYLOAD(= xstats) >=3D sizeof(*st)) { > + fprintf(f, " deficit %d count %u lastcount %u ldelay %s", > + st->class_stats.deficit, > + st->class_stats.count, > + st->class_stats.lastcount, > + sprint_time(st->class_stats.ldelay, b1)); > + if (st->class_stats.dropping) { > + fprintf(f, " dropping"); > + if (st->class_stats.drop_next < 0) > + fprintf(f, " drop_next -%s", > + sprint_time(-st->class_stats.drop_next, b1)); > + else > + fprintf(f, " drop_next %s", > + sprint_time(st->class_stats.drop_next, b1)); > + } > + } else if (stc->type =3D=3D 0xCAFE && RTA_PAYLOAD(xstats) >=3D sizeo= f(*stc)) { > + int i; > + > + fprintf(f, " "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, " Class %u ", i); > + fprintf(f, "\n"); > + > + fprintf(f, " rate "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12s", sprint_rate(stc->cls[i].rate, b1)); > + fprintf(f, "\n"); > + > + fprintf(f, " target"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12s", sprint_time(stc->cls[i].target_us, b1)); > + fprintf(f, "\n"); > + > + fprintf(f, "interval"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12s", sprint_time(stc->cls[i].interval_us, b1))= ; > + fprintf(f, "\n"); > + > + fprintf(f, "Pk delay"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12s", sprint_time(stc->cls[i].peak_delay, b1)); > + fprintf(f, "\n"); > + > + fprintf(f, "Av delay"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12s", sprint_time(stc->cls[i].avge_delay, b1)); > + fprintf(f, "\n"); > + > + fprintf(f, "Sp delay"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12s", sprint_time(stc->cls[i].base_delay, b1)); > + fprintf(f, "\n"); > + > + fprintf(f, " pkts "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12u", stc->cls[i].packets); > + fprintf(f, "\n"); > + > + fprintf(f, "way inds"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12u", stc->cls[i].way_indirect_hits); > + fprintf(f, "\n"); > + > + fprintf(f, "way miss"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12u", stc->cls[i].way_misses); > + fprintf(f, "\n"); > + > + fprintf(f, "way cols"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12u", stc->cls[i].way_collisions); > + fprintf(f, "\n"); > + > + fprintf(f, " bytes "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12llu", stc->cls[i].bytes); > + fprintf(f, "\n"); > + > + fprintf(f, " drops "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12u", stc->cls[i].dropped); > + fprintf(f, "\n"); > + > + fprintf(f, " marks "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%12u", stc->cls[i].ecn_marked); > + } else { > + return -1; > + } > + return 0; > +} > + > +struct qdisc_util cake_qdisc_util =3D { > + .id =3D "cake", > + .parse_qopt =3D cake_parse_opt, > + .print_qopt =3D cake_print_opt, > + .print_xstats =3D cake_print_xstats, > +}; > diff --git a/tc/q_cake0.c b/tc/q_cake0.c > new file mode 100644 > index 0000000..9fb63ed > --- /dev/null > +++ b/tc/q_cake0.c > @@ -0,0 +1,301 @@ > +/* > + * Common Applications Kept Enhanced -- CAKE > + * > + * Copyright (C) 2014 Jonathan Morton > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions, and the following disclaimer, > + * without modification. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in th= e > + * documentation and/or other materials provided with the distributio= n. > + * 3. The names of the authors may not be used to endorse or promote pro= ducts > + * derived from this software without specific prior written permissi= on. > + * > + * Alternatively, provided that this notice is retained in full, this > + * software may be distributed under the terms of the GNU General > + * Public License ("GPL") version 2, in which case the provisions of the > + * GPL apply INSTEAD OF those given above. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > + * DAMAGE. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "utils.h" > +#include "tc_util.h" > + > +static void explain(void) > +{ > + fprintf(stderr, "Usage: ... cake0 [ bandwidth RATE | unlimited ]\n" > + " [ besteffort | precedence | diffse= rv ]\n" > + " [ flowblind | srchost | dsthost | = hosts | flows ]\n" > + " [ atm ]\n"); > +} > + > +static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv, > + struct nlmsghdr *n) > +{ > + int unlimited =3D 0; > + unsigned bandwidth =3D 0; > + unsigned diffserv =3D 0; > + int flowmode =3D -1; > + int atm =3D -1; > + struct rtattr *tail; > + > + while (argc > 0) { > + if (strcmp(*argv, "bandwidth") =3D=3D 0) { > + NEXT_ARG(); > + if (get_rate(&bandwidth, *argv)) { > + fprintf(stderr, "Illegal \"bandwidth\"\n"); > + return -1; > + } > + unlimited =3D 0; > + } else if (strcmp(*argv, "unlimited") =3D=3D 0) { > + bandwidth =3D 0; > + unlimited =3D 1; > + > + } else if (strcmp(*argv, "besteffort") =3D=3D 0) { > + diffserv =3D 1; > + } else if (strcmp(*argv, "precedence") =3D=3D 0) { > + diffserv =3D 2; > + } else if (strcmp(*argv, "diffserv") =3D=3D 0) { > + diffserv =3D 3; > + > + } else if (strcmp(*argv, "flowblind") =3D=3D 0) { > + flowmode =3D 0; > + } else if (strcmp(*argv, "srchost") =3D=3D 0) { > + flowmode =3D 1; > + } else if (strcmp(*argv, "dsthost") =3D=3D 0) { > + flowmode =3D 2; > + } else if (strcmp(*argv, "hosts") =3D=3D 0) { > + flowmode =3D 3; > + } else if (strcmp(*argv, "flows") =3D=3D 0) { > + flowmode =3D 4; > + > + } else if (strcmp(*argv, "atm") =3D=3D 0) { > + atm =3D 1; > + } else if (strcmp(*argv, "noatm") =3D=3D 0) { > + atm =3D 0; > + > + } else if (strcmp(*argv, "help") =3D=3D 0) { > + explain(); > + return -1; > + } else { > + fprintf(stderr, "What is \"%s\"?\n", *argv); > + explain(); > + return -1; > + } > + argc--; argv++; > + } > + > + tail =3D NLMSG_TAIL(n); > + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); > + if (bandwidth || unlimited) > + addattr_l(n, 1024, TCA_CAKE_BASE_RATE, &bandwidth, sizeof(bandwi= dth)); > + if (diffserv) > + addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(dif= fserv)); > + if (atm !=3D -1) > + addattr_l(n, 1024, TCA_CAKE_ATM, &atm, sizeof(atm)); > + if (flowmode !=3D -1) > + addattr_l(n, 1024, TCA_CAKE_FLOW_MODE, &flowmode, sizeof(flowmod= e)); > + tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail; > + return 0; > +} > + > +static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr = *opt) > +{ > + struct rtattr *tb[TCA_CAKE_MAX + 1]; > + unsigned bandwidth =3D 0; > + unsigned diffserv =3D 0; > + unsigned flowmode =3D 0; > + int atm =3D -1; > + SPRINT_BUF(b1); > + > + if (opt =3D=3D NULL) > + return 0; > + > + parse_rtattr_nested(tb, TCA_CAKE_MAX, opt); > + > + if (tb[TCA_CAKE_BASE_RATE] && > + RTA_PAYLOAD(tb[TCA_CAKE_BASE_RATE]) >=3D sizeof(__u32)) { > + bandwidth =3D rta_getattr_u32(tb[TCA_CAKE_BASE_RATE]); > + if(bandwidth) > + fprintf(f, "bandwidth %s ", sprint_rate(bandwidth, b1)); > + else > + fprintf(f, "unlimited"); > + } > + if (tb[TCA_CAKE_DIFFSERV_MODE] && > + RTA_PAYLOAD(tb[TCA_CAKE_DIFFSERV_MODE]) >=3D sizeof(__u32)) { > + diffserv =3D rta_getattr_u32(tb[TCA_CAKE_DIFFSERV_MODE]); > + switch(diffserv) { > + case 1: > + fprintf(f, "besteffort "); > + break; > + case 2: > + fprintf(f, "precedence "); > + break; > + case 3: > + fprintf(f, "diffserv "); > + break; > + default: > + fprintf(f, "(?diffserv?) "); > + break; > + }; > + } > + if (tb[TCA_CAKE_FLOW_MODE] && > + RTA_PAYLOAD(tb[TCA_CAKE_FLOW_MODE]) >=3D sizeof(__u32)) { > + flowmode =3D rta_getattr_u32(tb[TCA_CAKE_FLOW_MODE]); > + switch(flowmode) { > + case 0: > + fprintf(f, "flowblind "); > + break; > + case 1: > + fprintf(f, "srchost "); > + break; > + case 2: > + fprintf(f, "dsthost "); > + break; > + case 3: > + fprintf(f, "hosts "); > + break; > + case 4: > + fprintf(f, "flows "); > + break; > + default: > + fprintf(f, "(?flowmode?) "); > + break; > + }; > + } > + if (tb[TCA_CAKE_ATM] && > + RTA_PAYLOAD(tb[TCA_CAKE_ATM]) >=3D sizeof(__u32)) { > + atm =3D rta_getattr_u32(tb[TCA_CAKE_ATM]); > + if (atm) > + fprintf(f, "atm "); > + } > + > + return 0; > +} > + > +static int cake_print_xstats(struct qdisc_util *qu, FILE *f, > + struct rtattr *xstats) > +{ > + /* fq_codel stats format borrowed */ > + struct tc_fq_codel_xstats *st; > + struct tc_cake_xstats *stc; > + SPRINT_BUF(b1); > + > + if (xstats =3D=3D NULL) > + return 0; > + > + if (RTA_PAYLOAD(xstats) < sizeof(st->type)) > + return -1; > + > + st =3D RTA_DATA(xstats); > + stc =3D RTA_DATA(xstats); > + > + if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC && RTA_PAYLOAD(xstats)= >=3D sizeof(*st)) { > + fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u e= cn_mark %u", > + st->qdisc_stats.maxpacket, > + st->qdisc_stats.drop_overlimit, > + st->qdisc_stats.new_flow_count, > + st->qdisc_stats.ecn_mark); > + fprintf(f, "\n new_flows_len %u old_flows_len %u", > + st->qdisc_stats.new_flows_len, > + st->qdisc_stats.old_flows_len); > + } else if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS && RTA_PAYLOAD(= xstats) >=3D sizeof(*st)) { > + fprintf(f, " deficit %d count %u lastcount %u ldelay %s", > + st->class_stats.deficit, > + st->class_stats.count, > + st->class_stats.lastcount, > + sprint_time(st->class_stats.ldelay, b1)); > + if (st->class_stats.dropping) { > + fprintf(f, " dropping"); > + if (st->class_stats.drop_next < 0) > + fprintf(f, " drop_next -%s", > + sprint_time(-st->class_stats.drop_next, b1)); > + else > + fprintf(f, " drop_next %s", > + sprint_time(st->class_stats.drop_next, b1)); > + } > + } else if (stc->type =3D=3D 0xCAFE && RTA_PAYLOAD(xstats) >=3D sizeo= f(*stc)) { > + int i; > + > + fprintf(f, " "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, " Class %u ", i); > + fprintf(f, "\n"); > + > + fprintf(f, " rate "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10s", sprint_rate(stc->cls[i].rate, b1)); > + fprintf(f, "\n"); > + > + fprintf(f, " target"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10s", sprint_time(stc->cls[i].target_us, b1)); > + fprintf(f, "\n"); > + > + fprintf(f, "interval"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10s", sprint_time(stc->cls[i].interval_us, b1))= ; > + fprintf(f, "\n"); > + > + fprintf(f, " delay "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10s", sprint_time(stc->cls[i].peak_delay, b1)); > + fprintf(f, "\n"); > + > + fprintf(f, " pkts "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10u", stc->cls[i].packets); > + fprintf(f, "\n"); > + > + fprintf(f, " bytes "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10llu", stc->cls[i].bytes); > + fprintf(f, "\n"); > + > + fprintf(f, " drops "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10u", stc->cls[i].dropped); > + fprintf(f, "\n"); > + > + fprintf(f, " marks "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10u", stc->cls[i].ecn_marked); > + } else { > + return -1; > + } > + return 0; > +} > + > +struct qdisc_util cake0_qdisc_util =3D { > + .id =3D "cake0", > + .parse_qopt =3D cake_parse_opt, > + .print_qopt =3D cake_print_opt, > + .print_xstats =3D cake_print_xstats, > +}; > diff --git a/tc/q_cake2.c b/tc/q_cake2.c > new file mode 100644 > index 0000000..a4d3f7c > --- /dev/null > +++ b/tc/q_cake2.c > @@ -0,0 +1,296 @@ > +/* > + * Common Applications Kept Enhanced -- CAKE > + * > + * Copyright (C) 2014 Jonathan Morton > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions, and the following disclaimer, > + * without modification. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in th= e > + * documentation and/or other materials provided with the distributio= n. > + * 3. The names of the authors may not be used to endorse or promote pro= ducts > + * derived from this software without specific prior written permissi= on. > + * > + * Alternatively, provided that this notice is retained in full, this > + * software may be distributed under the terms of the GNU General > + * Public License ("GPL") version 2, in which case the provisions of the > + * GPL apply INSTEAD OF those given above. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > + * DAMAGE. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "utils.h" > +#include "tc_util.h" > + > +static void explain(void) > +{ > + fprintf(stderr, "Usage: ... cake2 [ bandwidth RATE | unlimited ]\n" > + " [ besteffort | precedence | diffser= v ]\n" > + " [ flowblind | srchost | dsthost | h= osts | flows ]\n" > + " [ atm ]\n"); > +} > + > +static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv, > + struct nlmsghdr *n) > +{ > + int unlimited =3D 0; > + unsigned bandwidth =3D 0; > + unsigned diffserv =3D 0; > + int flowmode =3D -1; > + int atm =3D -1; > + struct rtattr *tail; > + > + while (argc > 0) { > + if (strcmp(*argv, "bandwidth") =3D=3D 0) { > + NEXT_ARG(); > + if (get_rate(&bandwidth, *argv)) { > + fprintf(stderr, "Illegal \"bandwidth\"\n"); > + return -1; > + } > + unlimited =3D 0; > + } else if (strcmp(*argv, "unlimited") =3D=3D 0) { > + bandwidth =3D 0; > + unlimited =3D 1; > + > + } else if (strcmp(*argv, "besteffort") =3D=3D 0) { > + diffserv =3D 1; > + } else if (strcmp(*argv, "precedence") =3D=3D 0) { > + diffserv =3D 2; > + } else if (strcmp(*argv, "diffserv") =3D=3D 0) { > + diffserv =3D 3; > + > + } else if (strcmp(*argv, "flowblind") =3D=3D 0) { > + flowmode =3D 0; > + } else if (strcmp(*argv, "srchost") =3D=3D 0) { > + flowmode =3D 1; > + } else if (strcmp(*argv, "dsthost") =3D=3D 0) { > + flowmode =3D 2; > + } else if (strcmp(*argv, "hosts") =3D=3D 0) { > + flowmode =3D 3; > + } else if (strcmp(*argv, "flows") =3D=3D 0) { > + flowmode =3D 4; > + > + } else if (strcmp(*argv, "atm") =3D=3D 0) { > + atm =3D 1; > + } else if (strcmp(*argv, "noatm") =3D=3D 0) { > + atm =3D 0; > + > + } else if (strcmp(*argv, "help") =3D=3D 0) { > + explain(); > + return -1; > + } else { > + fprintf(stderr, "What is \"%s\"?\n", *argv); > + explain(); > + return -1; > + } > + argc--; argv++; > + } > + > + tail =3D NLMSG_TAIL(n); > + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); > + if (bandwidth || unlimited) > + addattr_l(n, 1024, TCA_CAKE_BASE_RATE, &bandwidth, sizeof(bandwi= dth)); > + if (diffserv) > + addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(dif= fserv)); > + if (atm !=3D -1) > + addattr_l(n, 1024, TCA_CAKE_ATM, &atm, sizeof(atm)); > + if (flowmode !=3D -1) > + addattr_l(n, 1024, TCA_CAKE_FLOW_MODE, &flowmode, sizeof(flowmod= e)); > + tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail; > + return 0; > +} > + > +static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr = *opt) > +{ > + struct rtattr *tb[TCA_CAKE_MAX + 1]; > + unsigned bandwidth =3D 0; > + unsigned diffserv =3D 0; > + unsigned flowmode =3D 0; > + int atm =3D -1; > + SPRINT_BUF(b1); > + > + if (opt =3D=3D NULL) > + return 0; > + > + parse_rtattr_nested(tb, TCA_CAKE_MAX, opt); > + > + if (tb[TCA_CAKE_BASE_RATE] && > + RTA_PAYLOAD(tb[TCA_CAKE_BASE_RATE]) >=3D sizeof(__u32)) { > + bandwidth =3D rta_getattr_u32(tb[TCA_CAKE_BASE_RATE]); > + if(bandwidth) > + fprintf(f, "bandwidth %s ", sprint_rate(bandwidth, b1)); > + else > + fprintf(f, "unlimited"); > + } > + if (tb[TCA_CAKE_DIFFSERV_MODE] && > + RTA_PAYLOAD(tb[TCA_CAKE_DIFFSERV_MODE]) >=3D sizeof(__u32)) { > + diffserv =3D rta_getattr_u32(tb[TCA_CAKE_DIFFSERV_MODE]); > + switch(diffserv) { > + case 1: > + fprintf(f, "besteffort "); > + break; > + case 2: > + fprintf(f, "precedence "); > + break; > + case 3: > + fprintf(f, "diffserv "); > + break; > + default: > + fprintf(f, "(?diffserv?) "); > + break; > + }; > + } > + if (tb[TCA_CAKE_FLOW_MODE] && > + RTA_PAYLOAD(tb[TCA_CAKE_FLOW_MODE]) >=3D sizeof(__u32)) { > + flowmode =3D rta_getattr_u32(tb[TCA_CAKE_FLOW_MODE]); > + switch(flowmode) { > + case 0: > + fprintf(f, "flowblind "); > + break; > + case 1: > + fprintf(f, "srchost "); > + break; > + case 2: > + fprintf(f, "dsthost "); > + break; > + case 3: > + fprintf(f, "hosts "); > + break; > + case 4: > + fprintf(f, "flows "); > + break; > + default: > + fprintf(f, "(?flowmode?) "); > + break; > + }; > + } > + if (tb[TCA_CAKE_ATM] && > + RTA_PAYLOAD(tb[TCA_CAKE_ATM]) >=3D sizeof(__u32)) { > + atm =3D rta_getattr_u32(tb[TCA_CAKE_ATM]); > + if (atm) > + fprintf(f, "atm "); > + } > + > + return 0; > +} > + > +static int cake_print_xstats(struct qdisc_util *qu, FILE *f, > + struct rtattr *xstats) > +{ > + /* fq_codel stats format borrowed */ > + struct tc_fq_codel_xstats *st; > + struct tc_cake_xstats *stc; > + SPRINT_BUF(b1); > + > + if (xstats =3D=3D NULL) > + return 0; > + > + if (RTA_PAYLOAD(xstats) < sizeof(st->type)) > + return -1; > + > + st =3D RTA_DATA(xstats); > + stc =3D RTA_DATA(xstats); > + > + if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC && RTA_PAYLOAD(xstats)= >=3D sizeof(*st)) { > + fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u e= cn_mark %u", > + st->qdisc_stats.maxpacket, > + st->qdisc_stats.drop_overlimit, > + st->qdisc_stats.new_flow_count, > + st->qdisc_stats.ecn_mark); > + fprintf(f, "\n new_flows_len %u old_flows_len %u", > + st->qdisc_stats.new_flows_len, > + st->qdisc_stats.old_flows_len); > + } else if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS && RTA_PAYLOAD(= xstats) >=3D sizeof(*st)) { > + fprintf(f, " deficit %d count %u lastcount %u ldelay %s", > + st->class_stats.deficit, > + st->class_stats.count, > + st->class_stats.lastcount, > + sprint_time(st->class_stats.ldelay, b1)); > + if (st->class_stats.dropping) { > + fprintf(f, " dropping"); > + if (st->class_stats.drop_next < 0) > + fprintf(f, " drop_next -%s", > + sprint_time(-st->class_stats.drop_next, b1)); > + else > + fprintf(f, " drop_next %s", > + sprint_time(st->class_stats.drop_next, b1)); > + } > + } else if (stc->type =3D=3D 0xCAFE && RTA_PAYLOAD(xstats) >=3D sizeo= f(*stc)) { > + int i; > + > + fprintf(f, " "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, " Class %u ", i); > + fprintf(f, "\n"); > + > + fprintf(f, " rate "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10s", sprint_rate(stc->cls[i].rate, b1)); > + fprintf(f, "\n"); > + > + fprintf(f, " target"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10s", sprint_time(stc->cls[i].target_us, b1)); > + fprintf(f, "\n"); > + > + fprintf(f, "interval"); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10s", sprint_time(stc->cls[i].interval_us, b1))= ; > + fprintf(f, "\n"); > + > + fprintf(f, " pkts "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10u", stc->cls[i].packets); > + fprintf(f, "\n"); > + > + fprintf(f, " bytes "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10llu", stc->cls[i].bytes); > + fprintf(f, "\n"); > + > + fprintf(f, " drops "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10u", stc->cls[i].dropped); > + fprintf(f, "\n"); > + > + fprintf(f, " marks "); > + for(i=3D0; i < stc->class_cnt; i++) > + fprintf(f, "%10u", stc->cls[i].ecn_marked); > + } else { > + return -1; > + } > + return 0; > +} > + > +struct qdisc_util cake2_qdisc_util =3D { > + .id =3D "cake2", > + .parse_qopt =3D cake_parse_opt, > + .print_qopt =3D cake_print_opt, > + .print_xstats =3D cake_print_xstats, > +}; > diff --git a/tc/q_efq_codel.c b/tc/q_efq_codel.c > new file mode 100644 > index 0000000..b80e5e4 > --- /dev/null > +++ b/tc/q_efq_codel.c > @@ -0,0 +1,232 @@ > +/* > + * Fair Queue Codel > + * > + * Copyright (C) 2012 Eric Dumazet > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions, and the following disclaimer, > + * without modification. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in th= e > + * documentation and/or other materials provided with the distributio= n. > + * 3. The names of the authors may not be used to endorse or promote pro= ducts > + * derived from this software without specific prior written permissi= on. > + * > + * Alternatively, provided that this notice is retained in full, this > + * software may be distributed under the terms of the GNU General > + * Public License ("GPL") version 2, in which case the provisions of the > + * GPL apply INSTEAD OF those given above. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > + * DAMAGE. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "utils.h" > +#include "tc_util.h" > + > +static void explain(void) > +{ > + fprintf(stderr, "Usage: ... efq_codel [ limit PACKETS ] [ flows NUMB= ER ]\n"); > + fprintf(stderr, " [ target TIME] [ interval TIME = ]\n"); > + fprintf(stderr, " [ quantum BYTES ] [ [no]ecn ]\n= "); > +} > + > +static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **ar= gv, > + struct nlmsghdr *n) > +{ > + unsigned limit =3D 0; > + unsigned flows =3D 0; > + unsigned target =3D 0; > + unsigned interval =3D 0; > + unsigned quantum =3D 0; > + int ecn =3D -1; > + struct rtattr *tail; > + > + while (argc > 0) { > + if (strcmp(*argv, "limit") =3D=3D 0) { > + NEXT_ARG(); > + if (get_unsigned(&limit, *argv, 0)) { > + fprintf(stderr, "Illegal \"limit\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "flows") =3D=3D 0) { > + NEXT_ARG(); > + if (get_unsigned(&flows, *argv, 0)) { > + fprintf(stderr, "Illegal \"flows\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "quantum") =3D=3D 0) { > + NEXT_ARG(); > + if (get_unsigned(&quantum, *argv, 0)) { > + fprintf(stderr, "Illegal \"quantum\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "target") =3D=3D 0) { > + NEXT_ARG(); > + if (get_time(&target, *argv)) { > + fprintf(stderr, "Illegal \"target\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "interval") =3D=3D 0) { > + NEXT_ARG(); > + if (get_time(&interval, *argv)) { > + fprintf(stderr, "Illegal \"interval\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "ecn") =3D=3D 0) { > + ecn =3D 1; > + } else if (strcmp(*argv, "noecn") =3D=3D 0) { > + ecn =3D 0; > + } else if (strcmp(*argv, "help") =3D=3D 0) { > + explain(); > + return -1; > + } else { > + fprintf(stderr, "What is \"%s\"?\n", *argv); > + explain(); > + return -1; > + } > + argc--; argv++; > + } > + > + tail =3D NLMSG_TAIL(n); > + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); > + if (limit) > + addattr_l(n, 1024, TCA_FQ_CODEL_LIMIT, &limit, sizeof(limit)); > + if (flows) > + addattr_l(n, 1024, TCA_FQ_CODEL_FLOWS, &flows, sizeof(flows)); > + if (quantum) > + addattr_l(n, 1024, TCA_FQ_CODEL_QUANTUM, &quantum, sizeof(quantu= m)); > + if (interval) > + addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(inte= rval)); > + if (target) > + addattr_l(n, 1024, TCA_FQ_CODEL_TARGET, &target, sizeof(target))= ; > + if (ecn !=3D -1) > + addattr_l(n, 1024, TCA_FQ_CODEL_ECN, &ecn, sizeof(ecn)); > + tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail; > + return 0; > +} > + > +static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rta= ttr *opt) > +{ > + struct rtattr *tb[TCA_FQ_CODEL_MAX + 1]; > + unsigned limit; > + unsigned flows; > + unsigned interval; > + unsigned target; > + unsigned ecn; > + unsigned quantum; > + SPRINT_BUF(b1); > + > + if (opt =3D=3D NULL) > + return 0; > + > + parse_rtattr_nested(tb, TCA_FQ_CODEL_MAX, opt); > + > + if (tb[TCA_FQ_CODEL_LIMIT] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_LIMIT]) >=3D sizeof(__u32)) { > + limit =3D rta_getattr_u32(tb[TCA_FQ_CODEL_LIMIT]); > + fprintf(f, "limit %up ", limit); > + } > + if (tb[TCA_FQ_CODEL_FLOWS] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_FLOWS]) >=3D sizeof(__u32)) { > + flows =3D rta_getattr_u32(tb[TCA_FQ_CODEL_FLOWS]); > + fprintf(f, "flows %u ", flows); > + } > + if (tb[TCA_FQ_CODEL_QUANTUM] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_QUANTUM]) >=3D sizeof(__u32)) { > + quantum =3D rta_getattr_u32(tb[TCA_FQ_CODEL_QUANTUM]); > + fprintf(f, "quantum %u ", quantum); > + } > + if (tb[TCA_FQ_CODEL_TARGET] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_TARGET]) >=3D sizeof(__u32)) { > + target =3D rta_getattr_u32(tb[TCA_FQ_CODEL_TARGET]); > + fprintf(f, "target %s ", sprint_time(target, b1)); > + } > + if (tb[TCA_FQ_CODEL_INTERVAL] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_INTERVAL]) >=3D sizeof(__u32)) { > + interval =3D rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]); > + fprintf(f, "interval %s ", sprint_time(interval, b1)); > + } > + if (tb[TCA_FQ_CODEL_ECN] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >=3D sizeof(__u32)) { > + ecn =3D rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]); > + if (ecn) > + fprintf(f, "ecn "); > + } > + > + return 0; > +} > + > +static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, > + struct rtattr *xstats) > +{ > + struct tc_fq_codel_xstats *st; > + SPRINT_BUF(b1); > + > + if (xstats =3D=3D NULL) > + return 0; > + > + if (RTA_PAYLOAD(xstats) < sizeof(*st)) > + return -1; > + > + st =3D RTA_DATA(xstats); > + if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC) { > + fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u e= cn_mark %u", > + st->qdisc_stats.maxpacket, > + st->qdisc_stats.drop_overlimit, > + st->qdisc_stats.new_flow_count, > + st->qdisc_stats.ecn_mark); > + fprintf(f, "\n new_flows_len %u old_flows_len %u", > + st->qdisc_stats.new_flows_len, > + st->qdisc_stats.old_flows_len); > + } > + if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS) { > + fprintf(f, " deficit %d count %u lastcount %u ldelay %s", > + st->class_stats.deficit, > + st->class_stats.count, > + st->class_stats.lastcount, > + sprint_time(st->class_stats.ldelay, b1)); > + if (st->class_stats.dropping) { > + fprintf(f, " dropping"); > + if (st->class_stats.drop_next < 0) > + fprintf(f, " drop_next -%s", > + sprint_time(-st->class_stats.drop_next, b1)); > + else > + fprintf(f, " drop_next %s", > + sprint_time(st->class_stats.drop_next, b1)); > + } > + } > + return 0; > + > +} > + > +struct qdisc_util efq_codel_qdisc_util =3D { > + .id =3D "efq_codel", > + .parse_qopt =3D fq_codel_parse_opt, > + .print_qopt =3D fq_codel_print_opt, > + .print_xstats =3D fq_codel_print_xstats, > +}; > diff --git a/tc/q_nfq_codel.c b/tc/q_nfq_codel.c > new file mode 100644 > index 0000000..ef24909 > --- /dev/null > +++ b/tc/q_nfq_codel.c > @@ -0,0 +1,232 @@ > +/* > + * Fair Queue Codel > + * > + * Copyright (C) 2012 Eric Dumazet > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions, and the following disclaimer, > + * without modification. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in th= e > + * documentation and/or other materials provided with the distributio= n. > + * 3. The names of the authors may not be used to endorse or promote pro= ducts > + * derived from this software without specific prior written permissi= on. > + * > + * Alternatively, provided that this notice is retained in full, this > + * software may be distributed under the terms of the GNU General > + * Public License ("GPL") version 2, in which case the provisions of the > + * GPL apply INSTEAD OF those given above. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > + * DAMAGE. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "utils.h" > +#include "tc_util.h" > + > +static void explain(void) > +{ > + fprintf(stderr, "Usage: ... nfq_codel [ limit PACKETS ] [ flows NUMB= ER ]\n"); > + fprintf(stderr, " [ target TIME] [ interval TIME = ]\n"); > + fprintf(stderr, " [ quantum BYTES ] [ [no]ecn ]\n= "); > +} > + > +static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **ar= gv, > + struct nlmsghdr *n) > +{ > + unsigned limit =3D 0; > + unsigned flows =3D 0; > + unsigned target =3D 0; > + unsigned interval =3D 0; > + unsigned quantum =3D 0; > + int ecn =3D -1; > + struct rtattr *tail; > + > + while (argc > 0) { > + if (strcmp(*argv, "limit") =3D=3D 0) { > + NEXT_ARG(); > + if (get_unsigned(&limit, *argv, 0)) { > + fprintf(stderr, "Illegal \"limit\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "flows") =3D=3D 0) { > + NEXT_ARG(); > + if (get_unsigned(&flows, *argv, 0)) { > + fprintf(stderr, "Illegal \"flows\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "quantum") =3D=3D 0) { > + NEXT_ARG(); > + if (get_unsigned(&quantum, *argv, 0)) { > + fprintf(stderr, "Illegal \"quantum\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "target") =3D=3D 0) { > + NEXT_ARG(); > + if (get_time(&target, *argv)) { > + fprintf(stderr, "Illegal \"target\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "interval") =3D=3D 0) { > + NEXT_ARG(); > + if (get_time(&interval, *argv)) { > + fprintf(stderr, "Illegal \"interval\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "ecn") =3D=3D 0) { > + ecn =3D 1; > + } else if (strcmp(*argv, "noecn") =3D=3D 0) { > + ecn =3D 0; > + } else if (strcmp(*argv, "help") =3D=3D 0) { > + explain(); > + return -1; > + } else { > + fprintf(stderr, "What is \"%s\"?\n", *argv); > + explain(); > + return -1; > + } > + argc--; argv++; > + } > + > + tail =3D NLMSG_TAIL(n); > + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); > + if (limit) > + addattr_l(n, 1024, TCA_FQ_CODEL_LIMIT, &limit, sizeof(limit)); > + if (flows) > + addattr_l(n, 1024, TCA_FQ_CODEL_FLOWS, &flows, sizeof(flows)); > + if (quantum) > + addattr_l(n, 1024, TCA_FQ_CODEL_QUANTUM, &quantum, sizeof(quantu= m)); > + if (interval) > + addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(inte= rval)); > + if (target) > + addattr_l(n, 1024, TCA_FQ_CODEL_TARGET, &target, sizeof(target))= ; > + if (ecn !=3D -1) > + addattr_l(n, 1024, TCA_FQ_CODEL_ECN, &ecn, sizeof(ecn)); > + tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail; > + return 0; > +} > + > +static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rta= ttr *opt) > +{ > + struct rtattr *tb[TCA_FQ_CODEL_MAX + 1]; > + unsigned limit; > + unsigned flows; > + unsigned interval; > + unsigned target; > + unsigned ecn; > + unsigned quantum; > + SPRINT_BUF(b1); > + > + if (opt =3D=3D NULL) > + return 0; > + > + parse_rtattr_nested(tb, TCA_FQ_CODEL_MAX, opt); > + > + if (tb[TCA_FQ_CODEL_LIMIT] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_LIMIT]) >=3D sizeof(__u32)) { > + limit =3D rta_getattr_u32(tb[TCA_FQ_CODEL_LIMIT]); > + fprintf(f, "limit %up ", limit); > + } > + if (tb[TCA_FQ_CODEL_FLOWS] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_FLOWS]) >=3D sizeof(__u32)) { > + flows =3D rta_getattr_u32(tb[TCA_FQ_CODEL_FLOWS]); > + fprintf(f, "flows %u ", flows); > + } > + if (tb[TCA_FQ_CODEL_QUANTUM] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_QUANTUM]) >=3D sizeof(__u32)) { > + quantum =3D rta_getattr_u32(tb[TCA_FQ_CODEL_QUANTUM]); > + fprintf(f, "quantum %u ", quantum); > + } > + if (tb[TCA_FQ_CODEL_TARGET] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_TARGET]) >=3D sizeof(__u32)) { > + target =3D rta_getattr_u32(tb[TCA_FQ_CODEL_TARGET]); > + fprintf(f, "target %s ", sprint_time(target, b1)); > + } > + if (tb[TCA_FQ_CODEL_INTERVAL] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_INTERVAL]) >=3D sizeof(__u32)) { > + interval =3D rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]); > + fprintf(f, "interval %s ", sprint_time(interval, b1)); > + } > + if (tb[TCA_FQ_CODEL_ECN] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >=3D sizeof(__u32)) { > + ecn =3D rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]); > + if (ecn) > + fprintf(f, "ecn "); > + } > + > + return 0; > +} > + > +static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, > + struct rtattr *xstats) > +{ > + struct tc_fq_codel_xstats *st; > + SPRINT_BUF(b1); > + > + if (xstats =3D=3D NULL) > + return 0; > + > + if (RTA_PAYLOAD(xstats) < sizeof(*st)) > + return -1; > + > + st =3D RTA_DATA(xstats); > + if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC) { > + fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u e= cn_mark %u", > + st->qdisc_stats.maxpacket, > + st->qdisc_stats.drop_overlimit, > + st->qdisc_stats.new_flow_count, > + st->qdisc_stats.ecn_mark); > + fprintf(f, "\n new_flows_len %u old_flows_len %u", > + st->qdisc_stats.new_flows_len, > + st->qdisc_stats.old_flows_len); > + } > + if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS) { > + fprintf(f, " deficit %d count %u lastcount %u ldelay %s", > + st->class_stats.deficit, > + st->class_stats.count, > + st->class_stats.lastcount, > + sprint_time(st->class_stats.ldelay, b1)); > + if (st->class_stats.dropping) { > + fprintf(f, " dropping"); > + if (st->class_stats.drop_next < 0) > + fprintf(f, " drop_next -%s", > + sprint_time(-st->class_stats.drop_next, b1)); > + else > + fprintf(f, " drop_next %s", > + sprint_time(st->class_stats.drop_next, b1)); > + } > + } > + return 0; > + > +} > + > +struct qdisc_util nfq_codel_qdisc_util =3D { > + .id =3D "nfq_codel", > + .parse_qopt =3D fq_codel_parse_opt, > + .print_qopt =3D fq_codel_print_opt, > + .print_xstats =3D fq_codel_print_xstats, > +}; > diff --git a/tc/q_ns2_codel.c b/tc/q_ns2_codel.c > new file mode 100644 > index 0000000..223a971 > --- /dev/null > +++ b/tc/q_ns2_codel.c > @@ -0,0 +1,188 @@ > +/* > + * Codel - The Controlled-Delay Active Queue Management algorithm > + * > + * Copyright (C) 2011-2012 Kathleen Nichols > + * Copyright (C) 2011-2012 Van Jacobson > + * Copyright (C) 2012 Michael D. Taht > + * Copyright (C) 2012 Eric Dumazet > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions, and the following disclaimer, > + * without modification. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in th= e > + * documentation and/or other materials provided with the distributio= n. > + * 3. The names of the authors may not be used to endorse or promote pro= ducts > + * derived from this software without specific prior written permissi= on. > + * > + * Alternatively, provided that this notice is retained in full, this > + * software may be distributed under the terms of the GNU General > + * Public License ("GPL") version 2, in which case the provisions of the > + * GPL apply INSTEAD OF those given above. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > + * DAMAGE. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "utils.h" > +#include "tc_util.h" > + > +static void explain(void) > +{ > + fprintf(stderr, "Usage: ... ns2_codel [ limit PACKETS ] [ target TIM= E]\n"); > + fprintf(stderr, " [ interval TIME ] [ ecn | noecn ]\= n"); > +} > + > +static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, > + struct nlmsghdr *n) > +{ > + unsigned limit =3D 0; > + unsigned target =3D 0; > + unsigned interval =3D 0; > + int ecn =3D -1; > + struct rtattr *tail; > + > + while (argc > 0) { > + if (strcmp(*argv, "limit") =3D=3D 0) { > + NEXT_ARG(); > + if (get_unsigned(&limit, *argv, 0)) { > + fprintf(stderr, "Illegal \"limit\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "target") =3D=3D 0) { > + NEXT_ARG(); > + if (get_time(&target, *argv)) { > + fprintf(stderr, "Illegal \"target\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "interval") =3D=3D 0) { > + NEXT_ARG(); > + if (get_time(&interval, *argv)) { > + fprintf(stderr, "Illegal \"interval\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "ecn") =3D=3D 0) { > + ecn =3D 1; > + } else if (strcmp(*argv, "noecn") =3D=3D 0) { > + ecn =3D 0; > + } else if (strcmp(*argv, "help") =3D=3D 0) { > + explain(); > + return -1; > + } else { > + fprintf(stderr, "What is \"%s\"?\n", *argv); > + explain(); > + return -1; > + } > + argc--; argv++; > + } > + > + tail =3D NLMSG_TAIL(n); > + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); > + if (limit) > + addattr_l(n, 1024, TCA_CODEL_LIMIT, &limit, sizeof(limit)); > + if (interval) > + addattr_l(n, 1024, TCA_CODEL_INTERVAL, &interval, sizeof(interva= l)); > + if (target) > + addattr_l(n, 1024, TCA_CODEL_TARGET, &target, sizeof(target)); > + if (ecn !=3D -1) > + addattr_l(n, 1024, TCA_CODEL_ECN, &ecn, sizeof(ecn)); > + tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail; > + return 0; > +} > + > +static int codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr= *opt) > +{ > + struct rtattr *tb[TCA_CODEL_MAX + 1]; > + unsigned limit; > + unsigned interval; > + unsigned target; > + unsigned ecn; > + SPRINT_BUF(b1); > + > + if (opt =3D=3D NULL) > + return 0; > + > + parse_rtattr_nested(tb, TCA_CODEL_MAX, opt); > + > + if (tb[TCA_CODEL_LIMIT] && > + RTA_PAYLOAD(tb[TCA_CODEL_LIMIT]) >=3D sizeof(__u32)) { > + limit =3D rta_getattr_u32(tb[TCA_CODEL_LIMIT]); > + fprintf(f, "limit %up ", limit); > + } > + if (tb[TCA_CODEL_TARGET] && > + RTA_PAYLOAD(tb[TCA_CODEL_TARGET]) >=3D sizeof(__u32)) { > + target =3D rta_getattr_u32(tb[TCA_CODEL_TARGET]); > + fprintf(f, "target %s ", sprint_time(target, b1)); > + } > + if (tb[TCA_CODEL_INTERVAL] && > + RTA_PAYLOAD(tb[TCA_CODEL_INTERVAL]) >=3D sizeof(__u32)) { > + interval =3D rta_getattr_u32(tb[TCA_CODEL_INTERVAL]); > + fprintf(f, "interval %s ", sprint_time(interval, b1)); > + } > + if (tb[TCA_CODEL_ECN] && > + RTA_PAYLOAD(tb[TCA_CODEL_ECN]) >=3D sizeof(__u32)) { > + ecn =3D rta_getattr_u32(tb[TCA_CODEL_ECN]); > + if (ecn) > + fprintf(f, "ecn "); > + } > + > + return 0; > +} > + > +static int codel_print_xstats(struct qdisc_util *qu, FILE *f, > + struct rtattr *xstats) > +{ > + struct tc_codel_xstats *st; > + SPRINT_BUF(b1); > + > + if (xstats =3D=3D NULL) > + return 0; > + > + if (RTA_PAYLOAD(xstats) < sizeof(*st)) > + return -1; > + > + st =3D RTA_DATA(xstats); > + fprintf(f, " count %u lastcount %u ldelay %s", > + st->count, st->lastcount, sprint_time(st->ldelay, b1)); > + if (st->dropping) > + fprintf(f, " dropping"); > + if (st->drop_next < 0) > + fprintf(f, " drop_next -%s", sprint_time(-st->drop_next, b1)); > + else > + fprintf(f, " drop_next %s", sprint_time(st->drop_next, b1)); > + fprintf(f, "\n maxpacket %u ecn_mark %u drop_overlimit %u", > + st->maxpacket, st->ecn_mark, st->drop_overlimit); > + return 0; > + > +} > + > +struct qdisc_util ns2_codel_qdisc_util =3D { > + .id =3D "ns2_codel", > + .parse_qopt =3D codel_parse_opt, > + .print_qopt =3D codel_print_opt, > + .print_xstats =3D codel_print_xstats, > +}; > diff --git a/tc/q_ns4_codel.c b/tc/q_ns4_codel.c > new file mode 100644 > index 0000000..0aaa349 > --- /dev/null > +++ b/tc/q_ns4_codel.c > @@ -0,0 +1,188 @@ > +/* > + * Codel - The Controlled-Delay Active Queue Management algorithm > + * > + * Copyright (C) 2011-2012 Kathleen Nichols > + * Copyright (C) 2011-2012 Van Jacobson > + * Copyright (C) 2012 Michael D. Taht > + * Copyright (C) 2012 Eric Dumazet > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions, and the following disclaimer, > + * without modification. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in th= e > + * documentation and/or other materials provided with the distributio= n. > + * 3. The names of the authors may not be used to endorse or promote pro= ducts > + * derived from this software without specific prior written permissi= on. > + * > + * Alternatively, provided that this notice is retained in full, this > + * software may be distributed under the terms of the GNU General > + * Public License ("GPL") version 2, in which case the provisions of the > + * GPL apply INSTEAD OF those given above. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > + * DAMAGE. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "utils.h" > +#include "tc_util.h" > + > +static void explain(void) > +{ > + fprintf(stderr, "Usage: ... ns4_codel [ limit PACKETS ] [ target TIM= E]\n"); > + fprintf(stderr, " [ interval TIME ] [ ecn | noecn ]\= n"); > +} > + > +static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, > + struct nlmsghdr *n) > +{ > + unsigned limit =3D 0; > + unsigned target =3D 0; > + unsigned interval =3D 0; > + int ecn =3D -1; > + struct rtattr *tail; > + > + while (argc > 0) { > + if (strcmp(*argv, "limit") =3D=3D 0) { > + NEXT_ARG(); > + if (get_unsigned(&limit, *argv, 0)) { > + fprintf(stderr, "Illegal \"limit\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "target") =3D=3D 0) { > + NEXT_ARG(); > + if (get_time(&target, *argv)) { > + fprintf(stderr, "Illegal \"target\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "interval") =3D=3D 0) { > + NEXT_ARG(); > + if (get_time(&interval, *argv)) { > + fprintf(stderr, "Illegal \"interval\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "ecn") =3D=3D 0) { > + ecn =3D 1; > + } else if (strcmp(*argv, "noecn") =3D=3D 0) { > + ecn =3D 0; > + } else if (strcmp(*argv, "help") =3D=3D 0) { > + explain(); > + return -1; > + } else { > + fprintf(stderr, "What is \"%s\"?\n", *argv); > + explain(); > + return -1; > + } > + argc--; argv++; > + } > + > + tail =3D NLMSG_TAIL(n); > + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); > + if (limit) > + addattr_l(n, 1024, TCA_CODEL_LIMIT, &limit, sizeof(limit)); > + if (interval) > + addattr_l(n, 1024, TCA_CODEL_INTERVAL, &interval, sizeof(interva= l)); > + if (target) > + addattr_l(n, 1024, TCA_CODEL_TARGET, &target, sizeof(target)); > + if (ecn !=3D -1) > + addattr_l(n, 1024, TCA_CODEL_ECN, &ecn, sizeof(ecn)); > + tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail; > + return 0; > +} > + > +static int codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr= *opt) > +{ > + struct rtattr *tb[TCA_CODEL_MAX + 1]; > + unsigned limit; > + unsigned interval; > + unsigned target; > + unsigned ecn; > + SPRINT_BUF(b1); > + > + if (opt =3D=3D NULL) > + return 0; > + > + parse_rtattr_nested(tb, TCA_CODEL_MAX, opt); > + > + if (tb[TCA_CODEL_LIMIT] && > + RTA_PAYLOAD(tb[TCA_CODEL_LIMIT]) >=3D sizeof(__u32)) { > + limit =3D rta_getattr_u32(tb[TCA_CODEL_LIMIT]); > + fprintf(f, "limit %up ", limit); > + } > + if (tb[TCA_CODEL_TARGET] && > + RTA_PAYLOAD(tb[TCA_CODEL_TARGET]) >=3D sizeof(__u32)) { > + target =3D rta_getattr_u32(tb[TCA_CODEL_TARGET]); > + fprintf(f, "target %s ", sprint_time(target, b1)); > + } > + if (tb[TCA_CODEL_INTERVAL] && > + RTA_PAYLOAD(tb[TCA_CODEL_INTERVAL]) >=3D sizeof(__u32)) { > + interval =3D rta_getattr_u32(tb[TCA_CODEL_INTERVAL]); > + fprintf(f, "interval %s ", sprint_time(interval, b1)); > + } > + if (tb[TCA_CODEL_ECN] && > + RTA_PAYLOAD(tb[TCA_CODEL_ECN]) >=3D sizeof(__u32)) { > + ecn =3D rta_getattr_u32(tb[TCA_CODEL_ECN]); > + if (ecn) > + fprintf(f, "ecn "); > + } > + > + return 0; > +} > + > +static int codel_print_xstats(struct qdisc_util *qu, FILE *f, > + struct rtattr *xstats) > +{ > + struct tc_codel_xstats *st; > + SPRINT_BUF(b1); > + > + if (xstats =3D=3D NULL) > + return 0; > + > + if (RTA_PAYLOAD(xstats) < sizeof(*st)) > + return -1; > + > + st =3D RTA_DATA(xstats); > + fprintf(f, " count %u lastcount %u ldelay %s", > + st->count, st->lastcount, sprint_time(st->ldelay, b1)); > + if (st->dropping) > + fprintf(f, " dropping"); > + if (st->drop_next < 0) > + fprintf(f, " drop_next -%s", sprint_time(-st->drop_next, b1)); > + else > + fprintf(f, " drop_next %s", sprint_time(st->drop_next, b1)); > + fprintf(f, "\n maxpacket %u ecn_mark %u drop_overlimit %u", > + st->maxpacket, st->ecn_mark, st->drop_overlimit); > + return 0; > + > +} > + > +struct qdisc_util ns4_codel_qdisc_util =3D { > + .id =3D "ns4_codel", > + .parse_qopt =3D codel_parse_opt, > + .print_qopt =3D codel_print_opt, > + .print_xstats =3D codel_print_xstats, > +}; > diff --git a/tc/q_pfq_codel.c b/tc/q_pfq_codel.c > new file mode 100644 > index 0000000..52c5160 > --- /dev/null > +++ b/tc/q_pfq_codel.c > @@ -0,0 +1,232 @@ > +/* > + * Fair Queue Codel > + * > + * Copyright (C) 2012 Eric Dumazet > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions, and the following disclaimer, > + * without modification. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in th= e > + * documentation and/or other materials provided with the distributio= n. > + * 3. The names of the authors may not be used to endorse or promote pro= ducts > + * derived from this software without specific prior written permissi= on. > + * > + * Alternatively, provided that this notice is retained in full, this > + * software may be distributed under the terms of the GNU General > + * Public License ("GPL") version 2, in which case the provisions of the > + * GPL apply INSTEAD OF those given above. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > + * DAMAGE. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "utils.h" > +#include "tc_util.h" > + > +static void explain(void) > +{ > + fprintf(stderr, "Usage: ... pfq_codel [ limit PACKETS ] [ flows NUMB= ER ]\n"); > + fprintf(stderr, " [ target TIME] [ interval TIME = ]\n"); > + fprintf(stderr, " [ quantum BYTES ] [ [no]ecn ]\n= "); > +} > + > +static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **ar= gv, > + struct nlmsghdr *n) > +{ > + unsigned limit =3D 0; > + unsigned flows =3D 0; > + unsigned target =3D 0; > + unsigned interval =3D 0; > + unsigned quantum =3D 0; > + int ecn =3D -1; > + struct rtattr *tail; > + > + while (argc > 0) { > + if (strcmp(*argv, "limit") =3D=3D 0) { > + NEXT_ARG(); > + if (get_unsigned(&limit, *argv, 0)) { > + fprintf(stderr, "Illegal \"limit\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "flows") =3D=3D 0) { > + NEXT_ARG(); > + if (get_unsigned(&flows, *argv, 0)) { > + fprintf(stderr, "Illegal \"flows\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "quantum") =3D=3D 0) { > + NEXT_ARG(); > + if (get_unsigned(&quantum, *argv, 0)) { > + fprintf(stderr, "Illegal \"quantum\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "target") =3D=3D 0) { > + NEXT_ARG(); > + if (get_time(&target, *argv)) { > + fprintf(stderr, "Illegal \"target\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "interval") =3D=3D 0) { > + NEXT_ARG(); > + if (get_time(&interval, *argv)) { > + fprintf(stderr, "Illegal \"interval\"\n"); > + return -1; > + } > + } else if (strcmp(*argv, "ecn") =3D=3D 0) { > + ecn =3D 1; > + } else if (strcmp(*argv, "noecn") =3D=3D 0) { > + ecn =3D 0; > + } else if (strcmp(*argv, "help") =3D=3D 0) { > + explain(); > + return -1; > + } else { > + fprintf(stderr, "What is \"%s\"?\n", *argv); > + explain(); > + return -1; > + } > + argc--; argv++; > + } > + > + tail =3D NLMSG_TAIL(n); > + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); > + if (limit) > + addattr_l(n, 1024, TCA_FQ_CODEL_LIMIT, &limit, sizeof(limit)); > + if (flows) > + addattr_l(n, 1024, TCA_FQ_CODEL_FLOWS, &flows, sizeof(flows)); > + if (quantum) > + addattr_l(n, 1024, TCA_FQ_CODEL_QUANTUM, &quantum, sizeof(quantu= m)); > + if (interval) > + addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(inte= rval)); > + if (target) > + addattr_l(n, 1024, TCA_FQ_CODEL_TARGET, &target, sizeof(target))= ; > + if (ecn !=3D -1) > + addattr_l(n, 1024, TCA_FQ_CODEL_ECN, &ecn, sizeof(ecn)); > + tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail; > + return 0; > +} > + > +static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rta= ttr *opt) > +{ > + struct rtattr *tb[TCA_FQ_CODEL_MAX + 1]; > + unsigned limit; > + unsigned flows; > + unsigned interval; > + unsigned target; > + unsigned ecn; > + unsigned quantum; > + SPRINT_BUF(b1); > + > + if (opt =3D=3D NULL) > + return 0; > + > + parse_rtattr_nested(tb, TCA_FQ_CODEL_MAX, opt); > + > + if (tb[TCA_FQ_CODEL_LIMIT] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_LIMIT]) >=3D sizeof(__u32)) { > + limit =3D rta_getattr_u32(tb[TCA_FQ_CODEL_LIMIT]); > + fprintf(f, "limit %up ", limit); > + } > + if (tb[TCA_FQ_CODEL_FLOWS] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_FLOWS]) >=3D sizeof(__u32)) { > + flows =3D rta_getattr_u32(tb[TCA_FQ_CODEL_FLOWS]); > + fprintf(f, "flows %u ", flows); > + } > + if (tb[TCA_FQ_CODEL_QUANTUM] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_QUANTUM]) >=3D sizeof(__u32)) { > + quantum =3D rta_getattr_u32(tb[TCA_FQ_CODEL_QUANTUM]); > + fprintf(f, "quantum %u ", quantum); > + } > + if (tb[TCA_FQ_CODEL_TARGET] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_TARGET]) >=3D sizeof(__u32)) { > + target =3D rta_getattr_u32(tb[TCA_FQ_CODEL_TARGET]); > + fprintf(f, "target %s ", sprint_time(target, b1)); > + } > + if (tb[TCA_FQ_CODEL_INTERVAL] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_INTERVAL]) >=3D sizeof(__u32)) { > + interval =3D rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]); > + fprintf(f, "interval %s ", sprint_time(interval, b1)); > + } > + if (tb[TCA_FQ_CODEL_ECN] && > + RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >=3D sizeof(__u32)) { > + ecn =3D rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]); > + if (ecn) > + fprintf(f, "ecn "); > + } > + > + return 0; > +} > + > +static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, > + struct rtattr *xstats) > +{ > + struct tc_fq_codel_xstats *st; > + SPRINT_BUF(b1); > + > + if (xstats =3D=3D NULL) > + return 0; > + > + if (RTA_PAYLOAD(xstats) < sizeof(*st)) > + return -1; > + > + st =3D RTA_DATA(xstats); > + if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC) { > + fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u e= cn_mark %u", > + st->qdisc_stats.maxpacket, > + st->qdisc_stats.drop_overlimit, > + st->qdisc_stats.new_flow_count, > + st->qdisc_stats.ecn_mark); > + fprintf(f, "\n new_flows_len %u old_flows_len %u", > + st->qdisc_stats.new_flows_len, > + st->qdisc_stats.old_flows_len); > + } > + if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS) { > + fprintf(f, " deficit %d count %u lastcount %u ldelay %s", > + st->class_stats.deficit, > + st->class_stats.count, > + st->class_stats.lastcount, > + sprint_time(st->class_stats.ldelay, b1)); > + if (st->class_stats.dropping) { > + fprintf(f, " dropping"); > + if (st->class_stats.drop_next < 0) > + fprintf(f, " drop_next -%s", > + sprint_time(-st->class_stats.drop_next, b1)); > + else > + fprintf(f, " drop_next %s", > + sprint_time(st->class_stats.drop_next, b1)); > + } > + } > + return 0; > + > +} > + > +struct qdisc_util pfq_codel_qdisc_util =3D { > + .id =3D "pfq_codel", > + .parse_qopt =3D fq_codel_parse_opt, > + .print_qopt =3D fq_codel_print_opt, > + .print_xstats =3D fq_codel_print_xstats, > +}; > > 141-cake-add-support.patch > > > > > > > > --=20 Dave T=C3=A4ht Open Networking needs **Open Source Hardware** https://plus.google.com/u/0/+EricRaymond/posts/JqxCe2pFr67 --089e0112cb34d139f105151567ed Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
I had figured I could override the default iproute2 with t= he one in ceropackages with:

./scripts/feeds install -f -p cero ipro= ute2

But so far no luck. Tried removing and installing, no luck either. ?
<= br>
Aside from that I have kmod-sched-fq_pi= e and kmod-sched-cake building, at least, and everything
else wrapped up for a test build of chaos calmer with all= the new stuff.

Will try harder in the morning, brute forcing if I have to.
On Fri, M= ay 1, 2015 at 9:09 AM, Kevin Darbyshire-Bryant <kevin@darbyshi= re-bryant.me.uk> wrote:
=20 =20 =20
Hi Dave,

Forwarding to you in case it helps.=C2=A0 Replied to the list but my emails appear to stuck somewhere.

Kevin


-------- Forwarded Message --------
Subject: Re: [Cerowrt-devel] [Cake] documentation review request and out of tree cake builds for openwrt/etc.
Date: Fri, 01 May 2015 10:50:25 +0100
From: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
To: cerowrt-devel@lists.bufferbloat.net


On 30/04/2015 16:17, Dave Taht wrote:
> On Thu, Apr 30, 2015 at 7:38 AM, Jonathan Morton <chromatix99@gmail.com> wro=
te:
>> It took me a while to get around to thinking about this, partly be=
cause my
>> phone inexplicably refuses to believe snapon exists.
> It has an old dnssec signed dns tree, using the isc dlv, which turned
> out to somewhat break older versions of dnsmasq, if that helps any.
OpenWrt CC trunk is now up to dnsmasq2.73rc7 - the latest fix was for a dns=
sec fallback to tcp
problem.  Highly recommended.
> So the next step for me is to get cake working in openwrt on hardware =
fast enough to run at 110Mbit and returning to the yurtlab to try it... but=
 that won't be til sunday at best. Tho I almost got it built, at least,=
 last night. Still sorting through patches....
I have no idea if this will help you guys.  I was fiddling with getting cak=
e into CC a little earlier
based on the web page instructions.  My totally unsubtle approach was to ba=
sically copy over
relevant cerowrt-3.10 packages into the CC build tree:

ceropackages-3.10/net/sqm-scripts openwrt/package/feeds/packages/sqm-script=
s
ceropackages-3.10/net/kmod-sched-cake openwrt/feeds/packages/net/kmod-sched=
-cake *

ceropackages-3.10/luci/luci-app-sqm openwrt/package/feeds/packages/luci-app=
-sqm

iproute2 140&141 patches to openwrt/package/network/utils/iproute2/patc=
hes

You'll need to put a symlink from openwrt/package/feeds/packages/kmod-s=
ched-cake to
openwrt/feeds/packages/net/kmod-sched-cake

* note different directory!

Also to get iproute2 tc to understand cake I basically did a git diff on to=
ke's iproute-cake
vs iproute 4.0.0 which is where CC currently is:  Result 2 patches, 140 &am=
p; 141, 1st is to get
cake in, the 2nd is to do the required tc makefile tweak.  CC builds, runs =
on Archer C7,
nothing obviously exploded or broken...yet... your mileage may vary!  VERY =
VERY
UNTESTED, DRAGONS LURK, I'M AN IDIOT AND DON'T REALLY KNOW WHAT I&#=
39;M DOING.
Is that clear enough? :-)

Maybe it helps.  What I will say is that a dslreports test appears less jit=
tery for me.

Kevin



141-cake-disable-sfq-codel.patch

diff --git a/tc/Makefile b/tc/Makefile
index e503c8a..3dce533 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -61,7 +61,7 @@ TCMODULES +=3D q_codel.o
 TCMODULES +=3D q_fq_codel.o
 TCMODULES +=3D q_nfq_codel.o
 TCMODULES +=3D q_efq_codel.o
-TCMODULES +=3D q_sfq_codel.o
+#TCMODULES +=3D q_sfq_codel.o
 TCMODULES +=3D q_pfq_codel.o
 TCMODULES +=3D q_ns2_codel.o
 TCMODULES +=3D q_ns4_codel.o


140-cake-add-support.patch

diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index 534b847..a1d7b67 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -845,4 +845,38 @@ struct tc_pie_xstats {
     __u32 maxq;             /* maximum queue size */
     __u32 ecn_mark;         /* packets marked with ecn*/
 };
+
+/* CAKE */
+enum {
+    TCA_CAKE_UNSPEC,
+    TCA_CAKE_BASE_RATE,
+    TCA_CAKE_DIFFSERV_MODE,
+    TCA_CAKE_ATM,
+    TCA_CAKE_FLOW_MODE,
+    __TCA_CAKE_MAX
+};
+#define TCA_CAKE_MAX    (__TCA_CAKE_MAX - 1)
+
+struct tc_cake_xstats {
+    __u16 type;  /* constant magic 0xCAFE */
+    __u16 class_cnt;
+    struct {
+        __u32 rate;
+        __u32 target_us;
+        __u32 packets;
+        __u32 interval_us;
+        __u64 bytes;
+        __u32 dropped;
+        __u32 ecn_marked;
+        __u32 way_indirect_hits;
+        __u32 way_misses;
+        __u32 way_collisions;
+        __u32 backlog_bytes;
+        __u32 peak_delay; /* delay to fat flows */
+        __u32 avge_delay;
+        __u32 base_delay; /* delay to sparse flows */
+        __u32 dummy2;
+    } cls[8];
+};
+
 #endif
diff --git a/tc/Makefile b/tc/Makefile
index d831a15..e503c8a 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -59,8 +59,17 @@ TCMODULES +=3D em_meta.o
 TCMODULES +=3D q_mqprio.o
 TCMODULES +=3D q_codel.o
 TCMODULES +=3D q_fq_codel.o
+TCMODULES +=3D q_nfq_codel.o
+TCMODULES +=3D q_efq_codel.o
+TCMODULES +=3D q_sfq_codel.o
+TCMODULES +=3D q_pfq_codel.o
+TCMODULES +=3D q_ns2_codel.o
+TCMODULES +=3D q_ns4_codel.o
 TCMODULES +=3D q_fq.o
 TCMODULES +=3D q_pie.o
+TCMODULES +=3D q_cake.o
+TCMODULES +=3D q_cake0.o
+TCMODULES +=3D q_cake2.o
 TCMODULES +=3D q_hhf.o
=20
 ifeq ($(TC_CONFIG_IPSET), y)
diff --git a/tc/q_cake.c b/tc/q_cake.c
new file mode 100644
index 0000000..d9415d3
--- /dev/null
+++ b/tc/q_cake.c
@@ -0,0 +1,333 @@
+/*
+ * Common Applications Kept Enhanced  --  CAKE
+ *
+ *  Copyright (C) 2014-2015 Jonathan Morton <chromatix99@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote produ=
cts
+ *    derived from this software without specific prior written permission=
.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provision=
s of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT=
 NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+    fprintf(stderr, "Usage: ... cake [ bandwidth RATE | unlimited ]\n=
"
+                    "                [ besteffort | precedence | diff=
serv8 | diffserv4 ]\n"
+                    "                [ flowblind | srchost | dsthost =
| hosts | flows ]\n"
+                    "                [ atm ]\n");
+}
+
+static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+                  struct nlmsghdr *n)
+{
+    int unlimited =3D 0;
+    unsigned bandwidth =3D 0;
+    unsigned diffserv =3D 0;
+    int flowmode =3D -1;
+    int atm =3D -1;
+    struct rtattr *tail;
+
+    while (argc > 0) {
+        if (strcmp(*argv, "bandwidth") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_rate(&bandwidth, *argv)) {
+                fprintf(stderr, "Illegal \"bandwidth\"\n&qu=
ot;);
+                return -1;
+            }
+            unlimited =3D 0;
+        } else if (strcmp(*argv, "unlimited") =3D=3D 0) {
+            bandwidth =3D 0;
+            unlimited =3D 1;
+
+        } else if (strcmp(*argv, "besteffort") =3D=3D 0) {
+            diffserv =3D 1;
+        } else if (strcmp(*argv, "precedence") =3D=3D 0) {
+            diffserv =3D 2;
+        } else if (strcmp(*argv, "diffserv8") =3D=3D 0) {
+            diffserv =3D 3;
+        } else if (strcmp(*argv, "diffserv4") =3D=3D 0) {
+            diffserv =3D 4;
+        } else if (strcmp(*argv, "diffserv") =3D=3D 0) {
+            diffserv =3D 4;
+
+        } else if (strcmp(*argv, "flowblind") =3D=3D 0) {
+            flowmode =3D 0;
+        } else if (strcmp(*argv, "srchost") =3D=3D 0) {
+            flowmode =3D 1;
+        } else if (strcmp(*argv, "dsthost") =3D=3D 0) {
+            flowmode =3D 2;
+        } else if (strcmp(*argv, "hosts") =3D=3D 0) {
+            flowmode =3D 3;
+        } else if (strcmp(*argv, "flows") =3D=3D 0) {
+            flowmode =3D 4;
+
+        } else if (strcmp(*argv, "atm") =3D=3D 0) {
+            atm =3D 1;
+        } else if (strcmp(*argv, "noatm") =3D=3D 0) {
+            atm =3D 0;
+
+        } else if (strcmp(*argv, "help") =3D=3D 0) {
+            explain();
+            return -1;
+        } else {
+            fprintf(stderr, "What is \"%s\"?\n", *argv=
);
+            explain();
+            return -1;
+        }
+        argc--; argv++;
+    }
+
+    tail =3D NLMSG_TAIL(n);
+    addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+    if (bandwidth || unlimited)
+        addattr_l(n, 1024, TCA_CAKE_BASE_RATE, &bandwidth, sizeof(band=
width));
+    if (diffserv)
+        addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(d=
iffserv));
+    if (atm !=3D -1)
+        addattr_l(n, 1024, TCA_CAKE_ATM, &atm, sizeof(atm));
+    if (flowmode !=3D -1)
+        addattr_l(n, 1024, TCA_CAKE_FLOW_MODE, &flowmode, sizeof(flowm=
ode));
+    tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail;
+    return 0;
+}
+
+static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *o=
pt)
+{
+    struct rtattr *tb[TCA_CAKE_MAX + 1];
+    unsigned bandwidth =3D 0;
+    unsigned diffserv =3D 0;
+    unsigned flowmode =3D 0;
+    int atm =3D -1;
+    SPRINT_BUF(b1);
+
+    if (opt =3D=3D NULL)
+        return 0;
+
+    parse_rtattr_nested(tb, TCA_CAKE_MAX, opt);
+
+    if (tb[TCA_CAKE_BASE_RATE] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_BASE_RATE]) >=3D sizeof(__u32)) {
+        bandwidth =3D rta_getattr_u32(tb[TCA_CAKE_BASE_RATE]);
+        if(bandwidth)
+            fprintf(f, "bandwidth %s ", sprint_rate(bandwidth, b=
1));
+        else
+            fprintf(f, "unlimited ");
+    }
+    if (tb[TCA_CAKE_DIFFSERV_MODE] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_DIFFSERV_MODE]) >=3D sizeof(__u32)) {
+        diffserv =3D rta_getattr_u32(tb[TCA_CAKE_DIFFSERV_MODE]);
+        switch(diffserv) {
+        case 1:
+            fprintf(f, "besteffort ");
+            break;
+        case 2:
+            fprintf(f, "precedence ");
+            break;
+        case 3:
+            fprintf(f, "diffserv8 ");
+            break;
+        case 4:
+            fprintf(f, "diffserv4 ");
+            break;
+        default:
+            fprintf(f, "(?diffserv?) ");
+            break;
+        };
+    }
+    if (tb[TCA_CAKE_FLOW_MODE] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_FLOW_MODE]) >=3D sizeof(__u32)) {
+        flowmode =3D rta_getattr_u32(tb[TCA_CAKE_FLOW_MODE]);
+        switch(flowmode) {
+        case 0:
+            fprintf(f, "flowblind ");
+            break;
+        case 1:
+            fprintf(f, "srchost ");
+            break;
+        case 2:
+            fprintf(f, "dsthost ");
+            break;
+        case 3:
+            fprintf(f, "hosts ");
+            break;
+        case 4:
+            fprintf(f, "flows ");
+            break;
+        default:
+            fprintf(f, "(?flowmode?) ");
+            break;
+        };
+    }
+    if (tb[TCA_CAKE_ATM] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_ATM]) >=3D sizeof(__u32)) {
+        atm =3D rta_getattr_u32(tb[TCA_CAKE_ATM]);
+        if (atm)
+            fprintf(f, "atm ");
+    }
+
+    return 0;
+}
+
+static int cake_print_xstats(struct qdisc_util *qu, FILE *f,
+                 struct rtattr *xstats)
+{
+    /* fq_codel stats format borrowed */
+    struct tc_fq_codel_xstats *st;
+    struct tc_cake_xstats     *stc;
+    SPRINT_BUF(b1);
+
+    if (xstats =3D=3D NULL)
+        return 0;
+
+    if (RTA_PAYLOAD(xstats) < sizeof(st->type))
+        return -1;
+
+    st  =3D RTA_DATA(xstats);
+    stc =3D RTA_DATA(xstats);
+
+    if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC && RTA_PAYLOA=
D(xstats) >=3D sizeof(*st)) {
+        fprintf(f, "  maxpacket %u drop_overlimit %u new_flow_count %=
u ecn_mark %u",
+            st->qdisc_stats.maxpacket,
+            st->qdisc_stats.drop_overlimit,
+            st->qdisc_stats.new_flow_count,
+            st->qdisc_stats.ecn_mark);
+        fprintf(f, "\n  new_flows_len %u old_flows_len %u",
+            st->qdisc_stats.new_flows_len,
+            st->qdisc_stats.old_flows_len);
+    } else if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS && RTA=
_PAYLOAD(xstats) >=3D sizeof(*st)) {
+        fprintf(f, "  deficit %d count %u lastcount %u ldelay %s"=
;,
+            st->class_stats.deficit,
+            st->class_stats.count,
+            st->class_stats.lastcount,
+            sprint_time(st->class_stats.ldelay, b1));
+        if (st->class_stats.dropping) {
+            fprintf(f, " dropping");
+            if (st->class_stats.drop_next < 0)
+                fprintf(f, " drop_next -%s",
+                    sprint_time(-st->class_stats.drop_next, b1));
+            else
+                fprintf(f, " drop_next %s",
+                    sprint_time(st->class_stats.drop_next, b1));
+        }
+    } else if (stc->type =3D=3D 0xCAFE && RTA_PAYLOAD(xstats) &=
gt;=3D sizeof(*stc)) {
+        int i;
+
+        fprintf(f, "        ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "   Class %u  ", i);
+        fprintf(f, "\n");
+
+        fprintf(f, "  rate  ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12s", sprint_rate(stc->cls[i].rate, =
b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "  target");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12s", sprint_time(stc->cls[i].target=
_us, b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "interval");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12s", sprint_time(stc->cls[i].interv=
al_us, b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "Pk delay");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12s", sprint_time(stc->cls[i].peak_d=
elay, b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "Av delay");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12s", sprint_time(stc->cls[i].avge_d=
elay, b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "Sp delay");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12s", sprint_time(stc->cls[i].base_d=
elay, b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "  pkts  ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12u", stc->cls[i].packets);
+        fprintf(f, "\n");
+
+        fprintf(f, "way inds");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12u", stc->cls[i].way_indirect_hits)=
;
+        fprintf(f, "\n");
+
+        fprintf(f, "way miss");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12u", stc->cls[i].way_misses);
+        fprintf(f, "\n");
+
+        fprintf(f, "way cols");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12u", stc->cls[i].way_collisions);
+        fprintf(f, "\n");
+
+        fprintf(f, "  bytes ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12llu", stc->cls[i].bytes);
+        fprintf(f, "\n");
+
+        fprintf(f, "  drops ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12u", stc->cls[i].dropped);
+        fprintf(f, "\n");
+
+        fprintf(f, "  marks ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%12u", stc->cls[i].ecn_marked);
+    } else {
+        return -1;
+    }
+    return 0;
+}
+
+struct qdisc_util cake_qdisc_util =3D {
+    .id        =3D "cake",
+    .parse_qopt    =3D cake_parse_opt,
+    .print_qopt    =3D cake_print_opt,
+    .print_xstats    =3D cake_print_xstats,
+};
diff --git a/tc/q_cake0.c b/tc/q_cake0.c
new file mode 100644
index 0000000..9fb63ed
--- /dev/null
+++ b/tc/q_cake0.c
@@ -0,0 +1,301 @@
+/*
+ * Common Applications Kept Enhanced  --  CAKE
+ *
+ *  Copyright (C) 2014 Jonathan Morton <chromatix99@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote produ=
cts
+ *    derived from this software without specific prior written permission=
.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provision=
s of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT=
 NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+    fprintf(stderr, "Usage: ... cake0 [ bandwidth RATE | unlimited ]\=
n"
+                    "                 [ besteffort | precedence | dif=
fserv ]\n"
+                    "                 [ flowblind | srchost | dsthost=
 | hosts | flows ]\n"
+                    "                 [ atm ]\n");
+}
+
+static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+                  struct nlmsghdr *n)
+{
+    int unlimited =3D 0;
+    unsigned bandwidth =3D 0;
+    unsigned diffserv =3D 0;
+    int flowmode =3D -1;
+    int atm =3D -1;
+    struct rtattr *tail;
+
+    while (argc > 0) {
+        if (strcmp(*argv, "bandwidth") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_rate(&bandwidth, *argv)) {
+                fprintf(stderr, "Illegal \"bandwidth\"\n&qu=
ot;);
+                return -1;
+            }
+            unlimited =3D 0;
+        } else if (strcmp(*argv, "unlimited") =3D=3D 0) {
+            bandwidth =3D 0;
+            unlimited =3D 1;
+
+        } else if (strcmp(*argv, "besteffort") =3D=3D 0) {
+            diffserv =3D 1;
+        } else if (strcmp(*argv, "precedence") =3D=3D 0) {
+            diffserv =3D 2;
+        } else if (strcmp(*argv, "diffserv") =3D=3D 0) {
+            diffserv =3D 3;
+
+        } else if (strcmp(*argv, "flowblind") =3D=3D 0) {
+            flowmode =3D 0;
+        } else if (strcmp(*argv, "srchost") =3D=3D 0) {
+            flowmode =3D 1;
+        } else if (strcmp(*argv, "dsthost") =3D=3D 0) {
+            flowmode =3D 2;
+        } else if (strcmp(*argv, "hosts") =3D=3D 0) {
+            flowmode =3D 3;
+        } else if (strcmp(*argv, "flows") =3D=3D 0) {
+            flowmode =3D 4;
+
+        } else if (strcmp(*argv, "atm") =3D=3D 0) {
+            atm =3D 1;
+        } else if (strcmp(*argv, "noatm") =3D=3D 0) {
+            atm =3D 0;
+
+        } else if (strcmp(*argv, "help") =3D=3D 0) {
+            explain();
+            return -1;
+        } else {
+            fprintf(stderr, "What is \"%s\"?\n", *argv=
);
+            explain();
+            return -1;
+        }
+        argc--; argv++;
+    }
+
+    tail =3D NLMSG_TAIL(n);
+    addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+    if (bandwidth || unlimited)
+        addattr_l(n, 1024, TCA_CAKE_BASE_RATE, &bandwidth, sizeof(band=
width));
+    if (diffserv)
+        addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(d=
iffserv));
+    if (atm !=3D -1)
+        addattr_l(n, 1024, TCA_CAKE_ATM, &atm, sizeof(atm));
+    if (flowmode !=3D -1)
+        addattr_l(n, 1024, TCA_CAKE_FLOW_MODE, &flowmode, sizeof(flowm=
ode));
+    tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail;
+    return 0;
+}
+
+static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *o=
pt)
+{
+    struct rtattr *tb[TCA_CAKE_MAX + 1];
+    unsigned bandwidth =3D 0;
+    unsigned diffserv =3D 0;
+    unsigned flowmode =3D 0;
+    int atm =3D -1;
+    SPRINT_BUF(b1);
+
+    if (opt =3D=3D NULL)
+        return 0;
+
+    parse_rtattr_nested(tb, TCA_CAKE_MAX, opt);
+
+    if (tb[TCA_CAKE_BASE_RATE] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_BASE_RATE]) >=3D sizeof(__u32)) {
+        bandwidth =3D rta_getattr_u32(tb[TCA_CAKE_BASE_RATE]);
+        if(bandwidth)
+            fprintf(f, "bandwidth %s ", sprint_rate(bandwidth, b=
1));
+        else
+            fprintf(f, "unlimited");
+    }
+    if (tb[TCA_CAKE_DIFFSERV_MODE] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_DIFFSERV_MODE]) >=3D sizeof(__u32)) {
+        diffserv =3D rta_getattr_u32(tb[TCA_CAKE_DIFFSERV_MODE]);
+        switch(diffserv) {
+        case 1:
+            fprintf(f, "besteffort ");
+            break;
+        case 2:
+            fprintf(f, "precedence ");
+            break;
+        case 3:
+            fprintf(f, "diffserv ");
+            break;
+        default:
+            fprintf(f, "(?diffserv?) ");
+            break;
+        };
+    }
+    if (tb[TCA_CAKE_FLOW_MODE] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_FLOW_MODE]) >=3D sizeof(__u32)) {
+        flowmode =3D rta_getattr_u32(tb[TCA_CAKE_FLOW_MODE]);
+        switch(flowmode) {
+        case 0:
+            fprintf(f, "flowblind ");
+            break;
+        case 1:
+            fprintf(f, "srchost ");
+            break;
+        case 2:
+            fprintf(f, "dsthost ");
+            break;
+        case 3:
+            fprintf(f, "hosts ");
+            break;
+        case 4:
+            fprintf(f, "flows ");
+            break;
+        default:
+            fprintf(f, "(?flowmode?) ");
+            break;
+        };
+    }
+    if (tb[TCA_CAKE_ATM] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_ATM]) >=3D sizeof(__u32)) {
+        atm =3D rta_getattr_u32(tb[TCA_CAKE_ATM]);
+        if (atm)
+            fprintf(f, "atm ");
+    }
+
+    return 0;
+}
+
+static int cake_print_xstats(struct qdisc_util *qu, FILE *f,
+                 struct rtattr *xstats)
+{
+    /* fq_codel stats format borrowed */
+    struct tc_fq_codel_xstats *st;
+    struct tc_cake_xstats     *stc;
+    SPRINT_BUF(b1);
+
+    if (xstats =3D=3D NULL)
+        return 0;
+
+    if (RTA_PAYLOAD(xstats) < sizeof(st->type))
+        return -1;
+
+    st  =3D RTA_DATA(xstats);
+    stc =3D RTA_DATA(xstats);
+
+    if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC && RTA_PAYLOA=
D(xstats) >=3D sizeof(*st)) {
+        fprintf(f, "  maxpacket %u drop_overlimit %u new_flow_count %=
u ecn_mark %u",
+            st->qdisc_stats.maxpacket,
+            st->qdisc_stats.drop_overlimit,
+            st->qdisc_stats.new_flow_count,
+            st->qdisc_stats.ecn_mark);
+        fprintf(f, "\n  new_flows_len %u old_flows_len %u",
+            st->qdisc_stats.new_flows_len,
+            st->qdisc_stats.old_flows_len);
+    } else if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS && RTA=
_PAYLOAD(xstats) >=3D sizeof(*st)) {
+        fprintf(f, "  deficit %d count %u lastcount %u ldelay %s"=
;,
+            st->class_stats.deficit,
+            st->class_stats.count,
+            st->class_stats.lastcount,
+            sprint_time(st->class_stats.ldelay, b1));
+        if (st->class_stats.dropping) {
+            fprintf(f, " dropping");
+            if (st->class_stats.drop_next < 0)
+                fprintf(f, " drop_next -%s",
+                    sprint_time(-st->class_stats.drop_next, b1));
+            else
+                fprintf(f, " drop_next %s",
+                    sprint_time(st->class_stats.drop_next, b1));
+        }
+    } else if (stc->type =3D=3D 0xCAFE && RTA_PAYLOAD(xstats) &=
gt;=3D sizeof(*stc)) {
+        int i;
+
+        fprintf(f, "        ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "  Class %u ", i);
+        fprintf(f, "\n");
+
+        fprintf(f, "  rate  ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10s", sprint_rate(stc->cls[i].rate, =
b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "  target");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10s", sprint_time(stc->cls[i].target=
_us, b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "interval");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10s", sprint_time(stc->cls[i].interv=
al_us, b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "  delay ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10s", sprint_time(stc->cls[i].peak_d=
elay, b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "  pkts  ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10u", stc->cls[i].packets);
+        fprintf(f, "\n");
+
+        fprintf(f, "  bytes ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10llu", stc->cls[i].bytes);
+        fprintf(f, "\n");
+
+        fprintf(f, "  drops ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10u", stc->cls[i].dropped);
+        fprintf(f, "\n");
+
+        fprintf(f, "  marks ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10u", stc->cls[i].ecn_marked);
+    } else {
+        return -1;
+    }
+    return 0;
+}
+
+struct qdisc_util cake0_qdisc_util =3D {
+    .id        =3D "cake0",
+    .parse_qopt    =3D cake_parse_opt,
+    .print_qopt    =3D cake_print_opt,
+    .print_xstats    =3D cake_print_xstats,
+};
diff --git a/tc/q_cake2.c b/tc/q_cake2.c
new file mode 100644
index 0000000..a4d3f7c
--- /dev/null
+++ b/tc/q_cake2.c
@@ -0,0 +1,296 @@
+/*
+ * Common Applications Kept Enhanced  --  CAKE
+ *
+ *  Copyright (C) 2014 Jonathan Morton <chromatix99@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote produ=
cts
+ *    derived from this software without specific prior written permission=
.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provision=
s of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT=
 NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+    fprintf(stderr, "Usage: ... cake2 [ bandwidth RATE | unlimited ]\=
n"
+                    "                [ besteffort | precedence | diff=
serv ]\n"
+                    "                [ flowblind | srchost | dsthost =
| hosts | flows ]\n"
+                    "                [ atm ]\n");
+}
+
+static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+                  struct nlmsghdr *n)
+{
+    int unlimited =3D 0;
+    unsigned bandwidth =3D 0;
+    unsigned diffserv =3D 0;
+    int flowmode =3D -1;
+    int atm =3D -1;
+    struct rtattr *tail;
+
+    while (argc > 0) {
+        if (strcmp(*argv, "bandwidth") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_rate(&bandwidth, *argv)) {
+                fprintf(stderr, "Illegal \"bandwidth\"\n&qu=
ot;);
+                return -1;
+            }
+            unlimited =3D 0;
+        } else if (strcmp(*argv, "unlimited") =3D=3D 0) {
+            bandwidth =3D 0;
+            unlimited =3D 1;
+
+        } else if (strcmp(*argv, "besteffort") =3D=3D 0) {
+            diffserv =3D 1;
+        } else if (strcmp(*argv, "precedence") =3D=3D 0) {
+            diffserv =3D 2;
+        } else if (strcmp(*argv, "diffserv") =3D=3D 0) {
+            diffserv =3D 3;
+
+        } else if (strcmp(*argv, "flowblind") =3D=3D 0) {
+            flowmode =3D 0;
+        } else if (strcmp(*argv, "srchost") =3D=3D 0) {
+            flowmode =3D 1;
+        } else if (strcmp(*argv, "dsthost") =3D=3D 0) {
+            flowmode =3D 2;
+        } else if (strcmp(*argv, "hosts") =3D=3D 0) {
+            flowmode =3D 3;
+        } else if (strcmp(*argv, "flows") =3D=3D 0) {
+            flowmode =3D 4;
+
+        } else if (strcmp(*argv, "atm") =3D=3D 0) {
+            atm =3D 1;
+        } else if (strcmp(*argv, "noatm") =3D=3D 0) {
+            atm =3D 0;
+
+        } else if (strcmp(*argv, "help") =3D=3D 0) {
+            explain();
+            return -1;
+        } else {
+            fprintf(stderr, "What is \"%s\"?\n", *argv=
);
+            explain();
+            return -1;
+        }
+        argc--; argv++;
+    }
+
+    tail =3D NLMSG_TAIL(n);
+    addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+    if (bandwidth || unlimited)
+        addattr_l(n, 1024, TCA_CAKE_BASE_RATE, &bandwidth, sizeof(band=
width));
+    if (diffserv)
+        addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(d=
iffserv));
+    if (atm !=3D -1)
+        addattr_l(n, 1024, TCA_CAKE_ATM, &atm, sizeof(atm));
+    if (flowmode !=3D -1)
+        addattr_l(n, 1024, TCA_CAKE_FLOW_MODE, &flowmode, sizeof(flowm=
ode));
+    tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail;
+    return 0;
+}
+
+static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *o=
pt)
+{
+    struct rtattr *tb[TCA_CAKE_MAX + 1];
+    unsigned bandwidth =3D 0;
+    unsigned diffserv =3D 0;
+    unsigned flowmode =3D 0;
+    int atm =3D -1;
+    SPRINT_BUF(b1);
+
+    if (opt =3D=3D NULL)
+        return 0;
+
+    parse_rtattr_nested(tb, TCA_CAKE_MAX, opt);
+
+    if (tb[TCA_CAKE_BASE_RATE] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_BASE_RATE]) >=3D sizeof(__u32)) {
+        bandwidth =3D rta_getattr_u32(tb[TCA_CAKE_BASE_RATE]);
+        if(bandwidth)
+            fprintf(f, "bandwidth %s ", sprint_rate(bandwidth, b=
1));
+        else
+            fprintf(f, "unlimited");
+    }
+    if (tb[TCA_CAKE_DIFFSERV_MODE] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_DIFFSERV_MODE]) >=3D sizeof(__u32)) {
+        diffserv =3D rta_getattr_u32(tb[TCA_CAKE_DIFFSERV_MODE]);
+        switch(diffserv) {
+        case 1:
+            fprintf(f, "besteffort ");
+            break;
+        case 2:
+            fprintf(f, "precedence ");
+            break;
+        case 3:
+            fprintf(f, "diffserv ");
+            break;
+        default:
+            fprintf(f, "(?diffserv?) ");
+            break;
+        };
+    }
+    if (tb[TCA_CAKE_FLOW_MODE] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_FLOW_MODE]) >=3D sizeof(__u32)) {
+        flowmode =3D rta_getattr_u32(tb[TCA_CAKE_FLOW_MODE]);
+        switch(flowmode) {
+        case 0:
+            fprintf(f, "flowblind ");
+            break;
+        case 1:
+            fprintf(f, "srchost ");
+            break;
+        case 2:
+            fprintf(f, "dsthost ");
+            break;
+        case 3:
+            fprintf(f, "hosts ");
+            break;
+        case 4:
+            fprintf(f, "flows ");
+            break;
+        default:
+            fprintf(f, "(?flowmode?) ");
+            break;
+        };
+    }
+    if (tb[TCA_CAKE_ATM] &&
+        RTA_PAYLOAD(tb[TCA_CAKE_ATM]) >=3D sizeof(__u32)) {
+        atm =3D rta_getattr_u32(tb[TCA_CAKE_ATM]);
+        if (atm)
+            fprintf(f, "atm ");
+    }
+
+    return 0;
+}
+
+static int cake_print_xstats(struct qdisc_util *qu, FILE *f,
+                 struct rtattr *xstats)
+{
+    /* fq_codel stats format borrowed */
+    struct tc_fq_codel_xstats *st;
+    struct tc_cake_xstats     *stc;
+    SPRINT_BUF(b1);
+
+    if (xstats =3D=3D NULL)
+        return 0;
+
+    if (RTA_PAYLOAD(xstats) < sizeof(st->type))
+        return -1;
+
+    st  =3D RTA_DATA(xstats);
+    stc =3D RTA_DATA(xstats);
+
+    if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC && RTA_PAYLOA=
D(xstats) >=3D sizeof(*st)) {
+        fprintf(f, "  maxpacket %u drop_overlimit %u new_flow_count %=
u ecn_mark %u",
+            st->qdisc_stats.maxpacket,
+            st->qdisc_stats.drop_overlimit,
+            st->qdisc_stats.new_flow_count,
+            st->qdisc_stats.ecn_mark);
+        fprintf(f, "\n  new_flows_len %u old_flows_len %u",
+            st->qdisc_stats.new_flows_len,
+            st->qdisc_stats.old_flows_len);
+    } else if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS && RTA=
_PAYLOAD(xstats) >=3D sizeof(*st)) {
+        fprintf(f, "  deficit %d count %u lastcount %u ldelay %s"=
;,
+            st->class_stats.deficit,
+            st->class_stats.count,
+            st->class_stats.lastcount,
+            sprint_time(st->class_stats.ldelay, b1));
+        if (st->class_stats.dropping) {
+            fprintf(f, " dropping");
+            if (st->class_stats.drop_next < 0)
+                fprintf(f, " drop_next -%s",
+                    sprint_time(-st->class_stats.drop_next, b1));
+            else
+                fprintf(f, " drop_next %s",
+                    sprint_time(st->class_stats.drop_next, b1));
+        }
+    } else if (stc->type =3D=3D 0xCAFE && RTA_PAYLOAD(xstats) &=
gt;=3D sizeof(*stc)) {
+        int i;
+
+        fprintf(f, "        ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "  Class %u ", i);
+        fprintf(f, "\n");
+
+        fprintf(f, "  rate  ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10s", sprint_rate(stc->cls[i].rate, =
b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "  target");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10s", sprint_time(stc->cls[i].target=
_us, b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "interval");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10s", sprint_time(stc->cls[i].interv=
al_us, b1));
+        fprintf(f, "\n");
+
+        fprintf(f, "  pkts  ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10u", stc->cls[i].packets);
+        fprintf(f, "\n");
+
+        fprintf(f, "  bytes ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10llu", stc->cls[i].bytes);
+        fprintf(f, "\n");
+
+        fprintf(f, "  drops ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10u", stc->cls[i].dropped);
+        fprintf(f, "\n");
+
+        fprintf(f, "  marks ");
+        for(i=3D0; i < stc->class_cnt; i++)
+            fprintf(f, "%10u", stc->cls[i].ecn_marked);
+    } else {
+        return -1;
+    }
+    return 0;
+}
+
+struct qdisc_util cake2_qdisc_util =3D {
+    .id        =3D "cake2",
+    .parse_qopt    =3D cake_parse_opt,
+    .print_qopt    =3D cake_print_opt,
+    .print_xstats    =3D cake_print_xstats,
+};
diff --git a/tc/q_efq_codel.c b/tc/q_efq_codel.c
new file mode 100644
index 0000000..b80e5e4
--- /dev/null
+++ b/tc/q_efq_codel.c
@@ -0,0 +1,232 @@
+/*
+ * Fair Queue Codel
+ *
+ *  Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote produ=
cts
+ *    derived from this software without specific prior written permission=
.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provision=
s of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT=
 NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+    fprintf(stderr, "Usage: ... efq_codel [ limit PACKETS ] [ flows N=
UMBER ]\n");
+    fprintf(stderr, "                    [ target TIME] [ interval TI=
ME ]\n");
+    fprintf(stderr, "                    [ quantum BYTES ] [ [no]ecn =
]\n");
+}
+
+static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv=
,
+                  struct nlmsghdr *n)
+{
+    unsigned limit =3D 0;
+    unsigned flows =3D 0;
+    unsigned target =3D 0;
+    unsigned interval =3D 0;
+    unsigned quantum =3D 0;
+    int ecn =3D -1;
+    struct rtattr *tail;
+
+    while (argc > 0) {
+        if (strcmp(*argv, "limit") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_unsigned(&limit, *argv, 0)) {
+                fprintf(stderr, "Illegal \"limit\"\n")=
;
+                return -1;
+            }
+        } else if (strcmp(*argv, "flows") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_unsigned(&flows, *argv, 0)) {
+                fprintf(stderr, "Illegal \"flows\"\n")=
;
+                return -1;
+            }
+        } else if (strcmp(*argv, "quantum") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_unsigned(&quantum, *argv, 0)) {
+                fprintf(stderr, "Illegal \"quantum\"\n"=
;);
+                return -1;
+            }
+        } else if (strcmp(*argv, "target") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_time(&target, *argv)) {
+                fprintf(stderr, "Illegal \"target\"\n"=
);
+                return -1;
+            }
+        } else if (strcmp(*argv, "interval") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_time(&interval, *argv)) {
+                fprintf(stderr, "Illegal \"interval\"\n&quo=
t;);
+                return -1;
+            }
+        } else if (strcmp(*argv, "ecn") =3D=3D 0) {
+            ecn =3D 1;
+        } else if (strcmp(*argv, "noecn") =3D=3D 0) {
+            ecn =3D 0;
+        } else if (strcmp(*argv, "help") =3D=3D 0) {
+            explain();
+            return -1;
+        } else {
+            fprintf(stderr, "What is \"%s\"?\n", *argv=
);
+            explain();
+            return -1;
+        }
+        argc--; argv++;
+    }
+
+    tail =3D NLMSG_TAIL(n);
+    addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+    if (limit)
+        addattr_l(n, 1024, TCA_FQ_CODEL_LIMIT, &limit, sizeof(limit));
+    if (flows)
+        addattr_l(n, 1024, TCA_FQ_CODEL_FLOWS, &flows, sizeof(flows));
+    if (quantum)
+        addattr_l(n, 1024, TCA_FQ_CODEL_QUANTUM, &quantum, sizeof(quan=
tum));
+    if (interval)
+        addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(in=
terval));
+    if (target)
+        addattr_l(n, 1024, TCA_FQ_CODEL_TARGET, &target, sizeof(target=
));
+    if (ecn !=3D -1)
+        addattr_l(n, 1024, TCA_FQ_CODEL_ECN, &ecn, sizeof(ecn));
+    tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail;
+    return 0;
+}
+
+static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtatt=
r *opt)
+{
+    struct rtattr *tb[TCA_FQ_CODEL_MAX + 1];
+    unsigned limit;
+    unsigned flows;
+    unsigned interval;
+    unsigned target;
+    unsigned ecn;
+    unsigned quantum;
+    SPRINT_BUF(b1);
+
+    if (opt =3D=3D NULL)
+        return 0;
+
+    parse_rtattr_nested(tb, TCA_FQ_CODEL_MAX, opt);
+
+    if (tb[TCA_FQ_CODEL_LIMIT] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_LIMIT]) >=3D sizeof(__u32)) {
+        limit =3D rta_getattr_u32(tb[TCA_FQ_CODEL_LIMIT]);
+        fprintf(f, "limit %up ", limit);
+    }
+    if (tb[TCA_FQ_CODEL_FLOWS] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_FLOWS]) >=3D sizeof(__u32)) {
+        flows =3D rta_getattr_u32(tb[TCA_FQ_CODEL_FLOWS]);
+        fprintf(f, "flows %u ", flows);
+    }
+    if (tb[TCA_FQ_CODEL_QUANTUM] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_QUANTUM]) >=3D sizeof(__u32)) {
+        quantum =3D rta_getattr_u32(tb[TCA_FQ_CODEL_QUANTUM]);
+        fprintf(f, "quantum %u ", quantum);
+    }
+    if (tb[TCA_FQ_CODEL_TARGET] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_TARGET]) >=3D sizeof(__u32)) {
+        target =3D rta_getattr_u32(tb[TCA_FQ_CODEL_TARGET]);
+        fprintf(f, "target %s ", sprint_time(target, b1));
+    }
+    if (tb[TCA_FQ_CODEL_INTERVAL] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_INTERVAL]) >=3D sizeof(__u32)) {
+        interval =3D rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]);
+        fprintf(f, "interval %s ", sprint_time(interval, b1));
+    }
+    if (tb[TCA_FQ_CODEL_ECN] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >=3D sizeof(__u32)) {
+        ecn =3D rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]);
+        if (ecn)
+            fprintf(f, "ecn ");
+    }
+
+    return 0;
+}
+
+static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f,
+                 struct rtattr *xstats)
+{
+    struct tc_fq_codel_xstats *st;
+    SPRINT_BUF(b1);
+
+    if (xstats =3D=3D NULL)
+        return 0;
+
+    if (RTA_PAYLOAD(xstats) < sizeof(*st))
+        return -1;
+
+    st =3D RTA_DATA(xstats);
+    if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC) {
+        fprintf(f, "  maxpacket %u drop_overlimit %u new_flow_count %=
u ecn_mark %u",
+            st->qdisc_stats.maxpacket,
+            st->qdisc_stats.drop_overlimit,
+            st->qdisc_stats.new_flow_count,
+            st->qdisc_stats.ecn_mark);
+        fprintf(f, "\n  new_flows_len %u old_flows_len %u",
+            st->qdisc_stats.new_flows_len,
+            st->qdisc_stats.old_flows_len);
+    }
+    if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS) {
+        fprintf(f, "  deficit %d count %u lastcount %u ldelay %s"=
;,
+            st->class_stats.deficit,
+            st->class_stats.count,
+            st->class_stats.lastcount,
+            sprint_time(st->class_stats.ldelay, b1));
+        if (st->class_stats.dropping) {
+            fprintf(f, " dropping");
+            if (st->class_stats.drop_next < 0)
+                fprintf(f, " drop_next -%s",
+                    sprint_time(-st->class_stats.drop_next, b1));
+            else
+                fprintf(f, " drop_next %s",
+                    sprint_time(st->class_stats.drop_next, b1));
+        }
+    }
+    return 0;
+
+}
+
+struct qdisc_util efq_codel_qdisc_util =3D {
+    .id        =3D "efq_codel",
+    .parse_qopt    =3D fq_codel_parse_opt,
+    .print_qopt    =3D fq_codel_print_opt,
+    .print_xstats    =3D fq_codel_print_xstats,
+};
diff --git a/tc/q_nfq_codel.c b/tc/q_nfq_codel.c
new file mode 100644
index 0000000..ef24909
--- /dev/null
+++ b/tc/q_nfq_codel.c
@@ -0,0 +1,232 @@
+/*
+ * Fair Queue Codel
+ *
+ *  Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote produ=
cts
+ *    derived from this software without specific prior written permission=
.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provision=
s of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT=
 NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+    fprintf(stderr, "Usage: ... nfq_codel [ limit PACKETS ] [ flows N=
UMBER ]\n");
+    fprintf(stderr, "                    [ target TIME] [ interval TI=
ME ]\n");
+    fprintf(stderr, "                    [ quantum BYTES ] [ [no]ecn =
]\n");
+}
+
+static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv=
,
+                  struct nlmsghdr *n)
+{
+    unsigned limit =3D 0;
+    unsigned flows =3D 0;
+    unsigned target =3D 0;
+    unsigned interval =3D 0;
+    unsigned quantum =3D 0;
+    int ecn =3D -1;
+    struct rtattr *tail;
+
+    while (argc > 0) {
+        if (strcmp(*argv, "limit") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_unsigned(&limit, *argv, 0)) {
+                fprintf(stderr, "Illegal \"limit\"\n")=
;
+                return -1;
+            }
+        } else if (strcmp(*argv, "flows") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_unsigned(&flows, *argv, 0)) {
+                fprintf(stderr, "Illegal \"flows\"\n")=
;
+                return -1;
+            }
+        } else if (strcmp(*argv, "quantum") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_unsigned(&quantum, *argv, 0)) {
+                fprintf(stderr, "Illegal \"quantum\"\n"=
;);
+                return -1;
+            }
+        } else if (strcmp(*argv, "target") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_time(&target, *argv)) {
+                fprintf(stderr, "Illegal \"target\"\n"=
);
+                return -1;
+            }
+        } else if (strcmp(*argv, "interval") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_time(&interval, *argv)) {
+                fprintf(stderr, "Illegal \"interval\"\n&quo=
t;);
+                return -1;
+            }
+        } else if (strcmp(*argv, "ecn") =3D=3D 0) {
+            ecn =3D 1;
+        } else if (strcmp(*argv, "noecn") =3D=3D 0) {
+            ecn =3D 0;
+        } else if (strcmp(*argv, "help") =3D=3D 0) {
+            explain();
+            return -1;
+        } else {
+            fprintf(stderr, "What is \"%s\"?\n", *argv=
);
+            explain();
+            return -1;
+        }
+        argc--; argv++;
+    }
+
+    tail =3D NLMSG_TAIL(n);
+    addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+    if (limit)
+        addattr_l(n, 1024, TCA_FQ_CODEL_LIMIT, &limit, sizeof(limit));
+    if (flows)
+        addattr_l(n, 1024, TCA_FQ_CODEL_FLOWS, &flows, sizeof(flows));
+    if (quantum)
+        addattr_l(n, 1024, TCA_FQ_CODEL_QUANTUM, &quantum, sizeof(quan=
tum));
+    if (interval)
+        addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(in=
terval));
+    if (target)
+        addattr_l(n, 1024, TCA_FQ_CODEL_TARGET, &target, sizeof(target=
));
+    if (ecn !=3D -1)
+        addattr_l(n, 1024, TCA_FQ_CODEL_ECN, &ecn, sizeof(ecn));
+    tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail;
+    return 0;
+}
+
+static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtatt=
r *opt)
+{
+    struct rtattr *tb[TCA_FQ_CODEL_MAX + 1];
+    unsigned limit;
+    unsigned flows;
+    unsigned interval;
+    unsigned target;
+    unsigned ecn;
+    unsigned quantum;
+    SPRINT_BUF(b1);
+
+    if (opt =3D=3D NULL)
+        return 0;
+
+    parse_rtattr_nested(tb, TCA_FQ_CODEL_MAX, opt);
+
+    if (tb[TCA_FQ_CODEL_LIMIT] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_LIMIT]) >=3D sizeof(__u32)) {
+        limit =3D rta_getattr_u32(tb[TCA_FQ_CODEL_LIMIT]);
+        fprintf(f, "limit %up ", limit);
+    }
+    if (tb[TCA_FQ_CODEL_FLOWS] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_FLOWS]) >=3D sizeof(__u32)) {
+        flows =3D rta_getattr_u32(tb[TCA_FQ_CODEL_FLOWS]);
+        fprintf(f, "flows %u ", flows);
+    }
+    if (tb[TCA_FQ_CODEL_QUANTUM] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_QUANTUM]) >=3D sizeof(__u32)) {
+        quantum =3D rta_getattr_u32(tb[TCA_FQ_CODEL_QUANTUM]);
+        fprintf(f, "quantum %u ", quantum);
+    }
+    if (tb[TCA_FQ_CODEL_TARGET] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_TARGET]) >=3D sizeof(__u32)) {
+        target =3D rta_getattr_u32(tb[TCA_FQ_CODEL_TARGET]);
+        fprintf(f, "target %s ", sprint_time(target, b1));
+    }
+    if (tb[TCA_FQ_CODEL_INTERVAL] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_INTERVAL]) >=3D sizeof(__u32)) {
+        interval =3D rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]);
+        fprintf(f, "interval %s ", sprint_time(interval, b1));
+    }
+    if (tb[TCA_FQ_CODEL_ECN] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >=3D sizeof(__u32)) {
+        ecn =3D rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]);
+        if (ecn)
+            fprintf(f, "ecn ");
+    }
+
+    return 0;
+}
+
+static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f,
+                 struct rtattr *xstats)
+{
+    struct tc_fq_codel_xstats *st;
+    SPRINT_BUF(b1);
+
+    if (xstats =3D=3D NULL)
+        return 0;
+
+    if (RTA_PAYLOAD(xstats) < sizeof(*st))
+        return -1;
+
+    st =3D RTA_DATA(xstats);
+    if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC) {
+        fprintf(f, "  maxpacket %u drop_overlimit %u new_flow_count %=
u ecn_mark %u",
+            st->qdisc_stats.maxpacket,
+            st->qdisc_stats.drop_overlimit,
+            st->qdisc_stats.new_flow_count,
+            st->qdisc_stats.ecn_mark);
+        fprintf(f, "\n  new_flows_len %u old_flows_len %u",
+            st->qdisc_stats.new_flows_len,
+            st->qdisc_stats.old_flows_len);
+    }
+    if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS) {
+        fprintf(f, "  deficit %d count %u lastcount %u ldelay %s"=
;,
+            st->class_stats.deficit,
+            st->class_stats.count,
+            st->class_stats.lastcount,
+            sprint_time(st->class_stats.ldelay, b1));
+        if (st->class_stats.dropping) {
+            fprintf(f, " dropping");
+            if (st->class_stats.drop_next < 0)
+                fprintf(f, " drop_next -%s",
+                    sprint_time(-st->class_stats.drop_next, b1));
+            else
+                fprintf(f, " drop_next %s",
+                    sprint_time(st->class_stats.drop_next, b1));
+        }
+    }
+    return 0;
+
+}
+
+struct qdisc_util nfq_codel_qdisc_util =3D {
+    .id        =3D "nfq_codel",
+    .parse_qopt    =3D fq_codel_parse_opt,
+    .print_qopt    =3D fq_codel_print_opt,
+    .print_xstats    =3D fq_codel_print_xstats,
+};
diff --git a/tc/q_ns2_codel.c b/tc/q_ns2_codel.c
new file mode 100644
index 0000000..223a971
--- /dev/null
+++ b/tc/q_ns2_codel.c
@@ -0,0 +1,188 @@
+/*
+ * Codel - The Controlled-Delay Active Queue Management algorithm
+ *
+ *  Copyright (C) 2011-2012 Kathleen Nichols <nichols@pollere.com>
+ *  Copyright (C) 2011-2012 Van Jacobson <van@pollere.com>
+ *  Copyright (C) 2012 Michael D. Taht <dave.taht@bufferbloat.net>
+ *  Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote produ=
cts
+ *    derived from this software without specific prior written permission=
.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provision=
s of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT=
 NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+    fprintf(stderr, "Usage: ... ns2_codel [ limit PACKETS ] [ target =
TIME]\n");
+    fprintf(stderr, "                 [ interval TIME ] [ ecn | noecn=
 ]\n");
+}
+
+static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+               struct nlmsghdr *n)
+{
+    unsigned limit =3D 0;
+    unsigned target =3D 0;
+    unsigned interval =3D 0;
+    int ecn =3D -1;
+    struct rtattr *tail;
+
+    while (argc > 0) {
+        if (strcmp(*argv, "limit") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_unsigned(&limit, *argv, 0)) {
+                fprintf(stderr, "Illegal \"limit\"\n")=
;
+                return -1;
+            }
+        } else if (strcmp(*argv, "target") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_time(&target, *argv)) {
+                fprintf(stderr, "Illegal \"target\"\n"=
);
+                return -1;
+            }
+        } else if (strcmp(*argv, "interval") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_time(&interval, *argv)) {
+                fprintf(stderr, "Illegal \"interval\"\n&quo=
t;);
+                return -1;
+            }
+        } else if (strcmp(*argv, "ecn") =3D=3D 0) {
+            ecn =3D 1;
+        } else if (strcmp(*argv, "noecn") =3D=3D 0) {
+            ecn =3D 0;
+        } else if (strcmp(*argv, "help") =3D=3D 0) {
+            explain();
+            return -1;
+        } else {
+            fprintf(stderr, "What is \"%s\"?\n", *argv=
);
+            explain();
+            return -1;
+        }
+        argc--; argv++;
+    }
+
+    tail =3D NLMSG_TAIL(n);
+    addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+    if (limit)
+        addattr_l(n, 1024, TCA_CODEL_LIMIT, &limit, sizeof(limit));
+    if (interval)
+        addattr_l(n, 1024, TCA_CODEL_INTERVAL, &interval, sizeof(inter=
val));
+    if (target)
+        addattr_l(n, 1024, TCA_CODEL_TARGET, &target, sizeof(target));
+    if (ecn !=3D -1)
+        addattr_l(n, 1024, TCA_CODEL_ECN, &ecn, sizeof(ecn));
+    tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail;
+    return 0;
+}
+
+static int codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *=
opt)
+{
+    struct rtattr *tb[TCA_CODEL_MAX + 1];
+    unsigned limit;
+    unsigned interval;
+    unsigned target;
+    unsigned ecn;
+    SPRINT_BUF(b1);
+
+    if (opt =3D=3D NULL)
+        return 0;
+
+    parse_rtattr_nested(tb, TCA_CODEL_MAX, opt);
+
+    if (tb[TCA_CODEL_LIMIT] &&
+        RTA_PAYLOAD(tb[TCA_CODEL_LIMIT]) >=3D sizeof(__u32)) {
+        limit =3D rta_getattr_u32(tb[TCA_CODEL_LIMIT]);
+        fprintf(f, "limit %up ", limit);
+    }
+    if (tb[TCA_CODEL_TARGET] &&
+        RTA_PAYLOAD(tb[TCA_CODEL_TARGET]) >=3D sizeof(__u32)) {
+        target =3D rta_getattr_u32(tb[TCA_CODEL_TARGET]);
+        fprintf(f, "target %s ", sprint_time(target, b1));
+    }
+    if (tb[TCA_CODEL_INTERVAL] &&
+        RTA_PAYLOAD(tb[TCA_CODEL_INTERVAL]) >=3D sizeof(__u32)) {
+        interval =3D rta_getattr_u32(tb[TCA_CODEL_INTERVAL]);
+        fprintf(f, "interval %s ", sprint_time(interval, b1));
+    }
+    if (tb[TCA_CODEL_ECN] &&
+        RTA_PAYLOAD(tb[TCA_CODEL_ECN]) >=3D sizeof(__u32)) {
+        ecn =3D rta_getattr_u32(tb[TCA_CODEL_ECN]);
+        if (ecn)
+            fprintf(f, "ecn ");
+    }
+
+    return 0;
+}
+
+static int codel_print_xstats(struct qdisc_util *qu, FILE *f,
+                  struct rtattr *xstats)
+{
+    struct tc_codel_xstats *st;
+    SPRINT_BUF(b1);
+
+    if (xstats =3D=3D NULL)
+        return 0;
+
+    if (RTA_PAYLOAD(xstats) < sizeof(*st))
+        return -1;
+
+    st =3D RTA_DATA(xstats);
+    fprintf(f, "  count %u lastcount %u ldelay %s",
+        st->count, st->lastcount, sprint_time(st->ldelay, b1));
+    if (st->dropping)
+        fprintf(f, " dropping");
+    if (st->drop_next < 0)
+        fprintf(f, " drop_next -%s", sprint_time(-st->drop_ne=
xt, b1));
+    else
+        fprintf(f, " drop_next %s", sprint_time(st->drop_next=
, b1));
+    fprintf(f, "\n  maxpacket %u ecn_mark %u drop_overlimit %u",
+        st->maxpacket, st->ecn_mark, st->drop_overlimit);
+    return 0;
+
+}
+
+struct qdisc_util ns2_codel_qdisc_util =3D {
+    .id        =3D "ns2_codel",
+    .parse_qopt    =3D codel_parse_opt,
+    .print_qopt    =3D codel_print_opt,
+    .print_xstats    =3D codel_print_xstats,
+};
diff --git a/tc/q_ns4_codel.c b/tc/q_ns4_codel.c
new file mode 100644
index 0000000..0aaa349
--- /dev/null
+++ b/tc/q_ns4_codel.c
@@ -0,0 +1,188 @@
+/*
+ * Codel - The Controlled-Delay Active Queue Management algorithm
+ *
+ *  Copyright (C) 2011-2012 Kathleen Nichols <nichols@pollere.com>
+ *  Copyright (C) 2011-2012 Van Jacobson <van@pollere.com>
+ *  Copyright (C) 2012 Michael D. Taht <dave.taht@bufferbloat.net>
+ *  Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote produ=
cts
+ *    derived from this software without specific prior written permission=
.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provision=
s of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT=
 NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+    fprintf(stderr, "Usage: ... ns4_codel [ limit PACKETS ] [ target =
TIME]\n");
+    fprintf(stderr, "                 [ interval TIME ] [ ecn | noecn=
 ]\n");
+}
+
+static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+               struct nlmsghdr *n)
+{
+    unsigned limit =3D 0;
+    unsigned target =3D 0;
+    unsigned interval =3D 0;
+    int ecn =3D -1;
+    struct rtattr *tail;
+
+    while (argc > 0) {
+        if (strcmp(*argv, "limit") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_unsigned(&limit, *argv, 0)) {
+                fprintf(stderr, "Illegal \"limit\"\n")=
;
+                return -1;
+            }
+        } else if (strcmp(*argv, "target") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_time(&target, *argv)) {
+                fprintf(stderr, "Illegal \"target\"\n"=
);
+                return -1;
+            }
+        } else if (strcmp(*argv, "interval") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_time(&interval, *argv)) {
+                fprintf(stderr, "Illegal \"interval\"\n&quo=
t;);
+                return -1;
+            }
+        } else if (strcmp(*argv, "ecn") =3D=3D 0) {
+            ecn =3D 1;
+        } else if (strcmp(*argv, "noecn") =3D=3D 0) {
+            ecn =3D 0;
+        } else if (strcmp(*argv, "help") =3D=3D 0) {
+            explain();
+            return -1;
+        } else {
+            fprintf(stderr, "What is \"%s\"?\n", *argv=
);
+            explain();
+            return -1;
+        }
+        argc--; argv++;
+    }
+
+    tail =3D NLMSG_TAIL(n);
+    addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+    if (limit)
+        addattr_l(n, 1024, TCA_CODEL_LIMIT, &limit, sizeof(limit));
+    if (interval)
+        addattr_l(n, 1024, TCA_CODEL_INTERVAL, &interval, sizeof(inter=
val));
+    if (target)
+        addattr_l(n, 1024, TCA_CODEL_TARGET, &target, sizeof(target));
+    if (ecn !=3D -1)
+        addattr_l(n, 1024, TCA_CODEL_ECN, &ecn, sizeof(ecn));
+    tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail;
+    return 0;
+}
+
+static int codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *=
opt)
+{
+    struct rtattr *tb[TCA_CODEL_MAX + 1];
+    unsigned limit;
+    unsigned interval;
+    unsigned target;
+    unsigned ecn;
+    SPRINT_BUF(b1);
+
+    if (opt =3D=3D NULL)
+        return 0;
+
+    parse_rtattr_nested(tb, TCA_CODEL_MAX, opt);
+
+    if (tb[TCA_CODEL_LIMIT] &&
+        RTA_PAYLOAD(tb[TCA_CODEL_LIMIT]) >=3D sizeof(__u32)) {
+        limit =3D rta_getattr_u32(tb[TCA_CODEL_LIMIT]);
+        fprintf(f, "limit %up ", limit);
+    }
+    if (tb[TCA_CODEL_TARGET] &&
+        RTA_PAYLOAD(tb[TCA_CODEL_TARGET]) >=3D sizeof(__u32)) {
+        target =3D rta_getattr_u32(tb[TCA_CODEL_TARGET]);
+        fprintf(f, "target %s ", sprint_time(target, b1));
+    }
+    if (tb[TCA_CODEL_INTERVAL] &&
+        RTA_PAYLOAD(tb[TCA_CODEL_INTERVAL]) >=3D sizeof(__u32)) {
+        interval =3D rta_getattr_u32(tb[TCA_CODEL_INTERVAL]);
+        fprintf(f, "interval %s ", sprint_time(interval, b1));
+    }
+    if (tb[TCA_CODEL_ECN] &&
+        RTA_PAYLOAD(tb[TCA_CODEL_ECN]) >=3D sizeof(__u32)) {
+        ecn =3D rta_getattr_u32(tb[TCA_CODEL_ECN]);
+        if (ecn)
+            fprintf(f, "ecn ");
+    }
+
+    return 0;
+}
+
+static int codel_print_xstats(struct qdisc_util *qu, FILE *f,
+                  struct rtattr *xstats)
+{
+    struct tc_codel_xstats *st;
+    SPRINT_BUF(b1);
+
+    if (xstats =3D=3D NULL)
+        return 0;
+
+    if (RTA_PAYLOAD(xstats) < sizeof(*st))
+        return -1;
+
+    st =3D RTA_DATA(xstats);
+    fprintf(f, "  count %u lastcount %u ldelay %s",
+        st->count, st->lastcount, sprint_time(st->ldelay, b1));
+    if (st->dropping)
+        fprintf(f, " dropping");
+    if (st->drop_next < 0)
+        fprintf(f, " drop_next -%s", sprint_time(-st->drop_ne=
xt, b1));
+    else
+        fprintf(f, " drop_next %s", sprint_time(st->drop_next=
, b1));
+    fprintf(f, "\n  maxpacket %u ecn_mark %u drop_overlimit %u",
+        st->maxpacket, st->ecn_mark, st->drop_overlimit);
+    return 0;
+
+}
+
+struct qdisc_util ns4_codel_qdisc_util =3D {
+    .id        =3D "ns4_codel",
+    .parse_qopt    =3D codel_parse_opt,
+    .print_qopt    =3D codel_print_opt,
+    .print_xstats    =3D codel_print_xstats,
+};
diff --git a/tc/q_pfq_codel.c b/tc/q_pfq_codel.c
new file mode 100644
index 0000000..52c5160
--- /dev/null
+++ b/tc/q_pfq_codel.c
@@ -0,0 +1,232 @@
+/*
+ * Fair Queue Codel
+ *
+ *  Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote produ=
cts
+ *    derived from this software without specific prior written permission=
.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provision=
s of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT=
 NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static void explain(void)
+{
+    fprintf(stderr, "Usage: ... pfq_codel [ limit PACKETS ] [ flows N=
UMBER ]\n");
+    fprintf(stderr, "                    [ target TIME] [ interval TI=
ME ]\n");
+    fprintf(stderr, "                    [ quantum BYTES ] [ [no]ecn =
]\n");
+}
+
+static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv=
,
+                  struct nlmsghdr *n)
+{
+    unsigned limit =3D 0;
+    unsigned flows =3D 0;
+    unsigned target =3D 0;
+    unsigned interval =3D 0;
+    unsigned quantum =3D 0;
+    int ecn =3D -1;
+    struct rtattr *tail;
+
+    while (argc > 0) {
+        if (strcmp(*argv, "limit") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_unsigned(&limit, *argv, 0)) {
+                fprintf(stderr, "Illegal \"limit\"\n")=
;
+                return -1;
+            }
+        } else if (strcmp(*argv, "flows") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_unsigned(&flows, *argv, 0)) {
+                fprintf(stderr, "Illegal \"flows\"\n")=
;
+                return -1;
+            }
+        } else if (strcmp(*argv, "quantum") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_unsigned(&quantum, *argv, 0)) {
+                fprintf(stderr, "Illegal \"quantum\"\n"=
;);
+                return -1;
+            }
+        } else if (strcmp(*argv, "target") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_time(&target, *argv)) {
+                fprintf(stderr, "Illegal \"target\"\n"=
);
+                return -1;
+            }
+        } else if (strcmp(*argv, "interval") =3D=3D 0) {
+            NEXT_ARG();
+            if (get_time(&interval, *argv)) {
+                fprintf(stderr, "Illegal \"interval\"\n&quo=
t;);
+                return -1;
+            }
+        } else if (strcmp(*argv, "ecn") =3D=3D 0) {
+            ecn =3D 1;
+        } else if (strcmp(*argv, "noecn") =3D=3D 0) {
+            ecn =3D 0;
+        } else if (strcmp(*argv, "help") =3D=3D 0) {
+            explain();
+            return -1;
+        } else {
+            fprintf(stderr, "What is \"%s\"?\n", *argv=
);
+            explain();
+            return -1;
+        }
+        argc--; argv++;
+    }
+
+    tail =3D NLMSG_TAIL(n);
+    addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+    if (limit)
+        addattr_l(n, 1024, TCA_FQ_CODEL_LIMIT, &limit, sizeof(limit));
+    if (flows)
+        addattr_l(n, 1024, TCA_FQ_CODEL_FLOWS, &flows, sizeof(flows));
+    if (quantum)
+        addattr_l(n, 1024, TCA_FQ_CODEL_QUANTUM, &quantum, sizeof(quan=
tum));
+    if (interval)
+        addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(in=
terval));
+    if (target)
+        addattr_l(n, 1024, TCA_FQ_CODEL_TARGET, &target, sizeof(target=
));
+    if (ecn !=3D -1)
+        addattr_l(n, 1024, TCA_FQ_CODEL_ECN, &ecn, sizeof(ecn));
+    tail->rta_len =3D (void *) NLMSG_TAIL(n) - (void *) tail;
+    return 0;
+}
+
+static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtatt=
r *opt)
+{
+    struct rtattr *tb[TCA_FQ_CODEL_MAX + 1];
+    unsigned limit;
+    unsigned flows;
+    unsigned interval;
+    unsigned target;
+    unsigned ecn;
+    unsigned quantum;
+    SPRINT_BUF(b1);
+
+    if (opt =3D=3D NULL)
+        return 0;
+
+    parse_rtattr_nested(tb, TCA_FQ_CODEL_MAX, opt);
+
+    if (tb[TCA_FQ_CODEL_LIMIT] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_LIMIT]) >=3D sizeof(__u32)) {
+        limit =3D rta_getattr_u32(tb[TCA_FQ_CODEL_LIMIT]);
+        fprintf(f, "limit %up ", limit);
+    }
+    if (tb[TCA_FQ_CODEL_FLOWS] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_FLOWS]) >=3D sizeof(__u32)) {
+        flows =3D rta_getattr_u32(tb[TCA_FQ_CODEL_FLOWS]);
+        fprintf(f, "flows %u ", flows);
+    }
+    if (tb[TCA_FQ_CODEL_QUANTUM] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_QUANTUM]) >=3D sizeof(__u32)) {
+        quantum =3D rta_getattr_u32(tb[TCA_FQ_CODEL_QUANTUM]);
+        fprintf(f, "quantum %u ", quantum);
+    }
+    if (tb[TCA_FQ_CODEL_TARGET] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_TARGET]) >=3D sizeof(__u32)) {
+        target =3D rta_getattr_u32(tb[TCA_FQ_CODEL_TARGET]);
+        fprintf(f, "target %s ", sprint_time(target, b1));
+    }
+    if (tb[TCA_FQ_CODEL_INTERVAL] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_INTERVAL]) >=3D sizeof(__u32)) {
+        interval =3D rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]);
+        fprintf(f, "interval %s ", sprint_time(interval, b1));
+    }
+    if (tb[TCA_FQ_CODEL_ECN] &&
+        RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >=3D sizeof(__u32)) {
+        ecn =3D rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]);
+        if (ecn)
+            fprintf(f, "ecn ");
+    }
+
+    return 0;
+}
+
+static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f,
+                 struct rtattr *xstats)
+{
+    struct tc_fq_codel_xstats *st;
+    SPRINT_BUF(b1);
+
+    if (xstats =3D=3D NULL)
+        return 0;
+
+    if (RTA_PAYLOAD(xstats) < sizeof(*st))
+        return -1;
+
+    st =3D RTA_DATA(xstats);
+    if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_QDISC) {
+        fprintf(f, "  maxpacket %u drop_overlimit %u new_flow_count %=
u ecn_mark %u",
+            st->qdisc_stats.maxpacket,
+            st->qdisc_stats.drop_overlimit,
+            st->qdisc_stats.new_flow_count,
+            st->qdisc_stats.ecn_mark);
+        fprintf(f, "\n  new_flows_len %u old_flows_len %u",
+            st->qdisc_stats.new_flows_len,
+            st->qdisc_stats.old_flows_len);
+    }
+    if (st->type =3D=3D TCA_FQ_CODEL_XSTATS_CLASS) {
+        fprintf(f, "  deficit %d count %u lastcount %u ldelay %s"=
;,
+            st->class_stats.deficit,
+            st->class_stats.count,
+            st->class_stats.lastcount,
+            sprint_time(st->class_stats.ldelay, b1));
+        if (st->class_stats.dropping) {
+            fprintf(f, " dropping");
+            if (st->class_stats.drop_next < 0)
+                fprintf(f, " drop_next -%s",
+                    sprint_time(-st->class_stats.drop_next, b1));
+            else
+                fprintf(f, " drop_next %s",
+                    sprint_time(st->class_stats.drop_next, b1));
+        }
+    }
+    return 0;
+
+}
+
+struct qdisc_util pfq_codel_qdisc_util =3D {
+    .id        =3D "pfq_codel",
+    .parse_qopt    =3D fq_codel_parse_opt,
+    .print_qopt    =3D fq_codel_print_opt,
+    .print_xstats    =3D fq_codel_print_xstats,
+};

141-cake-add-support.patch









--
Dave T=C3=A4ht
Open Networking needs **Open Source Hardware**
https://plus.google.com/u/0/+EricRaymond/posts/JqxCe2pFr= 67
--089e0112cb34d139f105151567ed--