176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet/* 276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * Codel - The Controlled-Delay Active Queue Management algorithm 376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * 476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * Copyright (C) 2011-2012 Kathleen Nichols <nichols@pollere.com> 576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * Copyright (C) 2011-2012 Van Jacobson <van@pollere.net> 676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * 776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * Implemented on linux by : 876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * Copyright (C) 2012 Michael D. Taht <dave.taht@bufferbloat.net> 976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * Copyright (C) 2012 Eric Dumazet <edumazet@google.com> 1076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * 1176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * Redistribution and use in source and binary forms, with or without 1276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * modification, are permitted provided that the following conditions 1376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * are met: 1476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * 1. Redistributions of source code must retain the above copyright 1576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * notice, this list of conditions, and the following disclaimer, 1676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * without modification. 1776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * 2. Redistributions in binary form must reproduce the above copyright 1876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * notice, this list of conditions and the following disclaimer in the 1976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * documentation and/or other materials provided with the distribution. 2076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * 3. The names of the authors may not be used to endorse or promote products 2176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * derived from this software without specific prior written permission. 2276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * 2376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * Alternatively, provided that this notice is retained in full, this 2476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * software may be distributed under the terms of the GNU General 2576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * Public License ("GPL") version 2, in which case the provisions of the 2676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * GPL apply INSTEAD OF those given above. 2776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * 2876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 3976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * DAMAGE. 4076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * 4176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet */ 4276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 4376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet#include <linux/module.h> 4476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet#include <linux/slab.h> 4576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet#include <linux/types.h> 4676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet#include <linux/kernel.h> 4776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet#include <linux/errno.h> 4876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet#include <linux/skbuff.h> 49ce5b4b977127ee20c3f9c3fd3637cd3796f649f5Geert Uytterhoeven#include <linux/prefetch.h> 5076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet#include <net/pkt_sched.h> 5176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet#include <net/codel.h> 5276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 5376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 5476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet#define DEFAULT_CODEL_LIMIT 1000 5576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 5676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstruct codel_sched_data { 5776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct codel_params params; 5876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct codel_vars vars; 5976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct codel_stats stats; 6076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet u32 drop_overlimit; 6176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet}; 6276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 6376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet/* This is the specific function called from codel_dequeue() 6476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * to dequeue a packet from queue. Note: backlog is handled in 6576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * codel, we dont need to reduce it here. 6676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet */ 6776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic struct sk_buff *dequeue(struct codel_vars *vars, struct Qdisc *sch) 6876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet{ 6976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct sk_buff *skb = __skb_dequeue(&sch->q); 7076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 7176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet prefetch(&skb->end); /* we'll need skb_shinfo() */ 7276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return skb; 7376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet} 7476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 7576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch) 7676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet{ 7776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct codel_sched_data *q = qdisc_priv(sch); 7876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct sk_buff *skb; 7976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 80865ec5523dadbedefbc5710a68969f686a28d928Eric Dumazet skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, dequeue); 81865ec5523dadbedefbc5710a68969f686a28d928Eric Dumazet 8276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0, 8376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet * or HTB crashes. Defer it for next round. 8476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet */ 8576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (q->stats.drop_count && sch->q.qlen) { 8676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet qdisc_tree_decrease_qlen(sch, q->stats.drop_count); 8776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet q->stats.drop_count = 0; 8876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet } 8976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (skb) 9076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet qdisc_bstats_update(sch, skb); 9176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return skb; 9276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet} 9376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 9476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic int codel_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch) 9576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet{ 9676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct codel_sched_data *q; 9776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 9876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (likely(qdisc_qlen(sch) < sch->limit)) { 9976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet codel_set_enqueue_time(skb); 10076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return qdisc_enqueue_tail(skb, sch); 10176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet } 10276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet q = qdisc_priv(sch); 10376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet q->drop_overlimit++; 10476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return qdisc_drop(skb, sch); 10576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet} 10676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 10776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic const struct nla_policy codel_policy[TCA_CODEL_MAX + 1] = { 10876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet [TCA_CODEL_TARGET] = { .type = NLA_U32 }, 10976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet [TCA_CODEL_LIMIT] = { .type = NLA_U32 }, 11076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet [TCA_CODEL_INTERVAL] = { .type = NLA_U32 }, 11176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet [TCA_CODEL_ECN] = { .type = NLA_U32 }, 11276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet}; 11376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 11476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic int codel_change(struct Qdisc *sch, struct nlattr *opt) 11576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet{ 11676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct codel_sched_data *q = qdisc_priv(sch); 11776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct nlattr *tb[TCA_CODEL_MAX + 1]; 11876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet unsigned int qlen; 11976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet int err; 12076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 12176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (!opt) 12276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return -EINVAL; 12376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 12476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet err = nla_parse_nested(tb, TCA_CODEL_MAX, opt, codel_policy); 12576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (err < 0) 12676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return err; 12776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 12876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet sch_tree_lock(sch); 12976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 13076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (tb[TCA_CODEL_TARGET]) { 13176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet u32 target = nla_get_u32(tb[TCA_CODEL_TARGET]); 13276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 13376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet q->params.target = ((u64)target * NSEC_PER_USEC) >> CODEL_SHIFT; 13476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet } 13576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 13676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (tb[TCA_CODEL_INTERVAL]) { 13776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet u32 interval = nla_get_u32(tb[TCA_CODEL_INTERVAL]); 13876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 13976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet q->params.interval = ((u64)interval * NSEC_PER_USEC) >> CODEL_SHIFT; 14076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet } 14176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 14276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (tb[TCA_CODEL_LIMIT]) 14376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet sch->limit = nla_get_u32(tb[TCA_CODEL_LIMIT]); 14476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 14576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (tb[TCA_CODEL_ECN]) 14676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet q->params.ecn = !!nla_get_u32(tb[TCA_CODEL_ECN]); 14776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 14876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet qlen = sch->q.qlen; 14976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet while (sch->q.qlen > sch->limit) { 15076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct sk_buff *skb = __skb_dequeue(&sch->q); 15176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 15225331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend qdisc_qstats_backlog_dec(sch, skb); 15376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet qdisc_drop(skb, sch); 15476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet } 15576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); 15676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 15776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet sch_tree_unlock(sch); 15876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return 0; 15976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet} 16076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 16176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic int codel_init(struct Qdisc *sch, struct nlattr *opt) 16276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet{ 16376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct codel_sched_data *q = qdisc_priv(sch); 16476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 16576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet sch->limit = DEFAULT_CODEL_LIMIT; 16676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 16776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet codel_params_init(&q->params); 16876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet codel_vars_init(&q->vars); 16976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet codel_stats_init(&q->stats); 17076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 17176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (opt) { 17276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet int err = codel_change(sch, opt); 17376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 17476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (err) 17576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return err; 17676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet } 17776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 17876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (sch->limit >= 1) 17976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet sch->flags |= TCQ_F_CAN_BYPASS; 18076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet else 18176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet sch->flags &= ~TCQ_F_CAN_BYPASS; 18276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 18376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return 0; 18476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet} 18576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 18676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic int codel_dump(struct Qdisc *sch, struct sk_buff *skb) 18776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet{ 18876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct codel_sched_data *q = qdisc_priv(sch); 18976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct nlattr *opts; 19076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 19176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet opts = nla_nest_start(skb, TCA_OPTIONS); 19276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (opts == NULL) 19376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet goto nla_put_failure; 19476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 19576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (nla_put_u32(skb, TCA_CODEL_TARGET, 19676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet codel_time_to_us(q->params.target)) || 19776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet nla_put_u32(skb, TCA_CODEL_LIMIT, 19876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet sch->limit) || 19976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet nla_put_u32(skb, TCA_CODEL_INTERVAL, 20076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet codel_time_to_us(q->params.interval)) || 20176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet nla_put_u32(skb, TCA_CODEL_ECN, 20276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet q->params.ecn)) 20376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet goto nla_put_failure; 20476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 20576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return nla_nest_end(skb, opts); 20676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 20776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetnla_put_failure: 20876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet nla_nest_cancel(skb, opts); 20976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return -1; 21076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet} 21176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 21276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic int codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) 21376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet{ 21476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet const struct codel_sched_data *q = qdisc_priv(sch); 21576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct tc_codel_xstats st = { 21676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .maxpacket = q->stats.maxpacket, 21776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .count = q->vars.count, 21876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .lastcount = q->vars.lastcount, 21976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .drop_overlimit = q->drop_overlimit, 22076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .ldelay = codel_time_to_us(q->vars.ldelay), 22176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .dropping = q->vars.dropping, 22276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .ecn_mark = q->stats.ecn_mark, 22376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet }; 22476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 22576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (q->vars.dropping) { 22676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet codel_tdiff_t delta = q->vars.drop_next - codel_get_time(); 22776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 22876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet if (delta >= 0) 22976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet st.drop_next = codel_time_to_us(delta); 23076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet else 23176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet st.drop_next = -codel_time_to_us(-delta); 23276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet } 23376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 23476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return gnet_stats_copy_app(d, &st, sizeof(st)); 23576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet} 23676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 23776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic void codel_reset(struct Qdisc *sch) 23876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet{ 23976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet struct codel_sched_data *q = qdisc_priv(sch); 24076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 24176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet qdisc_reset_queue(sch); 24276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet codel_vars_init(&q->vars); 24376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet} 24476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 24576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic struct Qdisc_ops codel_qdisc_ops __read_mostly = { 24676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .id = "codel", 24776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .priv_size = sizeof(struct codel_sched_data), 24876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 24976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .enqueue = codel_qdisc_enqueue, 25076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .dequeue = codel_qdisc_dequeue, 25176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .peek = qdisc_peek_dequeued, 25276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .init = codel_init, 25376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .reset = codel_reset, 25476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .change = codel_change, 25576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .dump = codel_dump, 25676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .dump_stats = codel_dump_stats, 25776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet .owner = THIS_MODULE, 25876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet}; 25976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 26076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic int __init codel_module_init(void) 26176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet{ 26276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet return register_qdisc(&codel_qdisc_ops); 26376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet} 26476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 26576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetstatic void __exit codel_module_exit(void) 26676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet{ 26776e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet unregister_qdisc(&codel_qdisc_ops); 26876e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet} 26976e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 27076e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetmodule_init(codel_module_init) 27176e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazetmodule_exit(codel_module_exit) 27276e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric Dumazet 27376e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric DumazetMODULE_DESCRIPTION("Controlled Delay queue discipline"); 27476e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric DumazetMODULE_AUTHOR("Dave Taht"); 27576e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric DumazetMODULE_AUTHOR("Eric Dumazet"); 27676e3cc126bb223013a6b9a0e2a51238d1ef2e409Eric DumazetMODULE_LICENSE("Dual BSD/GPL"); 277