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