From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from emea01-db3-obe.outbound.protection.outlook.com (mail-db3on0076.outbound.protection.outlook.com [157.55.234.76]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client CN "mail.protection.outlook.com", Issuer "MSIT Machine Auth CA 2" (verified OK)) by huchra.bufferbloat.net (Postfix) with ESMTPS id 7315B21F2D9 for ; Fri, 1 May 2015 04:07:16 -0700 (PDT) Authentication-Results: lists.bufferbloat.net; dkim=none (message not signed) header.d=none; Received: from [IPv6:2001:470:183f:da2b::717c:e11c] (2001:470:183f:da2b::717c:e11c) by HE1PR07MB0939.eurprd07.prod.outlook.com (25.162.27.145) with Microsoft SMTP Server (TLS) id 15.1.148.16; Fri, 1 May 2015 11:07:08 +0000 Message-ID: <55435E48.9050709@darbyshire-bryant.me.uk> Date: Fri, 1 May 2015 12:06:48 +0100 From: Kevin Darbyshire-Bryant User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Thunderbird/31.6.0 MIME-Version: 1.0 To: References: In-Reply-To: Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg=sha1; boundary="------------ms090101010801070509030702" X-Originating-IP: [2001:470:183f:da2b::717c:e11c] X-ClientProxiedBy: BY2PR08CA040.namprd08.prod.outlook.com (10.141.248.158) To HE1PR07MB0939.eurprd07.prod.outlook.com (25.162.27.145) X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:HE1PR07MB0939; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(5005006)(3002001); SRVR:HE1PR07MB0939; BCL:0; PCL:0; RULEID:; SRVR:HE1PR07MB0939; X-Forefront-PRVS: 0563F2E8B7 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(6009001)(479174004)(377454003)(24454002)(450100001)(5890100001)(40100003)(83506001)(77156002)(62966003)(122386002)(4001350100001)(93886004)(568964001)(54356999)(42186005)(65956001)(33656002)(36756003)(65816999)(86362001)(2351001)(76176999)(84326002)(2950100001)(50986999)(87976001)(19580395003)(5001920100001)(74482002)(19580405001)(110136002)(80316001)(5001960100002)(92566002)(99136001)(107886002)(87266999)(512874002)(46102003)(3826002)(559001)(579004); DIR:OUT; SFP:1101; SCL:1; SRVR:HE1PR07MB0939; H:[IPv6:2001:470:183f:da2b::717c:e11c]; FPR:; SPF:None; MLV:sfv; LANG:en; X-OriginatorOrg: darbyshire-bryant.me.uk X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 May 2015 11:07:08.9874 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: HE1PR07MB0939 Subject: Re: [Cerowrt-devel] [Cake] documentation review request and out of tree cake builds for openwrt/etc. 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: Fri, 01 May 2015 11:07:47 -0000 --------------ms090101010801070509030702 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Resent without attachments: 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... bu= t 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= =2E Is that clear enough?=20 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 =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 + * + * 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 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 + * + * 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 | diffserv8 = | diffserv4 ]\n" + " [ flowblind | srchost | dsthost | host= s | 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(bandwidth));= + if (diffserv) + addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(diffserv)= ); + 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(flowmode)); + 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 ecn_mar= k %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(xst= ats) >=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 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].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 | diffserv = ]\n" + " [ flowblind | srchost | dsthost | hos= ts | 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(bandwidth));= + if (diffserv) + addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(diffserv)= ); + 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(flowmode)); + 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 ecn_mar= k %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(xst= ats) >=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 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].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 | diffserv ]= \n" + " [ flowblind | srchost | dsthost | host= s | 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(bandwidth));= + if (diffserv) + addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(diffserv)= ); + 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(flowmode)); + 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 ecn_mar= k %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(xst= ats) >=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 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].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 NUMBER = ]\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(quantum)); + if (interval) + addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(interval))= ; + 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 ecn_mar= k %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 NUMBER = ]\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(quantum)); + if (interval) + addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(interval))= ; + 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 ecn_mar= k %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 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"); + 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(interval)); + 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 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"); + 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(interval)); + 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 NUMBER = ]\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(quantum)); + if (interval) + addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(interval))= ; + 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 ecn_mar= k %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-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 --------------ms090101010801070509030702 Content-Type: application/pkcs7-signature; name="smime.p7s" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7s" Content-Description: S/MIME Cryptographic Signature MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIINnDCC BjQwggQcoAMCAQICAR4wDQYJKoZIhvcNAQEFBQAwfTELMAkGA1UEBhMCSUwxFjAUBgNVBAoT DVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNp Z25pbmcxKTAnBgNVBAMTIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA3 MTAyNDIxMDE1NVoXDTE3MTAyNDIxMDE1NVowgYwxCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1T dGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUgRGlnaXRhbCBDZXJ0aWZpY2F0ZSBTaWdu aW5nMTgwNgYDVQQDEy9TdGFydENvbSBDbGFzcyAxIFByaW1hcnkgSW50ZXJtZWRpYXRlIENs aWVudCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcJg8zOLdgasSmkLhOr lr6KMoOMpohBllVHrdRvEg/q6r8jR+EK75xCGhR8ToREoqe7zM9/UnC6TS2y9UKTpT1v7RSM zR0t6ndl0TWBuUr/UXBhPk+Kmy7bI4yW4urC+y7P3/1/X7U8ocb8VpH/Clt+4iq7nirMcNh6 qJR+xjOhV+VHzQMALuGYn5KZmc1NbJQYclsGkDxDz2UbFqE2+6vIZoL+jb9x4Pa5gNf1TwSD kOkikZB1xtB4ZqtXThaABSONdfmv/Z1pua3FYxnCFmdr/+N2JLKutIxMYqQOJebr/f/h5t95 m4JgrM3Y/w7YX9d7YAL9jvN4SydHsU6n65cCAwEAAaOCAa0wggGpMA8GA1UdEwEB/wQFMAMB Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRTcu2SnODaywFcfH6WNU7y1LhRgjAfBgNV HSMEGDAWgBROC+8apEBbpRdphzDKNGhD0EGu8jBmBggrBgEFBQcBAQRaMFgwJwYIKwYBBQUH MAGGG2h0dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbS9jYTAtBggrBgEFBQcwAoYhaHR0cDovL3d3 dy5zdGFydHNzbC5jb20vc2ZzY2EuY3J0MFsGA1UdHwRUMFIwJ6AloCOGIWh0dHA6Ly93d3cu c3RhcnRzc2wuY29tL3Nmc2NhLmNybDAnoCWgI4YhaHR0cDovL2NybC5zdGFydHNzbC5jb20v c2ZzY2EuY3JsMIGABgNVHSAEeTB3MHUGCysGAQQBgbU3AQIBMGYwLgYIKwYBBQUHAgEWImh0 dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93 d3cuc3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwDQYJKoZIhvcNAQEFBQADggIBAAqD CH14qywGXLhjjF6uHLkjd02hcdh9hrw+VUsv+q1eeQWB21jWj3kJ96AUlPCoEGZ/ynJNScWy 6QMVQjbbMXltUfO4n4bGGdKo3awPWp61tjAFgraLJgDk+DsSvUD6EowjMTNx25GQgyYJ5RPI zKKR9tQW8gGK+2+RHxkUCTbYFnL6kl8Ch507rUdPPipJ9CgJFws3kDS3gOS5WFMxcjO5DwKf KSETEPrHh7p5shuuNktvsv6hxHTLhiMKX893gxdT3XLS9OKmCv87vkINQcNEcIIoFWbP9HOR z9v3vQwR4e3ksLc2JZOAFK+ssS5XMEoznzpihEP0PLc4dCBYjbvSD7kxgDwZ+Aj8Q9PkbvE9 sIPP7ON0fz095HdThKjiVJe6vofq+n6b1NBc8XdrQvBmunwxD5nvtTW4vtN6VY7mUCmxsCie uoBJ9OlqmsVWQvifIYf40dJPZkk9YgGTzWLpXDSfLSplbY2LL9C9U0ptvjcDjefLTvqSFc7t w1sEhF0n/qpA2r0GpvkLRDmcSwVyPvmjFBGqUp/pNy8ZuPGQmHwFi2/14+xeSUDG2bwnsYJQ G2EdJCB6luQ57GEnTA/yKZSTKI8dDQa8Sd3zfXb19mOgSF0bBdXbuKhEpuP9wirslFe6fQ1t 5j5R0xi72MZ8ikMu1RQZKCyDbMwazlHiMIIHYDCCBkigAwIBAgIDCm0/MA0GCSqGSIb3DQEB BQUAMIGMMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20g Q2xhc3MgMSBQcmltYXJ5IEludGVybWVkaWF0ZSBDbGllbnQgQ0EwHhcNMTQwNzAzMTE1NjM5 WhcNMTUwNzA0MTc0MjQ1WjBxMRkwFwYDVQQNExA2dVNGb1pMU1d2dGgyd2tNMSYwJAYDVQQD DB1rZXZpbkBkYXJieXNoaXJlLWJyeWFudC5tZS51azEsMCoGCSqGSIb3DQEJARYda2V2aW5A ZGFyYnlzaGlyZS1icnlhbnQubWUudWswggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQDqCZMbkat9lukbtY+VQ4HBVkcHtcUU1sWZlg7foJ6XEQXCb3ArlyY7V+AldkNY6qRlrlVt YZmSFtDsors5e3Z1VWlEYBZEbnR57t5jmfGYmaaDzc8YsWr5gsUTa+MV/MNHpuAlf9GwgQCQ e7SC7kEzkQZApfB8/zG/a5JxgVXD9c3vK40p3OW27ZqVN9rie5SoLi1KEfQbA//VyPPeDpus oDwYGq6AA82lLFvgBxi1JPlS7M9zToUQCXpvDexQPiok1iqhwYBwX3qmSInlVWnudgaJ25iL m8/9bG5nCIo+dOEZP/bOCEsMzV8n9RaCNu8ilpjMXsHbkgrlvng81CTUFlYWhdMg58CM7N9y gSBjCKuHmJwQbIdsCmuKEOFVLZR8OZzoue6e/HAQlunWEfrr/H4+UYp8yTNLybqfcyZ3k7Sg i207jicY5dVKKFFY8eSB8Ps2svxj6BgrNPZMGzW36zRwaK1MpOZxHItCcuyXo+WkI3/61BZ5 mg34ejrgalQ04887n+4u3XPKnM/IwXfivlOD+n8bOOAGR8iZVlLTVmvypMdX3+wL/yB/w8g1 Ojj9Bk5/ksZb9Eh+3q1cVOOuXa/hcCLLqetNFzlxHjbVXzBKwO9pOs50DVxtv070KalD3iqz 8hCwnDt7odkGHwXyZAErmUSjc6tqVMivid/1swIDAQABo4IC4zCCAt8wCQYDVR0TBAIwADAL BgNVHQ8EBAMCBLAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBSg QyTrQHiayWJq77xyyu7kpPmJ2jAfBgNVHSMEGDAWgBRTcu2SnODaywFcfH6WNU7y1LhRgjAo BgNVHREEITAfgR1rZXZpbkBkYXJieXNoaXJlLWJyeWFudC5tZS51azCCAUwGA1UdIASCAUMw ggE/MIIBOwYLKwYBBAGBtTcBAgMwggEqMC4GCCsGAQUFBwIBFiJodHRwOi8vd3d3LnN0YXJ0 c3NsLmNvbS9wb2xpY3kucGRmMIH3BggrBgEFBQcCAjCB6jAnFiBTdGFydENvbSBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTADAgEBGoG+VGhpcyBjZXJ0aWZpY2F0ZSB3YXMgaXNzdWVkIGFj Y29yZGluZyB0byB0aGUgQ2xhc3MgMSBWYWxpZGF0aW9uIHJlcXVpcmVtZW50cyBvZiB0aGUg U3RhcnRDb20gQ0EgcG9saWN5LCByZWxpYW5jZSBvbmx5IGZvciB0aGUgaW50ZW5kZWQgcHVy cG9zZSBpbiBjb21wbGlhbmNlIG9mIHRoZSByZWx5aW5nIHBhcnR5IG9ibGlnYXRpb25zLjA2 BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9jcnR1MS1jcmwuY3Js MIGOBggrBgEFBQcBAQSBgTB/MDkGCCsGAQUFBzABhi1odHRwOi8vb2NzcC5zdGFydHNzbC5j b20vc3ViL2NsYXNzMS9jbGllbnQvY2EwQgYIKwYBBQUHMAKGNmh0dHA6Ly9haWEuc3RhcnRz c2wuY29tL2NlcnRzL3N1Yi5jbGFzczEuY2xpZW50LmNhLmNydDAjBgNVHRIEHDAahhhodHRw Oi8vd3d3LnN0YXJ0c3NsLmNvbS8wDQYJKoZIhvcNAQEFBQADggEBAChYSPOI6HHjtB2zQSGb 7vqo2f/QAum648uoNCFXf/ZmpU42ca6hq/JqsugqbnCY72hNTpCh3JZwTTaBWBvj1vzjjMra pLixIvceaAqMj6vd+L43APuMMmTH9tUUNS1ksXdA2r6STVIbr4p2sbVV3WktLGFnNAy5uXbr mLHay5w6jcmSfTAh1aA49sSvp+8CB6q6uDef2j9X8OE9Ajr5l0mcnGdVOkLZU6Zq20G8jb3p sdqoO9MU5UbKfZCN4/ibr+/0Pj3VZIE3jCEW2DwguN6DIDAYVc6b7RFGf3cWadJrSa887Sc/ 9wzXymTKAyBvfgRQeWcZ+5w4RlOI/TmpNfwxggTdMIIE2QIBATCBlDCBjDELMAkGA1UEBhMC SUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENl cnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJ bnRlcm1lZGlhdGUgQ2xpZW50IENBAgMKbT8wCQYFKw4DAhoFAKCCAh0wGAYJKoZIhvcNAQkD MQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTUwNTAxMTEwNjQ4WjAjBgkqhkiG9w0B CQQxFgQUszbdlxJO7ksHo72NNGioij6hNsgwbAYJKoZIhvcNAQkPMV8wXTALBglghkgBZQME ASowCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMCAgIAgDANBggqhkiG9w0D AgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDCBpQYJKwYBBAGCNxAEMYGXMIGUMIGMMQsw CQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3MgMSBQ cmltYXJ5IEludGVybWVkaWF0ZSBDbGllbnQgQ0ECAwptPzCBpwYLKoZIhvcNAQkQAgsxgZeg gZQwgYwxCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSswKQYDVQQLEyJT ZWN1cmUgRGlnaXRhbCBDZXJ0aWZpY2F0ZSBTaWduaW5nMTgwNgYDVQQDEy9TdGFydENvbSBD bGFzcyAxIFByaW1hcnkgSW50ZXJtZWRpYXRlIENsaWVudCBDQQIDCm0/MA0GCSqGSIb3DQEB AQUABIICAFabgBk5ajWScpxjTyqQ3b5a3wwlTX1Ixl6ZbBdnnIHwZPU2lanMlmcXtVlHMMcv GcR7r6ngaqNOa+lB2R9MxcKg7aPONb+iXY3fEB+37iAXVHC1euLR0XIL6aoY7mtfrJ5pS4TE pclJChuvOE5kkfSlNqdzNoJpt7+VuwQ/eB24YHFGpJ5Sr07GBoqHC401ey3VBrj7KXgSuTP4 M5o/XLRupSNWCc7Y7QQ9RG43Y2sabiOdGQ30ugQjJ4WdYON5N0uspYt0ChEplEVFoHM6yVWB WIKfzUKT9h5V0Shedl65Axb2isl6xAenW+F4Ip1Sa3aaKhlgj9eJcFEvmw4BjfcWaa9VY7G2 bNwd0a4SYTwNd4JMWpmQu0fN4nqLQ8M2I0dN+hTGGGOKt4IyEFf3apuil8FxxVHsR+Bm++ty nCpf7Ecj3+QtYCtZdFZ70BEYO5eYYBrzlaLokXcP1bZ66QoUfh1q3bJ2hWN2zpP5I28lEmIR IHtT25+WjmF+QCW0082O/ZYfIRiz/cl22jQRgSzMD+UZZiYmiihLUJq4RHkTFDTE0dls95fM 5st0GSoNiJHFoS9Mq1E2mPfZzWA9BdCYRaRxk0/xlOe6l9WC+IZWFXiBXsVPUzXtPSu4xcBq O7WY6bgK5c8ay1Pw5gK5j17UgyeOWYgslLqYgW8sHNDKAAAAAAAA --------------ms090101010801070509030702--