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