113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy/*
213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy * net/sched/sch_drr.c         Deficit Round Robin scheduler
313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy *
413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy *
613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy * This program is free software; you can redistribute it and/or
713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy * modify it under the terms of the GNU General Public License
813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy * version 2 as published by the Free Software Foundation.
913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy */
1013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
1113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy#include <linux/module.h>
125a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
1313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy#include <linux/init.h>
1413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy#include <linux/errno.h>
1513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy#include <linux/netdevice.h>
1613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy#include <linux/pkt_sched.h>
1713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy#include <net/sch_generic.h>
1813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy#include <net/pkt_sched.h>
1913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy#include <net/pkt_cls.h>
2013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
2113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystruct drr_class {
2213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct Qdisc_class_common	common;
2313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	unsigned int			refcnt;
2413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	unsigned int			filter_cnt;
2513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
26c1a8f1f1c8e01eab5862c8db39b49ace814e6c66Eric Dumazet	struct gnet_stats_basic_packed		bstats;
2713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct gnet_stats_queue		qstats;
2845203a3b380cee28f570475c0d28c169f908c209Eric Dumazet	struct gnet_stats_rate_est64	rate_est;
2913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct list_head		alist;
3013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct Qdisc			*qdisc;
3113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
3213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	u32				quantum;
3313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	u32				deficit;
3413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy};
3513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
3613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystruct drr_sched {
3713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct list_head		active;
3825d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend	struct tcf_proto __rcu		*filter_list;
3913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct Qdisc_class_hash		clhash;
4013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy};
4113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
4213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
4313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
4413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
4513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct Qdisc_class_common *clc;
4613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
4713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	clc = qdisc_class_find(&q->clhash, classid);
4813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (clc == NULL)
4913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return NULL;
5013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return container_of(clc, struct drr_class, common);
5113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
5213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
5313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic void drr_purge_queue(struct drr_class *cl)
5413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
5513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	unsigned int len = cl->qdisc->q.qlen;
5613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
5713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	qdisc_reset(cl->qdisc);
5813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	qdisc_tree_decrease_qlen(cl->qdisc, len);
5913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
6013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
6113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = {
6213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	[TCA_DRR_QUANTUM]	= { .type = NLA_U32 },
6313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy};
6413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
6513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
6613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			    struct nlattr **tca, unsigned long *arg)
6713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
6813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
6913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl = (struct drr_class *)*arg;
701844f747947bb89d7f12cd3034548805113f764bJarek Poplawski	struct nlattr *opt = tca[TCA_OPTIONS];
7113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct nlattr *tb[TCA_DRR_MAX + 1];
7213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	u32 quantum;
7313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	int err;
7413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
751844f747947bb89d7f12cd3034548805113f764bJarek Poplawski	if (!opt)
761844f747947bb89d7f12cd3034548805113f764bJarek Poplawski		return -EINVAL;
771844f747947bb89d7f12cd3034548805113f764bJarek Poplawski
781844f747947bb89d7f12cd3034548805113f764bJarek Poplawski	err = nla_parse_nested(tb, TCA_DRR_MAX, opt, drr_policy);
7913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (err < 0)
8013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return err;
8113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
8213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (tb[TCA_DRR_QUANTUM]) {
8313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		quantum = nla_get_u32(tb[TCA_DRR_QUANTUM]);
8413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		if (quantum == 0)
8513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			return -EINVAL;
8613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	} else
8713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		quantum = psched_mtu(qdisc_dev(sch));
8813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
8913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (cl != NULL) {
9071bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger		if (tca[TCA_RATE]) {
9122e0f8b9322cb1a48b1357e8f4ae6f5a9eca8cfaJohn Fastabend			err = gen_replace_estimator(&cl->bstats, NULL,
9222e0f8b9322cb1a48b1357e8f4ae6f5a9eca8cfaJohn Fastabend						    &cl->rate_est,
9371bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger						    qdisc_root_sleeping_lock(sch),
9471bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger						    tca[TCA_RATE]);
9571bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger			if (err)
9671bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger				return err;
9771bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger		}
9871bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger
9913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		sch_tree_lock(sch);
10013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		if (tb[TCA_DRR_QUANTUM])
10113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			cl->quantum = quantum;
10213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		sch_tree_unlock(sch);
10313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
10413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return 0;
10513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
10613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
10713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	cl = kzalloc(sizeof(struct drr_class), GFP_KERNEL);
10813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (cl == NULL)
10913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return -ENOBUFS;
11013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
11113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	cl->refcnt	   = 1;
11213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	cl->common.classid = classid;
11313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	cl->quantum	   = quantum;
1143511c9132f8b1e1b5634e41a3331c44b0c13be70Changli Gao	cl->qdisc	   = qdisc_create_dflt(sch->dev_queue,
11513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy					       &pfifo_qdisc_ops, classid);
11613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (cl->qdisc == NULL)
11713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		cl->qdisc = &noop_qdisc;
11813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
11971bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger	if (tca[TCA_RATE]) {
12022e0f8b9322cb1a48b1357e8f4ae6f5a9eca8cfaJohn Fastabend		err = gen_replace_estimator(&cl->bstats, NULL, &cl->rate_est,
12171bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger					    qdisc_root_sleeping_lock(sch),
12271bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger					    tca[TCA_RATE]);
12371bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger		if (err) {
12471bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger			qdisc_destroy(cl->qdisc);
12571bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger			kfree(cl);
12671bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger			return err;
12771bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger		}
12871bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger	}
12913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
13013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	sch_tree_lock(sch);
13113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	qdisc_class_hash_insert(&q->clhash, &cl->common);
13213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	sch_tree_unlock(sch);
13313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
13413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	qdisc_class_hash_grow(sch, &q->clhash);
13513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
13613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	*arg = (unsigned long)cl;
13713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return 0;
13813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
13913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
14013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic void drr_destroy_class(struct Qdisc *sch, struct drr_class *cl)
14113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
14213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	gen_kill_estimator(&cl->bstats, &cl->rate_est);
14313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	qdisc_destroy(cl->qdisc);
14413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	kfree(cl);
14513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
14613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
14713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic int drr_delete_class(struct Qdisc *sch, unsigned long arg)
14813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
14913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
15013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl = (struct drr_class *)arg;
15113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
15213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (cl->filter_cnt > 0)
15313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return -EBUSY;
15413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
15513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	sch_tree_lock(sch);
15613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
15713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	drr_purge_queue(cl);
15813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	qdisc_class_hash_remove(&q->clhash, &cl->common);
15913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
1607cd0a63872ac6ef97265f07adc367ca4f984468eJarek Poplawski	BUG_ON(--cl->refcnt == 0);
1617cd0a63872ac6ef97265f07adc367ca4f984468eJarek Poplawski	/*
1627cd0a63872ac6ef97265f07adc367ca4f984468eJarek Poplawski	 * This shouldn't happen: we "hold" one cops->get() when called
1637cd0a63872ac6ef97265f07adc367ca4f984468eJarek Poplawski	 * from tc_ctl_tclass; the destroy method is done from cops->put().
1647cd0a63872ac6ef97265f07adc367ca4f984468eJarek Poplawski	 */
16513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
16613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	sch_tree_unlock(sch);
16713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return 0;
16813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
16913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
17013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic unsigned long drr_get_class(struct Qdisc *sch, u32 classid)
17113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
17213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl = drr_find_class(sch, classid);
17313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
17413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (cl != NULL)
17513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		cl->refcnt++;
17613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
17713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return (unsigned long)cl;
17813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
17913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
18013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic void drr_put_class(struct Qdisc *sch, unsigned long arg)
18113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
18213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl = (struct drr_class *)arg;
18313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
18413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (--cl->refcnt == 0)
18513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		drr_destroy_class(sch, cl);
18613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
18713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
18825d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabendstatic struct tcf_proto __rcu **drr_tcf_chain(struct Qdisc *sch,
18925d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend					      unsigned long cl)
19013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
19113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
19213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
19313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (cl)
19413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return NULL;
19513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
19613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return &q->filter_list;
19713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
19813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
19913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic unsigned long drr_bind_tcf(struct Qdisc *sch, unsigned long parent,
20013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy				  u32 classid)
20113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
20213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl = drr_find_class(sch, classid);
20313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
20413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (cl != NULL)
20513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		cl->filter_cnt++;
20613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
20713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return (unsigned long)cl;
20813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
20913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
21013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic void drr_unbind_tcf(struct Qdisc *sch, unsigned long arg)
21113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
21213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl = (struct drr_class *)arg;
21313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
21413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	cl->filter_cnt--;
21513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
21613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
21713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic int drr_graft_class(struct Qdisc *sch, unsigned long arg,
21813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			   struct Qdisc *new, struct Qdisc **old)
21913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
22013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl = (struct drr_class *)arg;
22113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
22213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (new == NULL) {
2233511c9132f8b1e1b5634e41a3331c44b0c13be70Changli Gao		new = qdisc_create_dflt(sch->dev_queue,
22413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy					&pfifo_qdisc_ops, cl->common.classid);
22513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		if (new == NULL)
22613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			new = &noop_qdisc;
22713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
22813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
22913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	sch_tree_lock(sch);
23013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	drr_purge_queue(cl);
231b94c8afcba3ae6584653b98e315446ea83be6ea5Patrick McHardy	*old = cl->qdisc;
232b94c8afcba3ae6584653b98e315446ea83be6ea5Patrick McHardy	cl->qdisc = new;
23313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	sch_tree_unlock(sch);
23413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return 0;
23513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
23613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
23713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic struct Qdisc *drr_class_leaf(struct Qdisc *sch, unsigned long arg)
23813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
23913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl = (struct drr_class *)arg;
24013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
24113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return cl->qdisc;
24213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
24313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
24413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic void drr_qlen_notify(struct Qdisc *csh, unsigned long arg)
24513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
24613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl = (struct drr_class *)arg;
24713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
24813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (cl->qdisc->q.qlen == 0)
24913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		list_del(&cl->alist);
25013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
25113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
25213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic int drr_dump_class(struct Qdisc *sch, unsigned long arg,
25313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			  struct sk_buff *skb, struct tcmsg *tcm)
25413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
25513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl = (struct drr_class *)arg;
25613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct nlattr *nest;
25713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
25813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	tcm->tcm_parent	= TC_H_ROOT;
25913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	tcm->tcm_handle	= cl->common.classid;
26013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	tcm->tcm_info	= cl->qdisc->handle;
26113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
26213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	nest = nla_nest_start(skb, TCA_OPTIONS);
26313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (nest == NULL)
26413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		goto nla_put_failure;
2651b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put_u32(skb, TCA_DRR_QUANTUM, cl->quantum))
2661b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
26713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return nla_nest_end(skb, nest);
26813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
26913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardynla_put_failure:
27013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	nla_nest_cancel(skb, nest);
27113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return -EMSGSIZE;
27213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
27313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
27413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic int drr_dump_class_stats(struct Qdisc *sch, unsigned long arg,
27513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy				struct gnet_dump *d)
27613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
27713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl = (struct drr_class *)arg;
2786401585366326fc0ecbc372ec60d1a15cd8be2f5John Fastabend	__u32 qlen = cl->qdisc->q.qlen;
27913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct tc_drr_stats xstats;
28013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
28113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	memset(&xstats, 0, sizeof(xstats));
2826401585366326fc0ecbc372ec60d1a15cd8be2f5John Fastabend	if (qlen)
28313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		xstats.deficit = cl->deficit;
28413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
28522e0f8b9322cb1a48b1357e8f4ae6f5a9eca8cfaJohn Fastabend	if (gnet_stats_copy_basic(d, NULL, &cl->bstats) < 0 ||
286d250a5f90e53f5e150618186230795352d154c88Eric Dumazet	    gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 ||
287b0ab6f92752b9f9d8da980506e9df3bd9dcd7ed3John Fastabend	    gnet_stats_copy_queue(d, NULL, &cl->qdisc->qstats, qlen) < 0)
28813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return -1;
28913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
29013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
29113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
29213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
29313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic void drr_walk(struct Qdisc *sch, struct qdisc_walker *arg)
29413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
29513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
29613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl;
29713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	unsigned int i;
29813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
29913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (arg->stop)
30013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return;
30113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
30213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	for (i = 0; i < q->clhash.hashsize; i++) {
303b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin		hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) {
30413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			if (arg->count < arg->skip) {
30513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy				arg->count++;
30613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy				continue;
30713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			}
30813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
30913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy				arg->stop = 1;
31013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy				return;
31113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			}
31213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			arg->count++;
31313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		}
31413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
31513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
31613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
31713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic struct drr_class *drr_classify(struct sk_buff *skb, struct Qdisc *sch,
31813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy				      int *qerr)
31913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
32013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
32113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl;
32213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct tcf_result res;
32325d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend	struct tcf_proto *fl;
32413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	int result;
32513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
32613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (TC_H_MAJ(skb->priority ^ sch->handle) == 0) {
32713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		cl = drr_find_class(sch, skb->priority);
32813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		if (cl != NULL)
32913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			return cl;
33013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
33113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
33213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
33325d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend	fl = rcu_dereference_bh(q->filter_list);
33425d8c0d55f241ce2d360df1bea48e23a55836ee6John Fastabend	result = tc_classify(skb, fl, &res);
33513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (result >= 0) {
33613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy#ifdef CONFIG_NET_CLS_ACT
33713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		switch (result) {
33813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		case TC_ACT_QUEUED:
33913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		case TC_ACT_STOLEN:
34013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			*qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
34113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		case TC_ACT_SHOT:
34213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			return NULL;
34313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		}
34413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy#endif
34513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		cl = (struct drr_class *)res.class;
34613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		if (cl == NULL)
34713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			cl = drr_find_class(sch, res.classid);
34813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return cl;
34913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
35013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return NULL;
35113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
35213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
35313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch)
35413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
35513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
35613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl;
357f54ba7798848ce1385a71b36a2c997422c82220aDavid S. Miller	int err = 0;
35813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
35913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	cl = drr_classify(skb, sch, &err);
36013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (cl == NULL) {
36113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		if (err & __NET_XMIT_BYPASS)
36225331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend			qdisc_qstats_drop(sch);
36313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		kfree_skb(skb);
36413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return err;
36513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
36613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
36713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	err = qdisc_enqueue(skb, cl->qdisc);
36813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (unlikely(err != NET_XMIT_SUCCESS)) {
36913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		if (net_xmit_drop_count(err)) {
37013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			cl->qstats.drops++;
37125331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend			qdisc_qstats_drop(sch);
37213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		}
37313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return err;
37413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
37513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
37613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (cl->qdisc->q.qlen == 1) {
37713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		list_add_tail(&cl->alist, &q->active);
37813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		cl->deficit = cl->quantum;
37913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
38013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
38113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	sch->q.qlen++;
38213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return err;
38313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
38413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
38513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic struct sk_buff *drr_dequeue(struct Qdisc *sch)
38613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
38713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
38813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl;
38913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct sk_buff *skb;
39013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	unsigned int len;
39113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
3923f0947c3ffaed33c1c38b79e4b17f75ba072d3e9Patrick McHardy	if (list_empty(&q->active))
3933f0947c3ffaed33c1c38b79e4b17f75ba072d3e9Patrick McHardy		goto out;
3943f0947c3ffaed33c1c38b79e4b17f75ba072d3e9Patrick McHardy	while (1) {
39513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		cl = list_first_entry(&q->active, struct drr_class, alist);
39613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		skb = cl->qdisc->ops->peek(cl->qdisc);
3976e765a009ad33845033f94cf47159327f2ba59dbFlorian Westphal		if (skb == NULL) {
3986e765a009ad33845033f94cf47159327f2ba59dbFlorian Westphal			qdisc_warn_nonwc(__func__, cl->qdisc);
3993f0947c3ffaed33c1c38b79e4b17f75ba072d3e9Patrick McHardy			goto out;
4006e765a009ad33845033f94cf47159327f2ba59dbFlorian Westphal		}
40113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
40213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		len = qdisc_pkt_len(skb);
40313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		if (len <= cl->deficit) {
40413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			cl->deficit -= len;
40513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			skb = qdisc_dequeue_peeked(cl->qdisc);
40613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			if (cl->qdisc->q.qlen == 0)
40713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy				list_del(&cl->alist);
4082dd875ff31ac7ff42d6fc7d7f78ac6c0635439f5Eric Dumazet
4092dd875ff31ac7ff42d6fc7d7f78ac6c0635439f5Eric Dumazet			bstats_update(&cl->bstats, skb);
4109190b3b3208d052d98cb601fcc192f3f71a5658bEric Dumazet			qdisc_bstats_update(sch, skb);
41113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			sch->q.qlen--;
41213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			return skb;
41313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		}
41413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
41513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		cl->deficit += cl->quantum;
41613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		list_move_tail(&cl->alist, &q->active);
41713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
4183f0947c3ffaed33c1c38b79e4b17f75ba072d3e9Patrick McHardyout:
41913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return NULL;
42013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
42113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
42213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic unsigned int drr_drop(struct Qdisc *sch)
42313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
42413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
42513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl;
42613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	unsigned int len;
42713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
42813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	list_for_each_entry(cl, &q->active, alist) {
42913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		if (cl->qdisc->ops->drop) {
43013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			len = cl->qdisc->ops->drop(cl->qdisc);
43113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			if (len > 0) {
43298aa9c80f1fee01e98dfdc484ab7316af45f8f17Jarek Poplawski				sch->q.qlen--;
43313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy				if (cl->qdisc->q.qlen == 0)
43413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy					list_del(&cl->alist);
43513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy				return len;
43613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			}
43713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		}
43813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
43913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return 0;
44013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
44113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
44213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic int drr_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
44313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
44413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
44513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	int err;
44613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
44713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	err = qdisc_class_hash_init(&q->clhash);
44813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	if (err < 0)
44913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		return err;
45013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	INIT_LIST_HEAD(&q->active);
45113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return 0;
45213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
45313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
45413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic void drr_reset_qdisc(struct Qdisc *sch)
45513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
45613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
45713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl;
45813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	unsigned int i;
45913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
46013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	for (i = 0; i < q->clhash.hashsize; i++) {
461b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin		hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) {
46213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			if (cl->qdisc->q.qlen)
46313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy				list_del(&cl->alist);
46413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			qdisc_reset(cl->qdisc);
46513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy		}
46613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
46713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	sch->q.qlen = 0;
46813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
46913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
47013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic void drr_destroy_qdisc(struct Qdisc *sch)
47113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
47213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_sched *q = qdisc_priv(sch);
47313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	struct drr_class *cl;
474b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin	struct hlist_node *next;
47513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	unsigned int i;
47613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
47713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	tcf_destroy_chain(&q->filter_list);
47813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
47913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	for (i = 0; i < q->clhash.hashsize; i++) {
480b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin		hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
48113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy					  common.hnode)
48213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy			drr_destroy_class(sch, cl);
48313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	}
48413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	qdisc_class_hash_destroy(&q->clhash);
48513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
48613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
48713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic const struct Qdisc_class_ops drr_class_ops = {
48813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.change		= drr_change_class,
48913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.delete		= drr_delete_class,
49013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.get		= drr_get_class,
49113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.put		= drr_put_class,
49213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.tcf_chain	= drr_tcf_chain,
49313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.bind_tcf	= drr_bind_tcf,
49413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.unbind_tcf	= drr_unbind_tcf,
49513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.graft		= drr_graft_class,
49613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.leaf		= drr_class_leaf,
49713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.qlen_notify	= drr_qlen_notify,
49813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.dump		= drr_dump_class,
49913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.dump_stats	= drr_dump_class_stats,
50013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.walk		= drr_walk,
50113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy};
50213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
50313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic struct Qdisc_ops drr_qdisc_ops __read_mostly = {
50413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.cl_ops		= &drr_class_ops,
50513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.id		= "drr",
50613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.priv_size	= sizeof(struct drr_sched),
50713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.enqueue	= drr_enqueue,
50813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.dequeue	= drr_dequeue,
50913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.peek		= qdisc_peek_dequeued,
51013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.drop		= drr_drop,
51113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.init		= drr_init_qdisc,
51213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.reset		= drr_reset_qdisc,
51313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.destroy	= drr_destroy_qdisc,
51413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	.owner		= THIS_MODULE,
51513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy};
51613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
51713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic int __init drr_init(void)
51813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
51913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	return register_qdisc(&drr_qdisc_ops);
52013d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
52113d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
52213d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardystatic void __exit drr_exit(void)
52313d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy{
52413d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy	unregister_qdisc(&drr_qdisc_ops);
52513d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy}
52613d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardy
52713d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardymodule_init(drr_init);
52813d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardymodule_exit(drr_exit);
52913d2a1d2b032de08d7dcab6a1edcd47802681f96Patrick McHardyMODULE_LICENSE("GPL");
530