From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-yx0-f171.google.com (mail-yx0-f171.google.com [209.85.213.171]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority" (verified OK)) by huchra.bufferbloat.net (Postfix) with ESMTPS id 1B910201AF7; Wed, 9 May 2012 09:32:34 -0700 (PDT) Received: by yenq11 with SMTP id q11so889342yen.16 for ; Wed, 09 May 2012 09:32:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:cc:content-type :content-transfer-encoding; bh=iWBAQDdZm6A5RKKD0ubWQgdh3gR9QgvRp289cyEAr5I=; b=CK/1PD4ThOvr5eD+qezqVlU5fGmWYRMvL/rzkOxU+HyAID8hEU/ubtvQGDL07Mk39X Vk4FqCx6CUmHDeDw9CxURrg9c+8p3d8eO8JiDE60LVWP2B2+J7xTnxa77pPsOo/KGPz1 w/CDTUlNhqF0+gTQc7kolZ9PMn2JwBQqJ/nQy7vQEx6bPCCgvnAe1kmFHi5gA8xreEYZ IboSmrsLoaGo7revk1ssHF+W8T49ek1HKwq1pSV12EapTa7CPvyTeNbxVl1t61HWODLq WYyGnmLpwbIFWIno3+s4R79gmYVI7fgtH93pk8XOC2LOowc3zb480smUt9Yro9wmuw5q 8p5Q== MIME-Version: 1.0 Received: by 10.236.78.2 with SMTP id f2mr688243yhe.118.1336581153708; Wed, 09 May 2012 09:32:33 -0700 (PDT) Sender: joshhunt00@gmail.com Received: by 10.146.156.2 with HTTP; Wed, 9 May 2012 09:32:33 -0700 (PDT) In-Reply-To: <1336571439.12504.27.camel@edumazet-glaptop> References: <1336368957-17586-1-git-send-email-dave.taht@bufferbloat.net> <1336399043.3752.2318.camel@edumazet-glaptop> <1336571439.12504.27.camel@edumazet-glaptop> Date: Wed, 9 May 2012 11:32:33 -0500 X-Google-Sender-Auth: 2hIrFlRmUi7XX8ydlMp9hqLjZCk Message-ID: From: Josh Hunt To: Eric Dumazet Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Mailman-Approved-At: Wed, 09 May 2012 09:36:22 -0700 Cc: codel@lists.bufferbloat.net, bloat , =?ISO-8859-1?Q?Dave_T=E4ht?= Subject: Re: [Codel] [Bloat] [PATCH v12] codel: Controlled Delay AQM X-BeenThere: codel@lists.bufferbloat.net X-Mailman-Version: 2.1.13 Precedence: list List-Id: CoDel AQM discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 09 May 2012 16:32:35 -0000 On Wed, May 9, 2012 at 8:50 AM, Eric Dumazet wrote= : > From: Eric Dumazet > > An implementation of CoDel AQM, from Kathleen Nichols and Van Jacobson. > > =A0http://queue.acm.org/detail.cfm?id=3D2209336 > > Based on initial work from Dave Taht. > > Refactored to help future codel inclusion as plugin for other linux > qdisc (SFQ), like done with RED plugin. > > Tested up to 10Gb speeds with no particular problems. > > Signed-off-by: Eric Dumazet > Signed-off-by: Dave Taht > Cc: Kathleen Nichols > Cc: Van Jacobson > --- > v12: algo changes after Kathleen & Van last updates > =A0 - introduction of lastcount. > =A0 - minbytes renamed to maxpacket. > =A0 - maxpacket automatically learns biggest packet size. > =A0 - ldelay record sojourn time of last dequeued packet. > =A0 - various changes, better comments... > > I hope this is the last version before upstream submission (netdev) > I'll send the iproute2 patch as well. > > =A0include/linux/pkt_sched.h | =A0 28 +++ > =A0include/net/codel.h =A0 =A0 =A0 | =A0325 +++++++++++++++++++++++++++++= +++++++ > =A0net/sched/Kconfig =A0 =A0 =A0 =A0 | =A0 11 + > =A0net/sched/Makefile =A0 =A0 =A0 =A0| =A0 =A01 > =A0net/sched/sch_codel.c =A0 =A0 | =A0272 ++++++++++++++++++++++++++++++ > =A05 files changed, 637 insertions(+) > > diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h > index ffe975c..453dd2c 100644 > --- a/include/linux/pkt_sched.h > +++ b/include/linux/pkt_sched.h > @@ -655,4 +655,32 @@ struct tc_qfq_stats { > =A0 =A0 =A0 =A0__u32 lmax; > =A0}; > > +/* CODEL */ > + > +enum { > + =A0 =A0 =A0 TCA_CODEL_UNSPEC, > + =A0 =A0 =A0 TCA_CODEL_TARGET, > + =A0 =A0 =A0 TCA_CODEL_LIMIT, > + =A0 =A0 =A0 TCA_CODEL_INTERVAL, > + =A0 =A0 =A0 TCA_CODEL_ECN, > + =A0 =A0 =A0 __TCA_CODEL_MAX > +}; > + > +#define TCA_CODEL_MAX =A0(__TCA_CODEL_MAX - 1) > + > +struct tc_codel_xstats { > + =A0 =A0 =A0 __u32 =A0 maxpacket; /* largest packet we've seen so far */ > + =A0 =A0 =A0 __u32 =A0 count; > + =A0 =A0 =A0 __u32 =A0 lastcount; > + =A0 =A0 =A0 __u32 =A0 ldelay; /* in-queue delay seen by most recently d= equeued packet */ > + =A0 =A0 =A0 __u32 =A0 drop_next; > + =A0 =A0 =A0 __u32 =A0 drop_overlimit; > + =A0 =A0 =A0 __u32 =A0 ecn_mark; > + =A0 =A0 =A0 __u32 =A0 dropping; > + =A0 =A0 =A0 __u32 =A0 state1; > + =A0 =A0 =A0 __u32 =A0 state2; > + =A0 =A0 =A0 __u32 =A0 state3; > + =A0 =A0 =A0 __u32 =A0 states; > +}; > + > =A0#endif > diff --git a/include/net/codel.h b/include/net/codel.h > new file mode 100644 > index 0000000..565c1fe > --- /dev/null > +++ b/include/net/codel.h > @@ -0,0 +1,325 @@ > +#ifndef __NET_SCHED_CODEL_H > +#define __NET_SCHED_CODEL_H > + > +/* > + * Codel - The Controlled-Delay Active Queue Management algorithm > + * > + * =A0Copyright (C) 2011-2012 Kathleen Nichols > + * =A0Copyright (C) 2011-2012 Van Jacobson > + * =A0Copyright (C) 2012 Michael D. Taht > + * =A0Copyright (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 > + * =A0 =A0notice, this list of conditions, and the following disclaimer, > + * =A0 =A0without modification. > + * 2. Redistributions in binary form must reproduce the above copyright > + * =A0 =A0notice, this list of conditions and the following disclaimer i= n the > + * =A0 =A0documentation and/or other materials provided with the distrib= ution. > + * 3. The names of the authors may not be used to endorse or promote pro= ducts > + * =A0 =A0derived from this software without specific prior written perm= ission. > + * > + * 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 > + > +/* Controlling Queue Delay (CoDel) algorithm > + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + * Source : Kathleen Nichols and Van Jacobson > + * http://queue.acm.org/detail.cfm?id=3D2209396 This link is dead. Looks like it's a typo and should be: http://queue.acm.org/detail.cfm?id=3D2209336 Josh > + * > + * Implemented on linux by Dave Taht and Eric Dumazet > + */ > + > + > +/* > + * CoDel uses a 1024 nsec clock, encoded in u32 > + * This gives a range of 2199 seconds, because of signed compares > + */ > +typedef u32 codel_time_t; > +#define CODEL_SHIFT 10 > +#define MS2TIME(a) ((a * NSEC_PER_MSEC) >> CODEL_SHIFT) > + > +static inline codel_time_t codel_get_time(void) > +{ > + =A0 =A0 =A0 u64 ns =3D ktime_to_ns(ktime_get()); > + > + =A0 =A0 =A0 return ns >> CODEL_SHIFT; > +} > + > +#define codel_time_after(a, b) =A0 =A0 =A0 =A0 ((s32)(a) - (s32)(b) > 0) > +#define codel_time_after_eq(a, b) =A0 =A0 =A0((s32)(a) - (s32)(b) >=3D 0= ) > +#define codel_time_before(a, b) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0((s32)(a)= - (s32)(b) < 0) > +#define codel_time_before_eq(a, b) =A0 =A0 ((s32)(a) - (s32)(b) <=3D 0) > + > +struct codel_skb_cb { > + =A0 =A0 =A0 codel_time_t enqueue_time; > +}; > + > +static struct codel_skb_cb *get_codel_cb(const struct sk_buff *skb) > +{ > + =A0 =A0 =A0 qdisc_cb_private_validate(skb, sizeof(struct codel_skb_cb))= ; > + =A0 =A0 =A0 return (struct codel_skb_cb *)qdisc_skb_cb(skb)->data; > +} > + > +static codel_time_t codel_get_enqueue_time(const struct sk_buff *skb) > +{ > + =A0 =A0 =A0 return get_codel_cb(skb)->enqueue_time; > +} > + > +static void codel_set_enqueue_time(struct sk_buff *skb) > +{ > + =A0 =A0 =A0 get_codel_cb(skb)->enqueue_time =3D codel_get_time(); > +} > + > +static inline u32 codel_time_to_us(codel_time_t val) > +{ > + =A0 =A0 =A0 u64 valns =3D ((u64)val << CODEL_SHIFT); > + > + =A0 =A0 =A0 do_div(valns, NSEC_PER_USEC); > + =A0 =A0 =A0 return (u32)valns; > +} > + > +struct codel_params { > + =A0 =A0 =A0 u32 =A0 =A0 =A0 =A0 =A0 =A0 maxpacket; /* largest packet we= 've seen so far */ > + =A0 =A0 =A0 codel_time_t =A0 =A0target; =A0 /* target queue size (in ti= me units) */ > + =A0 =A0 =A0 codel_time_t =A0 =A0interval; /* width of moving time windo= w */ > + =A0 =A0 =A0 bool =A0 =A0 =A0 =A0 =A0 =A0ecn; =A0 =A0 =A0/* is ECN enabl= ed */ > +}; > + > +struct codel_vars { > + =A0 =A0 =A0 u32 =A0 =A0 =A0 =A0 =A0 =A0 count; =A0/* how many drops we'= ve done since the last time > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* we ent= ered dropping state > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/ > + =A0 =A0 =A0 u32 =A0 =A0 =A0 =A0 =A0 =A0 lastcount; =A0 =A0 =A0/* count = at entry to dropping state */ > + =A0 =A0 =A0 bool =A0 =A0 =A0 =A0 =A0 =A0dropping; =A0 =A0 =A0 /* set to= true id in dropping state */ > + > + =A0 =A0 =A0 codel_time_t =A0 =A0first_above_time; /* when we went (or w= ill go) continuously > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0* above target for interval > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0*/ > + =A0 =A0 =A0 codel_time_t =A0 =A0drop_next; =A0 =A0 =A0/* time to drop n= ext packet, or when we dropped last */ > + =A0 =A0 =A0 codel_time_t =A0 =A0ldelay; /* sojourn time of last dequeue= d packet */ > +}; > + > +/* contains stats and some shared info */ > +struct codel_stats { > + =A0 =A0 =A0 struct Qdisc =A0 =A0*sch; > + =A0 =A0 =A0 u32 =A0 =A0 =A0 =A0 =A0 =A0 drop_count; /* temp count of dr= opped packets in dequeue() */ > + > + =A0 =A0 =A0 u32 =A0 =A0 =A0 =A0 =A0 =A0 ecn_mark; /* number of packets = we ECN marked instead of dropping */ > + =A0 =A0 =A0 u32 =A0 =A0 =A0 =A0 =A0 =A0 states; /* number of codel_dequ= eue() calls */ > + =A0 =A0 =A0 u32 =A0 =A0 =A0 =A0 =A0 =A0 state1; /* number of times ok_t= o_drop was set to true */ > + =A0 =A0 =A0 u32 =A0 =A0 =A0 =A0 =A0 =A0 state2; > + =A0 =A0 =A0 u32 =A0 =A0 =A0 =A0 =A0 =A0 state3; > +}; > + > +static void codel_params_init(struct codel_params *params, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 const struct Qd= isc *sch) > +{ > + =A0 =A0 =A0 params->maxpacket =3D 256; > + =A0 =A0 =A0 params->interval =3D MS2TIME(100); > + =A0 =A0 =A0 params->target =3D MS2TIME(5); > + =A0 =A0 =A0 params->ecn =3D false; > +} > + > +static void codel_vars_init(struct codel_vars *vars) > +{ > + =A0 =A0 =A0 vars->drop_next =3D 0; > + =A0 =A0 =A0 vars->first_above_time =3D 0; > + =A0 =A0 =A0 vars->dropping =3D false; /* exit dropping state */ > + =A0 =A0 =A0 vars->count =3D 0; > + =A0 =A0 =A0 vars->lastcount =3D 0; > +} > + > +static void codel_stats_init(struct codel_stats *stats, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct Qdisc *sc= h) > +{ > + =A0 =A0 =A0 stats->sch =3D sch; /* back pointer for qdisc_drop() calls = */ > +} > + > +/* return interval/sqrt(x) with good precision */ > +static u32 codel_inv_sqrt(u32 _interval, u32 _x) > +{ > + =A0 =A0 =A0 u64 interval =3D _interval; > + =A0 =A0 =A0 unsigned long x =3D _x; > + > + =A0 =A0 =A0 /* Scale operands for max precision */ > + > +#if BITS_PER_LONG =3D=3D 64 > + =A0 =A0 =A0 x <<=3D 32; /* On 64bit arches, we can prescale x by 32bits= */ > + =A0 =A0 =A0 interval <<=3D 16; > +#endif > + > + =A0 =A0 =A0 while (x < (1UL << (BITS_PER_LONG - 2))) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 x <<=3D 2; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 interval <<=3D 1; > + =A0 =A0 =A0 } > + =A0 =A0 =A0 do_div(interval, int_sqrt(x)); > + =A0 =A0 =A0 return (u32)interval; > +} > + > +static codel_time_t codel_control_law(codel_time_t t, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= codel_time_t interval, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= u32 count) > +{ > + =A0 =A0 =A0 return t + codel_inv_sqrt(interval, count); > +} > + > + > +static bool codel_should_drop(struct sk_buff *skb, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *b= acklog, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct codel_va= rs *vars, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct codel_pa= rams *params, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct codel_st= ats *stats, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 codel_time_t no= w) > +{ > + =A0 =A0 =A0 bool ok_to_drop; > + > + =A0 =A0 =A0 if (!skb) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->first_above_time =3D 0; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return false; > + =A0 =A0 =A0 } > + > + =A0 =A0 =A0 vars->ldelay =3D now - codel_get_enqueue_time(skb); > + =A0 =A0 =A0 *backlog -=3D qdisc_pkt_len(skb); > + > + =A0 =A0 =A0 if (unlikely(qdisc_pkt_len(skb) > params->maxpacket)) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 params->maxpacket =3D qdisc_pkt_len(skb); > + > + =A0 =A0 =A0 if (codel_time_before(vars->ldelay, params->target) || > + =A0 =A0 =A0 =A0 =A0 *backlog <=3D params->maxpacket) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* went below - stay below for at least int= erval */ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->first_above_time =3D 0; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return false; > + =A0 =A0 =A0 } > + =A0 =A0 =A0 ok_to_drop =3D false; > + =A0 =A0 =A0 if (vars->first_above_time =3D=3D 0) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* just went above from below. If we stay a= bove > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* for at least interval we'll say it's o= k to drop > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->first_above_time =3D now + params->in= terval; > + =A0 =A0 =A0 } else if (codel_time_after(now, vars->first_above_time)) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ok_to_drop =3D true; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 stats->state1++; > + =A0 =A0 =A0 } > + =A0 =A0 =A0 return ok_to_drop; > +} > + > +typedef struct sk_buff * (*codel_skb_dequeue_t)(struct codel_vars *vars, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 struct Qdisc *sch); > + > +static struct sk_buff *codel_dequeue(struct codel_params *params, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= struct codel_vars *vars, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= struct codel_stats *stats, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= codel_skb_dequeue_t dequeue_func, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= u32 *backlog) > +{ > + =A0 =A0 =A0 struct sk_buff *skb =3D dequeue_func(vars, stats->sch); > + =A0 =A0 =A0 codel_time_t now; > + =A0 =A0 =A0 bool drop; > + > + =A0 =A0 =A0 stats->states++; > + =A0 =A0 =A0 if (!skb) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->dropping =3D false; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return skb; > + =A0 =A0 =A0 } > + =A0 =A0 =A0 now =3D codel_get_time(); > + =A0 =A0 =A0 drop =3D codel_should_drop(skb, backlog, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars, param= s, stats, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 now); > + =A0 =A0 =A0 if (vars->dropping) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!drop) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* sojourn time below targe= t - leave dropping state */ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->dropping =3D false; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else if (codel_time_after_eq(now, vars->d= rop_next)) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 stats->state2++; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* It's time for the next d= rop. Drop the current > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* packet and dequeue the= next. The dequeue might > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* take us out of droppin= g state. > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* If not, schedule the n= ext drop. > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* A large backlog might = result in drop rates so high > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* that the next drop sho= uld happen now, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* hence the while loop. > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 while (vars->dropping && > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0codel_time_a= fter_eq(now, vars->drop_next)) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->count= ++; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (params-= >ecn && INET_ECN_set_ce(skb)) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 stats->ecn_mark++; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 vars->drop_next =3D > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 codel_control_law(vars->drop_next, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 params->interval, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->count); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 goto end; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qdisc_drop(= skb, stats->sch); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 stats->drop= _count++; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 skb =3D deq= ueue_func(vars, stats->sch); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!codel_= should_drop(skb, backlog, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0vars, params, stats, now)) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 /* leave dropping state */ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 vars->dropping =3D false; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 /* and schedule the next drop */ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 vars->drop_next =3D > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 codel_control_law(vars->drop_next, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 params->interval, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->count); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 } else if (drop) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (params->ecn && INET_ECN_set_ce(skb)) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 stats->ecn_mark++; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qdisc_drop(skb, stats->sch)= ; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 stats->drop_count++; > + > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 skb =3D dequeue_func(vars, = stats->sch); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 drop =3D codel_should_drop(= skb, backlog, vars, params, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0stats, now); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->dropping =3D true; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 stats->state3++; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* if min went above target close to when= we last went below it > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* assume that the drop rate that control= led the queue on the > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* last cycle is a good starting point to= control it now. > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (codel_time_before(now - vars->drop_next= , > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= 16 * params->interval)) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->count =3D vars->count= - vars->lastcount + 1; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->count =3D 1; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->lastcount =3D vars->count; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->drop_next =3D codel_control_law(now, = params->interval, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 vars->count); > + =A0 =A0 =A0 } > +end: > + =A0 =A0 =A0 return skb; > +} > +#endif > diff --git a/net/sched/Kconfig b/net/sched/Kconfig > index 75b58f8..fadd252 100644 > --- a/net/sched/Kconfig > +++ b/net/sched/Kconfig > @@ -250,6 +250,17 @@ config NET_SCH_QFQ > > =A0 =A0 =A0 =A0 =A0If unsure, say N. > > +config NET_SCH_CODEL > + =A0 =A0 =A0 tristate "Controlled Delay AQM (CODEL)" > + =A0 =A0 =A0 help > + =A0 =A0 =A0 =A0 Say Y here if you want to use the Controlled Delay (COD= EL) > + =A0 =A0 =A0 =A0 packet scheduling algorithm. > + > + =A0 =A0 =A0 =A0 To compile this driver as a module, choose M here: the = module > + =A0 =A0 =A0 =A0 will be called sch_codel. > + > + =A0 =A0 =A0 =A0 If unsure, say N. > + > =A0config NET_SCH_INGRESS > =A0 =A0 =A0 =A0tristate "Ingress Qdisc" > =A0 =A0 =A0 =A0depends on NET_CLS_ACT > diff --git a/net/sched/Makefile b/net/sched/Makefile > index 8cdf4e2..30fab03 100644 > --- a/net/sched/Makefile > +++ b/net/sched/Makefile > @@ -37,6 +37,7 @@ obj-$(CONFIG_NET_SCH_PLUG) =A0 =A0+=3D sch_plug.o > =A0obj-$(CONFIG_NET_SCH_MQPRIO) =A0 +=3D sch_mqprio.o > =A0obj-$(CONFIG_NET_SCH_CHOKE) =A0 =A0+=3D sch_choke.o > =A0obj-$(CONFIG_NET_SCH_QFQ) =A0 =A0 =A0+=3D sch_qfq.o > +obj-$(CONFIG_NET_SCH_CODEL) =A0 =A0+=3D sch_codel.o > > =A0obj-$(CONFIG_NET_CLS_U32) =A0 =A0 =A0+=3D cls_u32.o > =A0obj-$(CONFIG_NET_CLS_ROUTE4) =A0 +=3D cls_route.o > diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c > new file mode 100644 > index 0000000..3112afa > --- /dev/null > +++ b/net/sched/sch_codel.c > @@ -0,0 +1,272 @@ > +/* > + * Codel - The Controlled-Delay Active Queue Management algorithm > + * > + * =A0Copyright (C) 2011-2012 Kathleen Nichols > + * =A0Copyright (C) 2011-2012 Van Jacobson > + * > + * =A0Implemented on linux by : > + * =A0Copyright (C) 2012 Michael D. Taht > + * =A0Copyright (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 > + * =A0 =A0notice, this list of conditions, and the following disclaimer, > + * =A0 =A0without modification. > + * 2. Redistributions in binary form must reproduce the above copyright > + * =A0 =A0notice, this list of conditions and the following disclaimer i= n the > + * =A0 =A0documentation and/or other materials provided with the distrib= ution. > + * 3. The names of the authors may not be used to endorse or promote pro= ducts > + * =A0 =A0derived from this software without specific prior written perm= ission. > + * > + * 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 > + > + > +#define DEFAULT_CODEL_LIMIT 1000 > + > +struct codel_sched_data { > + =A0 =A0 =A0 struct codel_params =A0 =A0 params; > + =A0 =A0 =A0 struct codel_vars =A0 =A0 =A0 vars; > + =A0 =A0 =A0 struct codel_stats =A0 =A0 =A0stats; > + =A0 =A0 =A0 u32 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 drop_overlimit; > +}; > + > +/* This is the specific function called from codel_dequeue() > + * to dequeue a packet from queue. Note: backlog is handled in > + * codel, we dont need to reduce it here. > + */ > +static struct sk_buff *dequeue(struct codel_vars *vars, struct Qdisc *sc= h) > +{ > + =A0 =A0 =A0 struct sk_buff *skb =3D __skb_dequeue(&sch->q); > + > + =A0 =A0 =A0 prefetch(&skb->end); /* we'll need skb_shinfo() */ > + =A0 =A0 =A0 return skb; > +} > + > +static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch) > +{ > + =A0 =A0 =A0 struct codel_sched_data *q =3D qdisc_priv(sch); > + =A0 =A0 =A0 struct sk_buff *skb; > + > + =A0 =A0 =A0 skb =3D codel_dequeue(&q->params, &q->vars, &q->stats, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dequeue, &sch->qsta= ts.backlog); > + =A0 =A0 =A0 /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0= , > + =A0 =A0 =A0 =A0* or HTB crashes. Defer it for next round. > + =A0 =A0 =A0 =A0*/ > + =A0 =A0 =A0 if (q->stats.drop_count && sch->q.qlen) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qdisc_tree_decrease_qlen(sch, q->stats.drop= _count); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 q->stats.drop_count =3D 0; > + =A0 =A0 =A0 } > + =A0 =A0 =A0 if (skb) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qdisc_bstats_update(sch, skb); > + =A0 =A0 =A0 return skb; > +} > + > +static int codel_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch) > +{ > + =A0 =A0 =A0 struct codel_sched_data *q; > + > + =A0 =A0 =A0 if (likely(qdisc_qlen(sch) < sch->limit)) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 codel_set_enqueue_time(skb); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return qdisc_enqueue_tail(skb, sch); > + =A0 =A0 =A0 } > + =A0 =A0 =A0 q =3D qdisc_priv(sch); > + =A0 =A0 =A0 q->drop_overlimit++; > + =A0 =A0 =A0 return qdisc_drop(skb, sch); > +} > + > +static const struct nla_policy codel_policy[TCA_CODEL_MAX + 1] =3D { > + =A0 =A0 =A0 [TCA_CODEL_TARGET] =A0 =A0 =A0=3D { .type =3D NLA_U32 }, > + =A0 =A0 =A0 [TCA_CODEL_LIMIT] =A0 =A0 =A0 =3D { .type =3D NLA_U32 }, > + =A0 =A0 =A0 [TCA_CODEL_INTERVAL] =A0 =A0=3D { .type =3D NLA_U32 }, > + =A0 =A0 =A0 [TCA_CODEL_ECN] =A0 =A0 =A0 =A0 =3D { .type =3D NLA_U32 }, > +}; > + > +static int codel_change(struct Qdisc *sch, struct nlattr *opt) > +{ > + =A0 =A0 =A0 struct codel_sched_data *q =3D qdisc_priv(sch); > + =A0 =A0 =A0 struct nlattr *tb[TCA_CODEL_MAX + 1]; > + =A0 =A0 =A0 unsigned int qlen; > + =A0 =A0 =A0 int err; > + > + =A0 =A0 =A0 if (!opt) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL; > + > + =A0 =A0 =A0 err =3D nla_parse_nested(tb, TCA_CODEL_MAX, opt, codel_poli= cy); > + =A0 =A0 =A0 if (err < 0) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return err; > + > + =A0 =A0 =A0 sch_tree_lock(sch); > + =A0 =A0 =A0 if (tb[TCA_CODEL_TARGET]) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 target =3D nla_get_u32(tb[TCA_CODEL_TAR= GET]); > + > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 q->params.target =3D ((u64)target * NSEC_PE= R_USEC) >> CODEL_SHIFT; > + =A0 =A0 =A0 } > + =A0 =A0 =A0 if (tb[TCA_CODEL_INTERVAL]) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 interval =3D nla_get_u32(tb[TCA_CODEL_I= NTERVAL]); > + > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 q->params.interval =3D ((u64)interval * NSE= C_PER_USEC) >> CODEL_SHIFT; > + =A0 =A0 =A0 } > + =A0 =A0 =A0 if (tb[TCA_CODEL_LIMIT]) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 sch->limit =3D nla_get_u32(tb[TCA_CODEL_LIM= IT]); > + > + =A0 =A0 =A0 if (tb[TCA_CODEL_ECN]) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 q->params.ecn =3D !!nla_get_u32(tb[TCA_CODE= L_ECN]); > + > + =A0 =A0 =A0 qlen =3D sch->q.qlen; > + =A0 =A0 =A0 while (sch->q.qlen > sch->limit) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct sk_buff *skb =3D __skb_dequeue(&sch-= >q); > + > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 sch->qstats.backlog -=3D qdisc_pkt_len(skb)= ; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qdisc_drop(skb, sch); > + =A0 =A0 =A0 } > + =A0 =A0 =A0 qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); > + > + =A0 =A0 =A0 sch_tree_unlock(sch); > + =A0 =A0 =A0 return 0; > +} > + > +static int codel_init(struct Qdisc *sch, struct nlattr *opt) > +{ > + =A0 =A0 =A0 struct codel_sched_data *q =3D qdisc_priv(sch); > + > + =A0 =A0 =A0 /* It should be possible to run with no limit, > + =A0 =A0 =A0 =A0* with infinite memory :) > + =A0 =A0 =A0 =A0*/ > + =A0 =A0 =A0 sch->limit =3D DEFAULT_CODEL_LIMIT; > + > + =A0 =A0 =A0 codel_params_init(&q->params, sch); > + =A0 =A0 =A0 codel_vars_init(&q->vars); > + =A0 =A0 =A0 codel_stats_init(&q->stats, sch); > + > + =A0 =A0 =A0 if (opt) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 int err =3D codel_change(sch, opt); > + > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (err) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return err; > + =A0 =A0 =A0 } > + > + =A0 =A0 =A0 if (sch->limit >=3D 1) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 sch->flags |=3D TCQ_F_CAN_BYPASS; > + =A0 =A0 =A0 else > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 sch->flags &=3D ~TCQ_F_CAN_BYPASS; > + > + =A0 =A0 =A0 return 0; > +} > + > +static int codel_dump(struct Qdisc *sch, struct sk_buff *skb) > +{ > + =A0 =A0 =A0 struct codel_sched_data *q =3D qdisc_priv(sch); > + =A0 =A0 =A0 struct nlattr *opts; > + > + =A0 =A0 =A0 opts =3D nla_nest_start(skb, TCA_OPTIONS); > + =A0 =A0 =A0 if (opts =3D=3D NULL) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto nla_put_failure; > + > + =A0 =A0 =A0 if (nla_put_u32(skb, TCA_CODEL_TARGET, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 codel_time_to_us(q->params.= target)) || > + =A0 =A0 =A0 =A0 =A0 nla_put_u32(skb, TCA_CODEL_LIMIT, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 sch->limit) || > + =A0 =A0 =A0 =A0 =A0 nla_put_u32(skb, TCA_CODEL_INTERVAL, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 codel_time_to_us(q->params.= interval)) || > + =A0 =A0 =A0 =A0 =A0 nla_put_u32(skb, TCA_CODEL_ECN, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 q->params.ecn)) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto nla_put_failure; > + > + =A0 =A0 =A0 return nla_nest_end(skb, opts); > + > +nla_put_failure: > + =A0 =A0 =A0 nla_nest_cancel(skb, opts); > + =A0 =A0 =A0 return -1; > +} > + > +static int codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) > +{ > + =A0 =A0 =A0 const struct codel_sched_data *q =3D qdisc_priv(sch); > + =A0 =A0 =A0 struct tc_codel_xstats st =3D { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .maxpacket =3D q->params.maxpacket, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .count =A0=3D q->vars.count, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .lastcount =3D q->vars.lastcount, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .states =3D q->stats.states, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .state1 =3D q->stats.state1, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .state2 =3D q->stats.state2, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .state3 =3D q->stats.state3, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .drop_overlimit =3D q->drop_overlimit, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .ldelay =3D codel_time_to_us(q->vars.ldelay= ), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .dropping =3D q->vars.dropping, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .ecn_mark =3D q->stats.ecn_mark, > + =A0 =A0 =A0 }; > + > + =A0 =A0 =A0 if (q->vars.dropping && q->vars.drop_next) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 st.drop_next =3D codel_time_to_us(q->vars.d= rop_next - > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 codel_get_time()); > + > + =A0 =A0 =A0 return gnet_stats_copy_app(d, &st, sizeof(st)); > +} > + > +static void codel_reset(struct Qdisc *sch) > +{ > + =A0 =A0 =A0 struct codel_sched_data *q =3D qdisc_priv(sch); > + > + =A0 =A0 =A0 qdisc_reset_queue(sch); > + =A0 =A0 =A0 codel_vars_init(&q->vars); > +} > + > +static struct Qdisc_ops codel_qdisc_ops __read_mostly =3D { > + =A0 =A0 =A0 .id =A0 =A0 =A0 =A0 =A0 =A0 =3D =A0 =A0 =A0 "codel", > + =A0 =A0 =A0 .priv_size =A0 =A0 =A0=3D =A0 =A0 =A0 sizeof(struct codel_s= ched_data), > + > + =A0 =A0 =A0 .enqueue =A0 =A0 =A0 =A0=3D =A0 =A0 =A0 codel_qdisc_enqueue= , > + =A0 =A0 =A0 .dequeue =A0 =A0 =A0 =A0=3D =A0 =A0 =A0 codel_qdisc_dequeue= , > + =A0 =A0 =A0 .peek =A0 =A0 =A0 =A0 =A0 =3D =A0 =A0 =A0 qdisc_peek_dequeu= ed, > + =A0 =A0 =A0 .init =A0 =A0 =A0 =A0 =A0 =3D =A0 =A0 =A0 codel_init, > + =A0 =A0 =A0 .reset =A0 =A0 =A0 =A0 =A0=3D =A0 =A0 =A0 codel_reset, > + =A0 =A0 =A0 .change =A0 =A0 =A0 =A0 =3D =A0 =A0 =A0 codel_change, > + =A0 =A0 =A0 .dump =A0 =A0 =A0 =A0 =A0 =3D =A0 =A0 =A0 codel_dump, > + =A0 =A0 =A0 .dump_stats =A0 =A0 =3D =A0 =A0 =A0 codel_dump_stats, > + =A0 =A0 =A0 .owner =A0 =A0 =A0 =A0 =A0=3D =A0 =A0 =A0 THIS_MODULE, > +}; > + > +static int __init codel_module_init(void) > +{ > + =A0 =A0 =A0 return register_qdisc(&codel_qdisc_ops); > +} > +static void __exit codel_module_exit(void) > +{ > + =A0 =A0 =A0 unregister_qdisc(&codel_qdisc_ops); > +} > +module_init(codel_module_init) > +module_exit(codel_module_exit) > + > +MODULE_DESCRIPTION("Controlled Delay queue discipline"); > +MODULE_AUTHOR("Dave Taht"); > +MODULE_AUTHOR("Eric Dumazet"); > +MODULE_LICENSE("Dual BSD/GPL"); > > > _______________________________________________ > Bloat mailing list > Bloat@lists.bufferbloat.net > https://lists.bufferbloat.net/listinfo/bloat