linux/net/sched/sch_htb.c
<<
>>
Prefs

	comment">/*

	comment"> * net/sched/sch_htb.c  Hierarchical token bucket, feed tree version

	comment"> *

	comment"> *              This program is free software; you caluredistribute it and/or

	comment"> *              modify it under the terms of the GNU General Public License

	comment"> *              as published by the Free Software Foundation; either version

	comment"> *              2 of the License, or (at your option) any later version.

	comment"> *

	comment"> * Authors:     Martin Devera, <devik@cdi.cz>

	comment"> *

	comment"> * Credits (in time order) for older HTB versions:

	comment"> *              Stef Coene <stef.coene@docum.org>

	comment"> *                      HTB support at LARTC mailing list

	comment"> *              Ondrej Kraus, <krauso@barr.cz>

	comment"> *                      found missing INIT_QDISC(htb)

	comment"> *              Vladimir Smelhaus, Aamer Akhter, Bert Hubert

	comment"> *                      helped a lot to locate nastyue=""> stall bug

	comment"> *              Andi Kleen, Jamal Hadi, Bert Hubert

	comment"> *                      codeureview and helpful comments on shaping

	comment"> *              Tomasz Wrona, <tw@eter.tym.pl>

	comment"> *                      created test case so that I was able to fix nastyubug

	comment"> *              Wilfried Weissmann

	comment"> *                      spotted bug in dequeue codeuand helped with fix

	comment"> *              Jiri Fojtasek

	comment"> *                      fixed requeue routine

	comment"> *              and many others. thanks.

	comment"> */
linux/module.host">
linux/moduleparam.host">
linux/types.host">
linux/kernel.host">
linux/string.host">
linux/errno.host">
linux/skbuff.host">
linux/list.host">
linux/compiler.host">
linux/rbtree.host">
linux/workqueue.host">
linux/slab.host">
net/netlink.host">
net/pkt_sched.host">

	comment">/* HTB algorithm.

	comment">    Author: devik@cdi.cz

	comment">    ========================================================================

	comment">    HTB is like TBF with multiple classes. It is also similar to CBQ because

	comment">    it allows to "">ign priority to eachue=""> in hierarchy.

	comment">    In fact it is another implementation of Floyd's formal sharing.

	comment">    Levels:

	comment">    Eachue=""> is "">igned level. Leaf has ALWAYS level 0 and root

	comment">    classes have level TC_HTB_MAXDEPTH-1. Interior nodes has level

	comment">    one le"> than their parent.

	comment">*/
htb_hysteresisost" __read_mostlyost" = 0; " value="">
	comment">/* whether to use mode hysteresis for speedup */
HTB_VERost" 0x30011         " value="">
	comment">/* major must be matched with number suplied by TC as version */
HTB_VERost" >> 16 != TC_HTB_PROTOVERost"

	string">"Mismatched sch_htb.c and pkt_sch.h"

	comment">/* Module parameter and sysfs export */
module_paramost"    (htb_hysteresisost", int, 0640);
MODULE_PARM_DESCost"(htb_hysteresisost", " value="">
	string">"Hysteresis mode, le"> CPU load, le"> accurate");

	comment">/* used internaly to keep status of single class */
htb_cmodeost" {
HTB_CANT_SENDost",          " value="">
	comment">/* class can't send and can't borrow */
HTB_MAY_BORROWost",         " value="">
	comment">/* class can't send but may borrow */
HTB_CAN_SENDost"            " value="">
	comment">/* class can send */

	comment">/* interior & leaf nodes; props specific to leave> are marked L: */
htb_classost" {
Qdisc_class_commonost" commonost";

	comment">/* general class parameters */
gnet_stats_basic_packedost" bstatsost";
gnet_stats_queueost" qstatsost";
gnet_stats_rate_estost" rate_estost";
tc_htb_xstatsost" xstatsost";    " value="">
	comment">/* our special stats */
refcntost";             " value="">
	comment">/* usage count of this class */

	comment">/* topology */
level
	comment">/* our level (see above) */
igned int childrenost";
htb_classost" *parent
	comment">/* parent class */
prio
	comment">/* these two are used only by leave>... */
quantum
	comment">/* but stored for parent-to-leaf return */
htb_class_leafost" {
Qdiscost" *qost";
deficitost"[TC_HTB_MAXDEPTHost"];
list_headost" drop_listost";
leafost";
htb_class_innerost" {
rb_rootost" feedost"[TC_HTB_NUMPRIOost"];    " value="">
	comment">/* feed trees */
rb_nodeost" *ptrost"[TC_HTB_NUMPRIOost"];    " value="">
	comment">/* current class ptr */

	comment">/* When class changes from state 1->2 and disconnects from

	comment">                         * parent's feed then we lost ptr value and start from the

	comment">                         * first child again. Here we storeue="">id of the

	comment">                         * =""t valid ptr (used when ptr is NULL).

	comment">                         */
u32ost" l""t_ptr_idost"[TC_HTB_NUMPRIOost"];
innerost";
unost";
rb_nodeost" nodeost"[TC_HTB_NUMPRIOost"];    " value="">
	comment">/* node for self or feed tree */
rb_nodeost" pq_node
	comment">/* node for event queue */
psched_time_tost" pq_keyost";
prio_activity
	comment">/* for which prio> are we active */
htb_cmodeost" cmodeost";   " value="">
	comment">/* current mode of the class */

	comment">/* class attached filters */
tcf_protoost" *filter_listost";
filter_cntost";

	comment">/* token bucket parameters */
qdisc_rate_tableost" *rateost";  " value="">
	comment">/* rate table of the class itself */
qdisc_rate_tableost" *ceilost";  " value="">
	comment">/* ceiling rate (limits borrows too) */
bufferost", "a href="+code=cbuffer" class="sref">cbufferost";   " value="">
	comment">/* token bucket depth/rate */
psched_tdiff_tost" mbufferost"; " value="">
	comment">/* max wait time */
tokensost", "a href="+code=ctokens" class="sref">ctokensost";   " value="">
	comment">/* current number of tokens */
psched_time_tost" t_c
	comment">/* checkpoint time */
htb_schedost" {
Qdisc_class_hashost" clhashost";
list_headost" dropsost"[TC_HTB_NUMPRIOost"];" value="">
	comment">/* active leave> (for drops) */

	comment">/* self list - roots of self generating tree */
rb_rootost" rowost"[TC_HTB_MAXDEPTHost"][TC_HTB_NUMPRIOost"];
row_maskost"[TC_HTB_MAXDEPTHost"];
rb_nodeost" *ptrost"[TC_HTB_MAXDEPTHost"][TC_HTB_NUMPRIOost"];
u32ost" l""t_ptr_idost"[TC_HTB_MAXDEPTHost"][TC_HTB_NUMPRIOost"];

	comment">/* self wait list - roots of wait PQs per row */
rb_rootost" wait_pqost"[TC_HTB_MAXDEPTHost"];

	comment">/* time of nearest event per level (row) */
psched_time_tost" near_ev_cacheost"[TC_HTB_MAXDEPTHost"];
defcls
	comment">/* class where une="">ified flows go to */

	comment">/* filters for qdisc itself */
tcf_protoost" *filter_listost";
rate2quantum
	comment">/* quant = rate / rate2quantum */
psched_time_tost" nowost";      " value="">
	comment">/* cached dequeue time */
qdisc_watchdogost" watchdogost";

	comment">/* non shaped skbs; let them go directly thru */
sk_buff_headost" direct_queueost";
direct_qlen
	comment">/* max qlen of above */
direct_pktsost";
HTB_WARN_TOOMANYEVENTSost"  0x1
igned int warned
	comment">/* only one warning */
work_structost" workost";

	comment">/* find class in global hash table using given handle */
inlineost" struct htb_classost" *htb_findost"(u32ost" handleost", struct Qdiscost" *schost")
htb_schedost" *qost" = qdisc_privost"(schost");
Qdisc_class_commonost" *clcost";
clcost" = qdisc_class_findost"(&qost"->clhashost", "a href="+code=handle" class="sref">handleost");
clcost" == NULLost")
NULLost";
container_ofost"(clcost", struct htb_classost", "a href="+code=common" class="sref">commonost");

	comment">/**

	comment"> * htb_classify - classify a packet into classosspan>

	comment"> *

	comment"> * It returns NULL if the packet should be dropped or -1 if the packet

	comment"> * should be p"">ed directly thru. In all other cases leaf class is returned.

	comment"> * We allow direct class selection byue="">id in priority. The we examine

	comment"> * filters in qdisc and in inner nodes (if higher filter points to the innerosspan>

	comment"> * node). If we end up with e="">id MAJOR:0 we enqueue the skb into specialosspan>

	comment"> * internal fifo (direct). These packets then go directly thru. If we stillosspan>

	comment"> * have no valid leaf we try to use MAJOR:default leaf. It still un>uccessfulosspan>

	comment"> * then finish and return direct queue.osspan>

	comment"> */
HTB_DIRECTost" ((struct htb_classost" *)-1L)
htb_classost" *htb_classifyost"(struct sk_buffost" *skbost", struct Qdiscost" *schost",
qerrost")
htb_schedost" *qost" = qdisc_privost"(schost");
htb_classost" *clost";
tcf_resultost" resost";
tcf_protoost" *tcfost";
resultost";

	comment">/* allow to select class byusetting skb->priority to valid e="">id;

	comment">         * note that nfmark can be used too byuattaching filter fw with no

	comment">         * rules in it

	comment">         */
skbost"->priorityost" == schost"->handleost")
HTB_DIRECTost";      " value="">
	comment">/* X:0 (direct flow) selected */
clost" = htb_findost"(skbost"->priorityost", "a href="+code=sch" class="sref">schost");
clost" && clost"->levelclost";
qerrost" = NET_XMIT_SUCCESSost" | __NET_XMIT_BYPASSost";
tcfost" = qost"->filter_listost";
tcfost" && (resultost" = tc_classifyost"(skbost", "a href="+code=tcf" class="sref">tcfost", &resost")) >= 0) {
CONFIG_NET_CLS_ACTost"
resultost") {
TC_ACT_QUEUEDost":
TC_ACT_STOLENost":
qerrost" = NET_XMIT_SUCCESSost" | __NET_XMIT_STOLENost";
TC_ACT_SHOTost":
NULLost";
clost" = (void *)resost"."a href="+code=class" class="sref">classost";
clost") {
resost"."a href="+code=classid" class="sref">classidost" == schost"->handleost")
HTB_DIRECTost";      " value="">
	comment">/* X:0 (direct flow) */
clost" = htb_findost"(resost"."a href="+code=classid" class="sref">classidost", "a href="+code=sch" class="sref">schost");
clost")

	comment">/* filter selected invalid e="">id */
clost"->levelclost";      " value="">
	comment">/* we hit leaf; return it */

	comment">/* we have got inner e="">; apply inner filter chain */
tcfost" = clost"->filter_listost";

	comment">/* classification failed; try to use default class */
clost" = htb_findost"(TC_H_MAKEost"(TC_H_MAJost"(schost"->handleost"), "a href="+code=q" class="sref">qost"->defclsschost");
clost" || clost"->levelHTB_DIRECTost";      " value="">
	comment">/* bad default .. this is safe bet */
clost";

	comment">/**

	comment"> * htb_add_to_id_tree - adds class to the round robin listosspan>

	comment"> *osspan>

	comment"> * Routine adds class to the list (actually tree) sorted byue="">id.osspan>

	comment"> * Make sure that class is not already on such list for given prio.osspan>

	comment"> */
htb_add_to_id_treeost"(struct rb_rootost" *rootost",
htb_classost" *clost", int priorb_nodeost" **post" = &rootost"->rb_nodeost", *parentNULLost";
post") {
htb_classost" *cost";
parentpost";
cost" = rb_entryost"(parenthtb_classost", "a href="+code=node" class="sref">nodeost"[prioclost"->commonost"."a href="+code=classid" class="sref">classidost" > cost"->commonost"."a href="+code=classid" class="sref">classidost")
post" = &parentrb_rightost";
post" = &parentrb_leftost";
rb_link_nodeost"(&clost"->nodeost"[prioparentpost");
rb_insert_colorost"(&clost"->nodeost"[priorootost");

	comment">/**

	comment"> * htb_add_to_wait_tree - adds class to the event queue with delay

	comment"> *

	comment"> * The class is added to priority event queue to indicate that class willosspan>

	comment"> * change its mode ilue=->pq_key microseconds. Make sure that class is notosspan>

	comment"> * already iluthe queue.osspan>

	comment"> */
htb_add_to_wait_treeost"(struct htb_schedost" *qost",
htb_classost" *clost", long delayrb_nodeost" **post" = &qost"->wait_pqost"[clost"->levelrb_nodeost", *parentNULLost";
clost"->pq_keyost" = qost"->nowost" + delayclost"->pq_keyost" == qost"->nowost")
clost"->pq_keyost"++;

	comment">/* update the nearest event cache */
qost"->near_ev_cacheost"[clost"->levelclost"->pq_keyost")
qost"->near_ev_cacheost"[clost"->levelclost"->pq_keyost";
post") {
htb_classost" *cost";
parentpost";
cost" = rb_entryost"(parenthtb_classost", "a href="+code=pq_node" class="sref">pq_nodeost");
clost"->pq_keyost" >= cost"->pq_keyost")
post" = &parentrb_rightost";
post" = &parentrb_leftost";
rb_link_nodeost"(&clost"->pq_nodeost", "a href="+code=parent" class="sref">parentpost");
rb_insert_colorost"(&clost"->pq_nodeost", &qost"->wait_pqost"[clost"->level
	comment">/**

	comment"> * htb_next_rb_node - finds next node ilubinary tree

	comment"> *

	comment"> * When we are p""t l""t key we return NULL.osspan>

	comment"> * Average complexity is 2 steps per call.osspan>

	comment"> */
inlineost" void htb_next_rb_nodeost"(struct rb_nodeost" **nost")
nost" = rb_nextost"(*nost");

	comment">/**

	comment"> * htb_add_e="">_to_row - addue=""> to its row

	comment"> *

	comment"> * The class is added to row at priorities marked in mask.osspan>

	comment"> * It does nothing if mask == 0.osspan>

	comment"> */
inlineost" void _to_row" class="sref">htb_add_e="">_to_rowost"(struct htb_schedost" *qost",
htb_classost" *clost", int maskost")
qost"->row_maskost"[clost"->levelmaskost";
maskost") {
prioffzost"(~maskost");
maskost" &= ~(1 << priohtb_add_to_id_treeost"("a href="+code=q" class="sref">qost"->rowost"[clost"->levelprioclost", prio
	comment">/* If this triggers, it is a bug iluthis code, but it need not be fatal */
htb_safe_rb_eraseost"(struct rb_nodeost" *rbrb_rootost" *rootost")
RB_EMPTY_NODEost"("a href="+code=rb" class="sref">rbWARN_ONost"(1);
rb_eraseost"(rbrootost");
RB_CLEAR_NODEost"("a href="+code=rb" class="sref">rb
	comment">/**

	comment"> * htb_remove_class_from_row - removes class from its row

	comment"> *

	comment"> * The class is removed from row at priorities marked in mask.osspan>

	comment"> * It does nothing if mask == 0.osspan>

	comment"> */
inlineost" void htb_remove_class_from_rowost"(struct htb_schedost" *qost",
htb_classost" *clost", int maskost")
mmaskost") {
prioffzost"(~maskost");
maskost" &= ~(1 << prioqost"->ptrost"[clost"->levelprioclost"->nodeost" + priohtb_next_rb_nodeost"(qost"->ptrost"[clost"->levelpriohtb_safe_rb_eraseost"(clost"->nodeost" + prioqost"->rowost"[clost"->levelprioqost"->rowost"[clost"->levelpriorb_nodeost")
mprioqost"->row_maskost"[clost"->levelm
	comment">/**

	comment"> * htb_activate_prios - creates active classe's feed chain

	comment"> *

	comment"> * The class is connected to ancestors and/or appropriate rows

	comment"> * for priorities it is participating on. e=->cmode must be new

	comment"> * (activated) mode. It does nothing if e=->prio_activity == 0.osspan>

	comment"> */
htb_activate_priosost"(struct htb_schedost" *qost", struct htb_classost" *clost")
htb_classost" *post" = clost"->parentmmaskost" = clost"->prio_activityclost"->cmodeost" == HTB_MAY_BORROWost" && post" && maskost") {
mmaskost";
mprioffzost"(~mmpriopost"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=feed" class="sref">feedost"[priorb_nodeost")

	comment">/* parent already has its feed in use so that

	comment">                                 * reset bit in mask as parent is already ok

	comment">                                 */
maskost" &= ~(1 << priohtb_add_to_id_treeost"("a href="+code=p" class="sref">post"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=feed" class="sref">feedost" + prioclost", priopost"->prio_activitymaskost";
clost" = post";
post" = clost"->parentclost"->cmodeost" == HTB_CAN_SENDost" && maskost")
htb_add_e="">_to_rowost"(qost", "a href="+code=cl" class="sref">clost", maskost");

	comment">/**

	comment"> * htb_deactivate_prios - remove class from feed chain

	comment"> *

	comment"> * e=->cmode must represent old mode (before deactivation). It does

	comment"> * nothing if e=->prio_activity == 0. Class is removed from all feedosspan>

	comment"> * chains and rows.osspan>

	comment"> */
htb_deactivate_priosost"(struct htb_schedost" *qost", struct htb_classost" *clost")
htb_classost" *post" = clost"->parentmmaskost" = clost"->prio_activityclost"->cmodeost" == HTB_MAY_BORROWost" && post" && maskmmaskost";
maskost" = 0;
mprioffzost"(~mmpriopost"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=ptr" class="sref">ptrost"[prioclost"->nodeost" + prio
	comment">/* we are removing child which is pointed to from

	comment">                                 * parent feed - forget the pointer but rememberosspan>

	comment">                                 * e="">idosspan>

	comment">                                 */
post"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=last_ptr_id" class="sref">last_ptr_idost"[prioclost"->commonost"."a href="+code=classid" class="sref">classidost";
post"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=ptr" class="sref">ptrost"[prioNULLost";
htb_safe_rb_eraseost"(clost"->nodeost" + priopost"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=feed" class="sref">feedost" + priopost"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=feed" class="sref">feedost"[priorb_nodeost")
maskost" |= 1 << priopost"->prio_activitymaskost";
clost" = post";
post" = clost"->parentclost"->cmodeost" == HTB_CAN_SENDost" && maskost")
htb_remove_class_from_rowost"(qost", "a href="+code=cl" class="sref">clost", maskost");
inlineost" long htb_lowaterost"(const struct htb_classost" *clost")
htb_hysteresisost")
clost"->cmodeost" != HTB_CANT_SENDost" ? -clost"->cbufferost" : 0;
inlineost" long htb_hiwaterost"(const struct htb_classost" *clost")
htb_hysteresisost")
clost"->cmodeost" == HTB_CAN_SENDost" ? -clost"->bufferost" : 0;

	comment">/**

	comment"> * htb_class_mode - computes and returns current class modeosspan>

	comment"> *osspan>

	comment"> * It computes cl's mode at time cl->t_c+diff and returns it. If modeosspan>

	comment"> * is not HTB_CAN_SEND then cl->pq_key is updated to time differenceosspan>

	comment"> * from now to time when cl will change its state.osspan>

	comment"> * Also it is worth to note that class mode doesn't change simplyosspan>

	comment"> * at cl->{c,}tokens == 0 but there calurather be hysteresis ofosspan>

	comment"> * 0 .. -cl->{c,}bufferurange. It is meant to limit number ofosspan>

	comment"> * mode transitions per time unit. The speed gain is about 1/6.osspan>

	comment"> */
inlineost" enum htb_cmodeost"
htb_class_modeost"(struct htb_classost" *clost", long *diffost")
tokstoksclost"->ctokensost" + *diffost")) < htb_lowaterost"(clost")) {
diffost" = -toksHTB_CANT_SENDost";
toksclost"->tokensost" + *diffost")) >= htb_hiwaterost"(clost"))
HTB_CAN_SENDost";
diffost" = -toksHTB_MAY_BORROWost";

	comment">/**

	comment"> * htb_change_class_mode - changes classe's mode

	comment"> *

	comment"> * This should be the only way how to change classe's mode under normal

	comment"> * cirsumstances. Routine will update feed lists linkage, change mode

	comment"> * and addue=""> to the wait event queue if appropriate. New mode should

	comment"> * be different from old one and cl->pq_key has to be valid if ehanging

	comment"> * to mode other than HTB_CAN_SEND (see htb_add_to_wait_tree).osspan>

	comment"> */
htb_change_class_modeost"(struct htb_schedost" *qost", struct htb_classost" *clost", long *diffost")
htb_cmodeost" new_modeost" = htb_class_modeost"("a href="+code=cl" class="sref">clost", diffost");
new_modeost" == clost"->cmodeost")
clost"->prio_activity
	comment">/* not necessary: speed optimization */
clost"->cmodeost" != HTB_CANT_SENDost")
htb_deactivate_priosost"(qost", clost");
clost"->cmodeost" = new_modeost";
new_modeost" != HTB_CANT_SENDost")
htb_activate_priosost"(qost", clost");
clost"->cmodeost" = new_modeost";

	comment">/**

	comment"> * htb_activate - inserts leaf e= into appropriate active feeds

	comment"> *

	comment"> * Routine learns (new) priority of leaf and activates feed chain

	comment"> * for the prio. It calube called on already active leaf safely.osspan>

	comment"> * It also adds leaf into droplist.osspan>

	comment"> */
inlineost" void htb_activateost"(struct htb_schedost" *qost", struct htb_classost" *clost")
WARN_ONost"("a href="+code=cl" class="sref">clost"->levelclost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost" || !"a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost"->qost"."a href="+code=qlen" class="sref">qlenost");
clost"->prio_activityclost"->prio_activityclost"->prioost";
htb_activate_priosost"(qost", clost");
list_add_tailost"(&"a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=drop_list" class="sref">drop_listost",
qost"->dropsost" + clost"->prioost");

	comment">/**

	comment"> * htb_deactivate - remove leaf e= from active feeds

	comment"> *

	comment"> * Make sure that leaf is active. In the other words it cal't be called

	comment"> * with non-active leaf. It also removes class from the drop list.osspan>

	comment"> */
inlineost" void htb_deactivateost"(struct htb_schedost" *qost", struct htb_classost" *clost")
WARN_ONost"(!"a href="+code=cl" class="sref">clost"->prio_activityhtb_deactivate_priosost"(qost", clost");
clost"->prio_activitylist_del_initost"(&"a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=drop_list" class="sref">drop_listost");
htb_enqueueost"(struct sk_buffost" *skbost", struct Qdiscost" *schost")
uninitialized_varost"(retost");
htb_schedost" *qost" = qdisc_privost"(schost");
htb_classost" *clost" = htb_classifyost"(skbost", schost", &"a href="+code=ret" class="sref">retost");
clost" == HTB_DIRECT
	comment">/* enqueue to helper queue */
qost"->direct_queueost"."a href="+code=qlen" class="sref">qlenost" < qost"->direct_qlen__skb_queue_tailost"(&"a href="+code=q" class="sref">qost"->direct_queueost", skbost");
qost"->direct_pktsost"++;
qdisc_dropost"(skbost", schost");
CONFIG_NET_CLS_ACTost"
clost") {
retost" & __NET_XMIT_BYPASSost")
schost"->qstatsost"."a href="+code=drops" class="sref">dropsost"++;
kfree_skbost"(skbost");
retost";
retost" = qdisc_enqueueost"(skbost", clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost")) != NET_XMIT_SUCCESSost") {
net_xmit_drop_countost"(retost")) {
schost"->qstatsost"."a href="+code=drops" class="sref">dropsost"++;
clost"->qstatsost"."a href="+code=drops" class="sref">dropsost"++;
retost";
htb_activateost"(qost", clost");
schost"->qost"."a href="+code=qlen" class="sref">qlenost"++;
NET_XMIT_SUCCESSost";
inlineost" void htb_accnt_tokensost"(struct htb_classost" *clost", int bytesost", long diffost")
toksdiffost" + clost"->tokensost";
toksclost"->bufferost")
toksclost"->bufferost";
toksqdisc_l2tost"(clost"->rateost", bytesost");
toksclost"->mbufferost")
toksclost"->mbufferost";
clost"->tokensost" = toksinlineost" void htb_accnt_ctokensost"(struct htb_classost" *clost", int bytesost", long diffost")
toksdiffost" + clost"->ctokensost";
toksclost"->cbufferost")
toksclost"->cbufferost";
toksqdisc_l2tost"(clost"->ceilost", bytesost");
toksclost"->mbufferost")
toksclost"->mbufferost";
clost"->ctokensost" = toks
	comment">/**

	comment"> * htb_charge_class - charges amount "bytes" to leaf and ancestors

	comment"> *osspan>

	comment"> * Routine "">umes that packet "bytes" long was dequeued from leaf e=osspan>

	comment"> * borrowing from "level". It accounts bytes to ceil leaky bucket forosspan>

	comment"> * leaf and all ancestors and to rate bucket for ancestors at levels

	comment"> * "level" and higher. It also handles possible change of mode resulting

	comment"> * from the update. Note that mode calualso increase here (MAY_BORROW to

	comment"> * CAN_SEND) because we caluuse more precise clock that event queue here.osspan>

	comment"> * In such case we remove class from event queue first.osspan>

	comment"> */
htb_charge_classost"(struct htb_schedost" *qost", struct htb_classost" *clost",
levelsk_buffost" *skbost")
bytesost" = qdisc_pkt_lenost"(skbost");
htb_cmodeost" old_modediffost";
clost") {
diffost" = "a href="+code=psched_tdiff_bounded" class="sref">psched_tdiff_boundedost"(qost"->nowost", clost"->t_cost", clost"->mbufferost");
clost"->levellevelclost"->levellevelclost"->xstatsost"."a href="+code=lends" class="sref">lendsost"++;
htb_accnt_tokensost"(clost", bytesost", diffost");
clost"->xstatsost"."a href="+code=borrows" class="sref">borrowsost"++;
clost"->tokensost" += diffost";     < value="">
	comment">/* we moved t_c; update tokens */
htb_accnt_ctokensost"(clost", bytesost", diffost");
clost"->t_cost" = qost"->nowost";
old_modeclost"->cmodeost";
diffost" = 0;
htb_change_class_modeost"(qost", clost", &"a href="+code=diff" class="sref">diffost");
old_modeclost"->cmodeost") {
old_modeHTB_CAN_SENDost")
htb_safe_rb_eraseost"(&"a href="+code=cl" class="sref">clost"->pq_nodeost", qost"->wait_pqost" + clost"->levelclost"->cmodeost" != HTB_CAN_SENDost")
htb_add_to_wait_treeost"(qost", clost", "a href="+code=diff" class="sref">diffost");

	comment">/* update basic stats except for leaves which are already updated */
clost"->levelbstats_updateost"(&"a href="+code=cl" class="sref">clost"->bstatsost", skbost");
clost" = clost"->parentost";

	comment">/**

	comment"> * htb_do_events - make mode changes to c="">es at the level

	comment"> *

	comment"> * Scans event queue for pending events and applies them. Returns time of

	comment"> * next pending event (0 for no event in pq, q->now for too many events).osspan>

	comment"> * Note: Applied are events whose have cl->pq_key <= q->now.osspan>

	comment"> */
psched_time_tost" htb_do_eventsost"(struct htb_schedost" *qost", int levelstart
	comment">/* dol't run for longer thalu2 jiffies;u2 isuused instead of

	comment">         * 1 to simplify things when jiffy isugoing to be incremented

	comment">         * too soon

	comment">         */
stop_atost" = starttime_beforeost"(jiffiesost", stop_atost")) {
htb_classost" *clost";
diffost";
rb_nodeost" *post" = rb_firstost"(&"a href="+code=q" class="sref">qost"->wait_pqost"[levelpost")
clost" = rb_entryost"(post", struct htb_classost", pq_nodeost");
clost"->pq_keyost" > qost"->nowost")
clost"->pq_keyost";
htb_safe_rb_eraseost"(post", qost"->wait_pqost" + leveldiffost" = "a href="+code=psched_tdiff_bounded" class="sref">psched_tdiff_boundedost"(qost"->nowost", clost"->t_cost", clost"->mbufferost");
htb_change_class_modeost"(qost", clost", &"a href="+code=diff" class="sref">diffost");
clost"->cmodeost" != HTB_CAN_SENDost")
htb_add_to_wait_treeost"(qost", clost", "a href="+code=diff" class="sref">diffost");

	comment">/* too much load - let's continue after a break for scheduling */
qost"->warnedost" & HTB_WARN_TOOMANYEVENTSost")) {
pr_warningost"(< value="">
	string">"htb: too many events!\n");
qost"->warnedost" |= HTB_WARN_TOOMANYEVENTSost";
qost"->nowost";

	comment">/* Returns e="">->node+prio from id-tree where classe's id isu>= id. NULL

	comment"> * isuno such one exists.osspan>

	comment"> */
rb_nodeost" *htb_id_find_next_upperost"(int prioost", struct rb_nodeost" *nu32ost" idost")
rb_nodeost" *rost" = "a href="+code=NULL" class="sref">NULLnhtb_classost" *clost" =
rb_entryost"(nhtb_classost", nodeost"[prioost"]);
idost" > clost"->commonost"."a href="+code=classid" class="sref">classidnnrb_rightidost" < clost"->commonost"."a href="+code=classid" class="sref">classidrost" = "a href="+code=n" class="sref">nnnrb_leftnrost";

	comment">/**

	comment"> * htb_lookup_leaf - returns next leaf e=""> in DRR orderosspan>

	comment"> *osspan>

	comment"> * Find leaf where current feed pointers points to.osspan>

	comment"> */
htb_classost" *htb_lookup_leafost"(struct rb_rootost" *treeost", int prioost",
rb_nodeost" **pptrost", u32ost" * pidost")
iost";
rb_nodeost" *rootost";
rb_nodeost" **pptrost";
u32ost" *pidost";
stkost"[TC_HTB_MAXDEPTHost"], *spost" = stkost";
BUG_ONost"(!"a href="+code=tree" class="sref">treeost"->rb_nodeost");
spost"->rootost" = treeost"->rb_nodeost";
spost"->pptrost" = "a href="+code=pptr" class="sref">pptrost";
spost"->pidost" = "a href="+code=pid" class="sref">pidost";
iost" = 0; iost" < 65535; iost"++) {
spost"->pptrost" && *spost"->pidost") {

	comment">/* ptr was invalidated but id isuvalid - try to recoverosspan>

	comment">                         * the original or next ptrosspan>

	comment">                         */
spost"->pptrost" =
htb_id_find_next_upperost"(prioost", spost"->rootost", *spost"->pidost");
spost"->pidost" = 0;   " value="">
	comment">/* ptr isuvalid now so that remove thisuhint as it

	comment">                                 * calubecome out of date quickly

	comment">                                 */
spost"->pptrost") {       " value="">
	comment">/* we are at right end; rewind & go up */
spost"->pptrost" = spost"->rootost";
spost"->pptrost")->rb_leftspost"->pptrost" = (*spost"->pptrost")->rb_leftspost" > stkost") {
spost"--;
spost"->pptrost") {
WARN_ONost"(1);
NULLhtb_next_rb_nodeost"(spost"->pptrost");
htb_classost" *clost";
clost" = rb_entryost"(*spost"->pptrost", struct htb_classost", nodeost"[prioost"]);
clost"->levelclost";
spost")->rootost" = clost"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=feed" class="sref">feedost"[prioost"]."a href="+code=rb_node" class="sref">rb_nodeost";
spost"->pptrost" = clost"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=ptr" class="sref">ptrost" + prioost";
spost"->pidost" = "a href="+code=cl" class="sref">clost"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=last_ptr_id" class="sref">last_ptr_idost" + prioost";
WARN_ONost"(1);
NULL
	comment">/* dequeues packet at given priority and level; call only if

	comment"> * you are sure that there is active class at prio/level

	comment"> */
sk_buffost" *htb_dequeue_treeost"(struct htb_schedost" *qost", int prioost",
levelsk_buffost" *skbost" = "a href="+code=NULL" class="sref">NULLhtb_classost" *clost", *start
	comment">/* look initial class up in the row */
startclost" = "a href="+code=htb_lookup_leaf" class="sref">htb_lookup_leafost"(qost"->rowost"[levelprioost", prioost",
qost"->ptrost"[levelprioost",
qost"->last_ptr_idost"[levelprioost");
nextost":
unlikelyost"(!"a href="+code=cl" class="sref">clost"))
NULL
	comment">/* class calube empty - it isuunlikely but calube true if leafosspan>

	comment">                 * qdisc drops packet> in enqueue routine or if someone usedosspan>

	comment">                 * graft operation on the leaf since last dequeue;osspan>

	comment">                 * simply deactivate and skip such classosspan>

	comment">                 */
unlikelyost"("a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost"->qost"."a href="+code=qlen" class="sref">qlenost" == 0)) {
htb_classost" *nextost";
htb_deactivateost"(qost", clost");

	comment">/* row/level might become empty */
qost"->row_maskost"[levelprioost")) == 0)
NULLnextost" = "a href="+code=htb_lookup_leaf" class="sref">htb_lookup_leafost"(qost"->rowost"[levelprioost",
prioost", qost"->ptrost"[levelprioost",
qost"->last_ptr_idost"[levelprioost");
clost" == start
	comment">/* fix start if we just deleted it */
startnextost";
clost" = "a href="+code=next" class="sref">nextost";
nextost";
skbost" = "a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost"->dequeueost"("a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost");
likelyost"("a href="+code=skb" class="sref">skbost" != NULLqdisc_warn_nonwcost"(" value="">
	string">"htb", clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost");
htb_next_rb_nodeost"((levelclost"->parentost"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=ptr" class="sref">ptrost" : qost"->
ptrost"[0]) + prioost");
clost" = "a href="+code=htb_lookup_leaf" class="sref">htb_lookup_leafost"(qost"->rowost"[levelprioost", prioost",
qost"->ptrost"[levelprioost",
qost"->last_ptr_idost"[levelprioost");
clost" != startlikelyost"("a href="+code=skb" class="sref">skbost" != NULLbstats_updateost"(&"a href="+code=cl" class="sref">clost"->bstatsost", skbost");
clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=deficit" class="sref">deficitost"[levelqdisc_pkt_lenost"("a href="+code=skb" class="sref">skbost");
clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=deficit" class="sref">deficitost"[levelclost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=deficit" class="sref">deficitost"[levelclost"->quantumost";
htb_next_rb_nodeost"((levelclost"->parentost"->unost"."a href="+code=inner" class="sref">innerost"."a href="+code=ptr" class="sref">ptrost" : qost"->
ptrost"[0]) + prioost");

	comment">/* thisuused to be after charge_class but thisuconstelation

	comment">                 * givesuus slightly better performance

	comment">                 */
clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost"->qost"."a href="+code=qlen" class="sref">qlenost")
htb_deactivateost"(qost", clost");
htb_charge_classost"(qost", clost", levelskbost");
skbost";
sk_buffost" *htb_dequeueost"(struct Qdiscost" *schost")
sk_buffost" *skbost";
htb_schedost" *qost" = "a href="+code=qdisc_priv" class="sref">qdisc_privost"("a href="+code=sch" class="sref">schost");
levelpsched_time_tost" next_eventstart_at
	comment">/* try to dequeue direct packet> asuhigh prio (!) to minimize cpu work */
skbost" = "a href="+code=__skb_dequeue" class="sref">__skb_dequeueost"(&"a href="+code=q" class="sref">qost"->direct_queueost");
skbost" != NULLokost":
qdisc_bstats_updateost"("a href="+code=sch" class="sref">schost", skbost");
qdisc_unthrottledost"("a href="+code=sch" class="sref">schost");
schost"->qost"."a href="+code=qlen" class="sref">qlenost"--;
skbost";
schost"->qost"."a href="+code=qlen" class="sref">qlenost")
finost";
qost"->nowost" = "a href="+code=psched_get_time" class="sref">psched_get_timeost"();
start_atjiffiesost";
next_eventqost"->nowost" + 5 * PSCHED_TICKS_PER_SECost";
levellevelTC_HTB_MAXDEPTHost"; level
	comment">/* commoluease optimization - skip event handler quickly */
most";
psched_time_tost" eventqost"->nowost" >= "a href="+code=q" class="sref">qost"->near_ev_cacheost"[leveleventhtb_do_eventsost"(qost", levelstart_ateventeventqost"->nowost" + PSCHED_TICKS_PER_SECost";
qost"->near_ev_cacheost"[leveleventeventqost"->near_ev_cacheost"[levelnext_eventeventnext_eventeventmost" = ~"a href="+code=q" class="sref">qost"->row_maskost"[levelmost" != (int)(-1)) {
prioost" = "a href="+code=ffz" class="sref">ffzost"(most");
most" |= 1 << prioost";
skbost" = "a href="+code=htb_dequeue_tree" class="sref">htb_dequeue_treeost"(qost", prioost", levellikelyost"("a href="+code=skb" class="sref">skbost" != NULLokost";
schost"->qstatsost"."a href="+code=overlimits" class="sref">overlimitslikelyost"("a href="+code=next_event" class="sref">next_eventqost"->nowost"))
qdisc_watchdog_scheduleost"(&"a href="+code=q" class="sref">qost"->watchdogost", next_eventschedule_workost"(&"a href="+code=q" class="sref">qost"->workost");
finost":
skbost";

	comment">/* try to drop from each class (by prio) until one succeed */
htb_dropost"(struct Qdiscost" *schost")
htb_schedost" *qost" = "a href="+code=qdisc_priv" class="sref">qdisc_privost"("a href="+code=sch" class="sref">schost");
prioost";
prioost" = "a href="+code=TC_HTB_NUMPRIO" class="sref">TC_HTB_NUMPRIOost" - 1; prioost" >= 0; prioost"--) {
list_headost" *post";
list_for_eachost"("a href="+code=p" class="sref">post", qost"->dropsost" + prioost") {
htb_classost" *clost" = "a href="+code=list_entry" class="sref">list_entryost"("a href="+code=p" class="sref">post", struct htb_classost",
unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=drop_list" class="sref">drop_listost");
lenost";
clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost"->opsost"->dropost" &&
lenost" = "a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost"->opsost"->dropost"(clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost"))) {
schost"->qost"."a href="+code=qlen" class="sref">qlenost"--;
clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost"->qost"."a href="+code=qlen" class="sref">qlenost")
htb_deactivateost"(qost", clost");
lenost";

	comment">/* reset all classes */

	comment">/* always caled under BH & queue lock */
htb_resetost"(struct Qdiscost" *schost")
htb_schedost" *qost" = "a href="+code=qdisc_priv" class="sref">qdisc_privost"("a href="+code=sch" class="sref">schost");
htb_classost" *clost";
hlist_nodeost" *nost";
iost";
iost" = 0; iost" < qost"->clhashost"."a href="+code=hashsize" class="sref">hashsizeost"; iost"++) {
hlist_for_each_entryost"(clost", nost", &"a href="+code=q" class="sref">qost"->clhashost"."a href="+code=hash" class="sref">hashost"[iost"], commolost"."a href="+code=hnode" class="sref">hnodeost") {
clost"->levelmemsetost"(&"a href="+code=cl" class="sref">clost"->unost"."a href="+code=inner" class="sref">innerost", 0, sizeof(clost"->unost"."a href="+code=inner" class="sref">innerost"));
clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost")
qdisc_resetost"(clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost");
INIT_LIST_HEADost"(&"a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=drop_list" class="sref">drop_listost");
clost"->prio_activityost" = 0;
clost"->cmodeost" = "a href="+code=HTB_CAN_SEND" class="sref">HTB_CAN_SENDost";
qdisc_watchdog_cancelost"(&"a href="+code=q" class="sref">qost"->watchdogost");
__skb_queue_purgeost"(&"a href="+code=q" class="sref">qost"->direct_queueost");
schost"->qost"."a href="+code=qlen" class="sref">qlenost" = 0;
memsetost"("a href="+code=q" class="sref">qost"->rowost", 0, sizeof(qost"->rowost"));
memsetost"("a href="+code=q" class="sref">qost"->row_maskost", 0, sizeof(qost"->row_maskost"));
memsetost"("a href="+code=q" class="sref">qost"->wait_pqost", 0, sizeof(qost"->wait_pqost"));
memsetost"("a href="+code=q" class="sref">qost"->ptrost", 0, sizeof(qost"->ptrost"));
iost" = 0; iost" < TC_HTB_NUMPRIOost"; iost"++)
INIT_LIST_HEADost"("a href="+code=q" class="sref">qost"->dropsost" + iost");
nla_policyost" htb_policyost"[TCA_HTB_MAXost" + 1] = {
TCA_HTB_PARMSost"] = { ."a href="+code=len" class="sref">lenost" = sizeof(struct tc_htb_optost") },
TCA_HTB_INITost"]  = { ."a href="+code=len" class="sref">lenost" = sizeof(struct tc_htb_globost") },
TCA_HTB_CTABost"]  = { ."a href="+code=type" class="sref">typeost" = "a href="+code=NLA_BINARY" class="sref">NLA_BINARYost", ."a href="+code=len" class="sref">lenost" = TC_RTAB_SIZEost" },
TCA_HTB_RTABost"]  = { ."a href="+code=type" class="sref">typeost" = "a href="+code=NLA_BINARY" class="sref">NLA_BINARYost", ."a href="+code=len" class="sref">lenost" = TC_RTAB_SIZEost" },
htb_work_funcost"(struct work_structost" *workost")
htb_schedost" *qost" = "a href="+code=container_of" class="sref">container_ofost"("a href="+code=work" class="sref">workost", struct htb_schedost", workost");
Qdiscost" *schost" = "a href="+code=q" class="sref">qost"->watchdogost"."a href="+code=qdisc" class="sref">qdiscost";
__netif_scheduleost"("a href="+code=qdisc_root" class="sref">qdisc_rootost"("a href="+code=sch" class="sref">schost"));
htb_initost"(struct Qdiscost" *schost", struct nlattrost" *optost")
htb_schedost" *qost" = "a href="+code=qdisc_priv" class="sref">qdisc_privost"("a href="+code=sch" class="sref">schost");
nlattrost" *tbost"[TCA_HTB_INITost" + 1];
tc_htb_globost" *goptost";
errost";
iost";
optost")
EINVALost";
errost" = "a href="+code=nla_parse_nested" class="sref">nla_parse_nestedost"("a href="+code=tb" class="sref">tbost", TCA_HTB_INITost", optost", htb_policyost");
errost" < 0)
1000ost"                return errost";
1001ost"
1002ost"        if (tbost"[TCA_HTB_INITost"] == NULL1003ost"                pr_errost"(" value="">
	string">"HTB: hey probably you have bad tc tool ?\n");
1004ost"                return -"a href="+code=EINVAL" class="sref">EINVALost";
1005ost"        }
1006ost"        goptost" = "a href="+code=nla_data" class="sref">nla_dataost"("a href="+code=tb" class="sref">tbost"[TCA_HTB_INITost"]);
1007ost"        if (goptost"->versiolost" != HTB_VERost" >> 16) {
1008ost"                pr_errost"(" value="">
	string">"HTB: need tc/htb versiol %d (minor is %d), you have %d\n",
1009ost"                       HTB_VERost" >> 16, HTB_VERost" & 0xffff, goptost"->versiolost");
1010ost"                return -"a href="+code=EINVAL" class="sref">EINVALost";
1011ost"        }
1012ost"
1013ost"        errost" = "a href="+code=qdisc_class_hash_init" class="sref">qdisc_class_hash_initost"(&"a href="+code=q" class="sref">qost"->clhashost");
1014ost"        if (errost" < 0)
1015ost"                return errost";
1016ost"        for (iost" = 0; iost" < TC_HTB_NUMPRIOost"; iost"++)
1017ost"                "a href="+code=INIT_LIST_HEAD" class="sref">INIT_LIST_HEADost"("a href="+code=q" class="sref">qost"->dropsost" + iost");
1018ost"
1019ost"        qdisc_watchdog_initost"(&"a href="+code=q" class="sref">qost"->watchdogost", schost");
1020ost"        INIT_WORKost"(&"a href="+code=q" class="sref">qost"->workost", htb_work_funcost");
1021ost"        skb_queue_head_initost"(&"a href="+code=q" class="sref">qost"->direct_queueost");
1022ost"
1023ost"        qost"->direct_qlenost" = "a href="+code=qdisc_dev" class="sref">qdisc_devost"("a href="+code=sch" class="sref">schost")->tx_queue_lenost";
1024ost"        if (qost"->direct_qlenost" < 2) " value="">
	comment">/* some devices have zero tx_queue_len */
1025ost"                qost"->direct_qlenost" = 2;
1026ost"
1027ost"        if ((qost"->rate2quantumost" = "a href="+code=gopt" class="sref">goptost"->rate2quantumost") < 1)
1028ost"                qost"->rate2quantumost" = 1;
1029ost"        qost"->defclsost" = "a href="+code=gopt" class="sref">goptost"->defclsost";
1030ost"
1031ost"        return 0;
1032ost"}
1033ost"
1034ost"static int htb_dumpost"(struct Qdiscost" *schost", struct sk_buffost" *skbost")
1035ost"{
1036ost"        spinlock_tost" *root_lockost" = "a href="+code=qdisc_root_sleeping_lock" class="sref">qdisc_root_sleeping_lockost"("a href="+code=sch" class="sref">schost");
1037ost"        struct htb_schedost" *qost" = "a href="+code=qdisc_priv" class="sref">qdisc_privost"("a href="+code=sch" class="sref">schost");
1038ost"        struct nlattrost" *nestost";
1039ost"        struct tc_htb_globost" "a href="+code=gopt" class="sref">goptost";
1040ost"
1041ost"        spin_lock_bhost"("a href="+code=root_lock" class="sref">root_lockost");
1042ost"
1043ost"        goptost"."a href="+code=direct_pkts" class="sref">direct_pktsost" = "a href="+code=q" class="sref">qost"->direct_pktsost";
1044ost"        goptost"."a href="+code=versiol" class="sref">versiolost" = HTB_VERost";
1045ost"        goptost"."a href="+code=rate2quantum" class="sref">rate2quantumost" = "a href="+code=q" class="sref">qost"->rate2quantumost";
1046ost"        goptost"."a href="+code=defcls" class="sref">defclsost" = "a href="+code=q" class="sref">qost"->defclsost";
1047ost"        goptost"."a href="+code=debug" class="sref">debugost" = 0;
1048ost"
1049ost"        nestost" = "a href="+code=nla_nest_start" class="sref">nla_nest_startost"("a href="+code=skb" class="sref">skbost", TCA_OPTIONSost");
1050ost"        if (nestost" == NULL1051ost"                goto "a href="+code=nla_put_failure" class="sref">nla_put_failureost";
1052ost"        if (nla_putost"("a href="+code=skb" class="sref">skbost", TCA_HTB_INITost", sizeof(goptost"), &"a href="+code=gopt" class="sref">goptost"))
1053ost"                goto "a href="+code=nla_put_failure" class="sref">nla_put_failureost";
1054ost"        nla_nest_endost"("a href="+code=skb" class="sref">skbost", nestost");
1055ost"
1056ost"        spin_unlock_bhost"("a href="+code=root_lock" class="sref">root_lockost");
1057ost"        return skbost"->lenost";
1058ost"
1059ost""a href="+code=nla_put_failure" class="sref">nla_put_failureost":
1060ost"        spin_unlock_bhost"("a href="+code=root_lock" class="sref">root_lockost");
1061ost"        nla_nest_cancelost"("a href="+code=skb" class="sref">skbost", nestost");
1062ost"        return -1;
1063ost"}
1064ost"
1065ost"static int htb_dump_classost"(struct Qdiscost" *schost", unsigned long argost",
1066ost"                          struct sk_buffost" *skbost", struct tcmsgost" *tcm1067ost"{
1068ost"        struct htb_classost" *clost" = (struct htb_classost" *)argost";
1069ost"        spinlock_tost" *root_lockost" = "a href="+code=qdisc_root_sleeping_lock" class="sref">qdisc_root_sleeping_lockost"("a href="+code=sch" class="sref">schost");
1070ost"        struct nlattrost" *nestost";
1071ost"        struct tc_htb_optost" optost";
1072ost"
1073ost"        spin_lock_bhost"("a href="+code=root_lock" class="sref">root_lockost");
1074ost"        tcmtcm_parentost" = "a href="+code=cl" class="sref">clost"->parentost" ? "a href="+code=cl" class="sref">clost"->parentost"->commolost"."a href="+code=classid" class="sref">classidost" : TC_H_ROOTost";
1075ost"        tcmtcm_handleost" = "a href="+code=cl" class="sref">clost"->commolost"."a href="+code=classid" class="sref">classidost";
1076ost"        if (!"a href="+code=cl" class="sref">clost"->levelclost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost")
1077ost"                "a href="+code=tcm" class="sref">tcmtcm_infoost" = "a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost"->handleost";
1078ost"
1079ost"        nestost" = "a href="+code=nla_nest_start" class="sref">nla_nest_startost"("a href="+code=skb" class="sref">skbost", TCA_OPTIONSost");
1080ost"        if (nestost" == NULL1081ost"                goto "a href="+code=nla_put_failure" class="sref">nla_put_failureost";
1082ost"
1083ost"        memsetost"(&"a href="+code=opt" class="sref">optost", 0, sizeof(optost"));
1084ost"
1085ost"        optost"."a href="+code=rate" class="sref">rateost" = "a href="+code=cl" class="sref">clost"->rateost"->rateost";
1086ost"        optost"."a href="+code=buffer" class="sref">bufferost" = "a href="+code=cl" class="sref">clost"->bufferost";
1087ost"        optost"."a href="+code=ceil" class="sref">ceilost" = "a href="+code=cl" class="sref">clost"->ceilost"->rateost";
1088ost"        optost"."a href="+code=cbuffer" class="sref">cbufferost" = "a href="+code=cl" class="sref">clost"->cbufferost";
1089ost"        optost"."a href="+code=quantum" class="sref">quantumost" = "a href="+code=cl" class="sref">clost"->quantumost";
1090ost"        optost"."a href="+code=prio" class="sref">prioost" = "a href="+code=cl" class="sref">clost"->prioost";
1091ost"        optost"."a href="+code=level" class="sref">levelclost"->level1092ost"        if (nla_putost"("a href="+code=skb" class="sref">skbost", TCA_HTB_PARMSost", sizeof(optost"), &"a href="+code=opt" class="sref">optost"))
1093ost"                goto "a href="+code=nla_put_failure" class="sref">nla_put_failureost";
1094ost"
1095ost"        nla_nest_endost"("a href="+code=skb" class="sref">skbost", nestost");
1096ost"        spin_unlock_bhost"("a href="+code=root_lock" class="sref">root_lockost");
1097ost"        return skbost"->lenost";
1098ost"
1099ost""a href="+code=nla_put_failure" class="sref">nla_put_failureost":
1100ost"        spin_unlock_bhost"("a href="+code=root_lock" class="sref">root_lockost");
1101ost"        nla_nest_cancelost"("a href="+code=skb" class="sref">skbost", nestost");
1102ost"        return -1;
1103ost"}
1104ost"
1105ost"static int
1106ost"htb_dump_class_statsost"(struct Qdiscost" *schost", unsigned long argost", struct gnet_dumpost" *d1107ost"{
1108ost"        struct htb_classost" *clost" = (struct htb_classost" *)argost";
1109ost"
1110ost"        if (!"a href="+code=cl" class="sref">clost"->levelclost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t")
1111ost"                "a href="+code=cl" class="sref">clost"->qstatsost"."a href="+code=qlen" class="sref">qlenost" = "a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t"->qost"."a href="+code=qlen" class="sref">qlenost";
1112ost"        clost"->xstatsost"."a href="+code=tokens" class="sref">tokensost" = "a href="+code=cl" class="sref">clost"->tokensost";
1113ost"        clost"->xstatsost"."a href="+code=ctokens" class="sref">ctokensost" = "a href="+code=cl" class="sref">clost"->ctokensost";
1114ost"
1115ost"        if (gnet_stats_copy_basicost"("a href="+code=d" class="sref">dclost"->bstatsost") < 0 ||
1116ost"            gnet_stats_copy_rate_estost"("a href="+code=d" class="sref">dNULLclost"->rate_estost") < 0 ||
1117ost"            gnet_stats_copy_queueost"("a href="+code=d" class="sref">dclost"->qstatsost") < 0)
1118ost"                return -1;
1119ost"
1120ost"        return gnet_stats_copy_appost"("a href="+code=d" class="sref">dclost"->xstatsost", sizeof(clost"->xstatsost"));
1121ost"}
1122ost"
1123ost"static int htb_graftost"(struct Qdiscost" *schost", unsigned long argost", struct Qdiscost" *newost",
1124ost"                     struct Qdiscost" **oldo/t")
1125ost"{
1126ost"        struct htb_classost" *clost" = (struct htb_classost" *)argost";
1127ost"
1128ost"        if (clost"->level1129ost"                return -"a href="+code=EINVAL" class="sref">EINVALost";
1130ost"        if (newost" == NULL1131ost"            (newost" = "a href="+code=qdisc_create_dflt" class="sref">qdisc_create_dfltost"("a href="+code=sch" class="sref">schost"->dev_queuepfifo_qdisc_opsost",
1132ost"                                     "a href="+code=cl" class="sref">clost"->commolost"."a href="+code=classid" class="sref">classidost")) == NULL1133ost"                return -"a href="+code=ENOBUFS" class="sref">ENOBUFSost";
1134ost"
1135ost"        sch_tree_lockost"("a href="+code=sch" class="sref">schost");
1136ost"        *oldo/t" = "a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t";
1137ost"        clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t" = "a href="+code=new" class="sref">newost";
1138ost"        if (*oldo/t" != NULL1139ost"                "a href="+code=qdisc_tree_decrease_qlen" class="sref">qdisc_tree_decrease_qlenost"(*oldo/t", (*oldo/t")->qost"."a href="+code=qlen" class="sref">qlenost");
1140ost"                "a href="+code=qdisc_reset" class="sref">qdisc_resetost"(*oldo/t");
1141ost"        }
1142ost"        sch_tree_unlockost"("a href="+code=sch" class="sref">schost");
1143ost"        return 0;
1144ost"}
1145ost"
1146ost"static struct Qdiscost" *htb_leafost"(struct Qdiscost" *schost", unsigned long argost")
1147ost"{
1148ost"        struct htb_classost" *clost" = (struct htb_classost" *)argost";
1149ost"        return !"a href="+code=cl" class="sref">clost"->levelclost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t" : NULL1150ost"}
1151ost"
1152ost"static void htb_qlen_notifyost"(struct Qdiscost" *schost", unsigned long argost")
1153ost"{
1154ost"        struct htb_classost" *clost" = (struct htb_classost" *)argost";
1155ost"
1156ost"        if ("a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t"->qost"."a href="+code=qlen" class="sref">qlenost" == 0)
1157ost"                "a href="+code=htb_deactivate" class="sref">htb_deactivateost"("a href="+code=qdisc_priv" class="sref">qdisc_privost"("a href="+code=sch" class="sref">schost"), "a href="+code=cl" class="sref">clost");
1158ost"}
1159ost"
1160ost"static unsigned long htb_getost"(struct Qdiscost" *schost", u32ost" "a href="+code=classid" class="sref">classidost")
1161ost"{
1162ost"        struct htb_classost" *clost" = htb_findost"("a href="+code=classid" class="sref">classidost", schost");
1163ost"        if ("a href="+code=cl" class="sref">clost")
1164ost"                "a href="+code=cl" class="sref">clost"->refcntost"++;
1165ost"        return (unsigned long)clost";
1166ost"}
1167ost"
1168ost"static inlineost" int htb_parent_last_childost"(struct htb_classost" *clost")
1169ost"{
1170ost"        if (!"a href="+code=cl" class="sref">clost"->parentost")
1171ost"                " value="">
	comment">/* the rootue=""> */
1172ost"                return 0;
1173ost"        if ("a href="+code=cl" class="sref">clost"->parentost"->childrenost" > 1)
1174ost"                " value="">
	comment">/* not the last child */
1175ost"                return 0;
1176ost"        return 1;
1177ost"}
1178ost"
1179ost"static void htb_parent_to_leafost"(struct htb_schedost" *qost", struct htb_classost" *clost",
1180ost"                               struct Qdiscost" *new_qost")
1181ost"{
1182ost"        struct htb_classost" *parentost" = "a href="+code=cl" class="sref">clost"->parentost";
1183ost"
1184ost"        WARN_ONost"("a href="+code=cl" class="sref">clost"->levelclost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t" || "a href="+code=cl" class="sref">clost"->prio_activityost");
1185ost"
1186ost"        if ("a href="+code=parent" class="sref">parentost"->cmodeost" != HTB_CAN_SENDost")
1187ost"                "a href="+code=htb_safe_rb_erase" class="sref">htb_safe_rb_eraseost"(&"a href="+code=parent" class="sref">parentost"->pq_nodeost", qo/t"->wait_pqost" + parentost"->level1188ost"
1189ost"        parentost"->level1190ost"        memsetost"(&"a href="+code=parent" class="sref">parentost"->unost"."a href="+code=inner" class="sref">innerost", 0, sizeof(parentost"->unost"."a href="+code=inner" class="sref">innerost"));
1191ost"        INIT_LIST_HEADost"(&"a href="+code=parent" class="sref">parentost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=drop_list" class="sref">drop_list1192ost"        parentost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t" = "a href="+code=new_q" class="sref">new_qost" ? "a href="+code=new_q" class="sref">new_qost" : &"a href="+code=noop_qdisc" class="sref">noop_qdiscost";
1193ost"        parentost"->tokensost" = "a href="+code=parent" class="sref">parentost"->bufferost";
1194ost"        parentost"->ctokensost" = "a href="+code=parent" class="sref">parentost"->cbufferost";
1195ost"        parentost"->t_cost" = "a href="+code=psched_get_time" class="sref">psched_get_timeost"();
1196ost"        parentost"->cmodeost" = HTB_CAN_SENDost";
1197ost"}
1198ost"
1199ost"static void htb_destroy_classost"(struct Qdiscost" *schost", struct htb_classost" *clost")
1200ost"{
1201ost"        if (!"a href="+code=cl" class="sref">clost"->level1202ost"                WARN_ONost"(!"a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t");
1203ost"                "a href="+code=qdisc_destroy" class="sref">qdisc_destroyost"("a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t");
1204ost"        }
1205ost"        gen_kill_estimatorost"(&"a href="+code=cl" class="sref">clost"->bstatsost", &"a href="+code=cl" class="sref">clost"->rate_estost");
1206ost"        qdisc_put_rtabost"("a href="+code=cl" class="sref">clost"->rateost");
1207ost"        qdisc_put_rtabost"("a href="+code=cl" class="sref">clost"->ceilost");
1208ost"
1209ost"        tcf_destroy_chainost"(&"a href="+code=cl" class="sref">clost"->filter_listost");
1210ost"        kfreeost"("a href="+code=cl" class="sref">clost");
1211ost"}
1212ost"
1213ost"static void htb_destroyost"(struct Qdiscost" *schost")
1214ost"{
1215ost"        struct htb_schedost" *qost" = "a href="+code=qdisc_priv" class="sref">qdisc_privost"("a href="+code=sch" class="sref">schost");
1216ost"        struct hlist_nodeost" *nost", *nextost";
1217ost"        struct htb_classost" *clost";
1218ost"        unsigned int iost";
1219ost"
1220ost"        cancel_work_syncost"(&"a href="+code=q" class="sref">qo/t"->workost");
1221ost"        qdisc_watchdog_cancelost"(&"a href="+code=q" class="sref">qo/t"->watchdogost");
1222ost"        < value="">
	comment">/* This line used to be after htb_destroy_class call below
1223ost"< value="">
	comment">         * and surprisingly it worked in 2.4. But it must precede it
1224ost"< value="">
	comment">         * because filter need its targetue=""> alive to be able to call
1225ost"< value="">
	comment">         * unbind_filter on it (without Oops).
1226ost"< value="">
	comment">         */
1227ost"        tcf_destroy_chainost"(&"a href="+code=q" class="sref">qo/t"->filter_listost");
1228ost"
1229ost"        for ("a href="+code=i" class="sref">iost" = 0; iost" < "a href="+code=q" class="sref">qo/t"->clhashost"."a href="+code=hashsize" class="sref">hashsizeost"; iost"++) {
1230ost"                "a href="+code=hlist_for_each_entry" class="sref">hlist_for_each_entryost"("a href="+code=cl" class="sref">clost", nost", &"a href="+code=q" class="sref">qo/t"->clhashost"."a href="+code=hash" class="sref">hashost"[iost"], "a href="+code=commol" class="sref">commolost"."a href="+code=hnode" class="sref">hnodeost")
1231ost"                        "a href="+code=tcf_destroy_chain" class="sref">tcf_destroy_chainost"(&"a href="+code=cl" class="sref">clost"->filter_listost");
1232ost"        }
1233ost"        for ("a href="+code=i" class="sref">iost" = 0; iost" < "a href="+code=q" class="sref">qo/t"->clhashost"."a href="+code=hashsize" class="sref">hashsizeost"; iost"++) {
1234ost"                "a href="+code=hlist_for_each_entry_safe" class="sref">hlist_for_each_entry_safeost"("a href="+code=cl" class="sref">clost", nost", nextost", &"a href="+code=q" class="sref">qo/t"->clhashost"."a href="+code=hash" class="sref">hashost"[iost"],
1235ost"                                          "a href="+code=commol" class="sref">commolost"."a href="+code=hnode" class="sref">hnodeost")
1236ost"                        "a href="+code=htb_destroy_class" class="sref">htb_destroy_classost"(schost", "a href="+code=cl" class="sref">clost");
1237ost"        }
1238ost"        qdisc_class_hash_destroyost"(&"a href="+code=q" class="sref">qo/t"->clhashost");
1239ost"        __skb_queue_purgeost"(&"a href="+code=q" class="sref">qo/t"->direct_queueost");
1240ost"}
1241ost"
1242ost"static int htb_deleteost"(struct Qdiscost" *schost", unsigned long argost")
1243ost"{
1244ost"        struct htb_schedost" *qost" = "a href="+code=qdisc_priv" class="sref">qdisc_privost"("a href="+code=sch" class="sref">schost");
1245ost"        struct htb_classost" *clost" = (struct htb_classost" *)argost";
1246ost"        unsigned int qlenost";
1247ost"        struct Qdiscost" *new_qost" = "a href="+code=NULL" class="sref">NULL1248ost"        int last_childost" = 0;
1249ost"
1250ost"        < value="">
	comment">// TODO: why don't allow to delete subtree ? references ? does
1251ost"        < value="">
	comment">// tc subsys quarantee us that in htb_destroy it holds no classosspan>
1252ost"        < value="">
	comment">// refs so that we caluremove children safely there ?osspan>
1253ost"        if ("a href="+code=cl" class="sref">clost"->childrenost" || "a href="+code=cl" class="sref">clost"->filter_cntost")
1254ost"                return -"a href="+code=EBUSY" class="sref">EBUSY1255ost"
1256ost"        if (!"a href="+code=cl" class="sref">clost"->levelhtb_parent_last_childost"("a href="+code=cl" class="sref">clost")) {
1257ost"                "a href="+code=new_q" class="sref">new_qost" = "a href="+code=qdisc_create_dflt" class="sref">qdisc_create_dfltost"("a href="+code=sch" class="sref">schost"->dev_queuepfifo_qdisc_opsost",
1258ost"                                          "a href="+code=cl" class="sref">clost"->parentost"->commolost"."a href="+code=classid" class="sref">classidost");
1259ost"                "a href="+code=last_child" class="sref">last_childost" = 1;
1260ost"        }
1261ost"
1262ost"        sch_tree_lockost"("a href="+code=sch" class="sref">schost");
1263ost"
1264ost"        if (!"a href="+code=cl" class="sref">clost"->level1265ost"                qlenost" = "a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t"->qost"."a href="+code=qlen" class="sref">qlenost";
1266ost"                "a href="+code=qdisc_reset" class="sref">qdisc_resetost"("a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t");
1267ost"                "a href="+code=qdisc_tree_decrease_qlen" class="sref">qdisc_tree_decrease_qlenost"("a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t", qlenost");
1268ost"        }
1269ost"
1270ost"        < value="">
	comment">/* delete from hash and active;uremainder in destroy_class */
1271ost"        qdisc_class_hash_removeost"(&"a href="+code=q" class="sref">qo/t"->clhashost", &"a href="+code=cl" class="sref">clost"->commolost");
1272ost"        if ("a href="+code=cl" class="sref">clost"->parentost")
1273ost"                "a href="+code=cl" class="sref">clost"->parentost"->childrenost"--;
1274ost"
1275ost"        if ("a href="+code=cl" class="sref">clost"->prio_activityost")
1276ost"                "a href="+code=htb_deactivate" class="sref">htb_deactivateost"("a href="+code=q" class="sref">qo/t", clost");
1277ost"
1278ost"        if (clost"->cmodeost" != HTB_CAN_SENDost")
1279ost"                "a href="+code=htb_safe_rb_erase" class="sref">htb_safe_rb_eraseost"(&"a href="+code=cl" class="sref">clost"->pq_nodeost", qo/t"->wait_pqost" + clost"->level1280ost"
1281ost"        if ("a href="+code=last_child" class="sref">last_childost")
1282ost"                htb_parent_to_leafost"("a href="+code=q" class="sref">qo/t", clost", new_qost");
1283ost"
1284ost"        BUG_ONost"(--"a href="+code=cl" class="sref">clost"->refcntost" == 0);
1285ost"        < value="">
	comment">/*
1286ost"< value="">
	comment">         * This shouldn't happen: we "hold" one cops->get() when calledosspan>
1287ost"< value="">
	comment">         * from tc_ctl_te="">; the destroy method is done from cops->put().
1288ost"< value="">
	comment">         */
1289ost"
1290ost"        sch_tree_unlockost"("a href="+code=sch" class="sref">schost");
1291ost"        return 0;
1292ost"}
1293ost"
1294ost"static void htb_putost"(struct Qdiscost" *schost", unsigned long argost")
1295ost"{
1296ost"        struct htb_classost" *clost" = (struct htb_classost" *)argost";
1297ost"
1298ost"        if (--"a href="+code=cl" class="sref">clost"->refcntost" == 0)
1299ost"                "a href="+code=htb_destroy_class" class="sref">htb_destroy_classost"(schost", "a href="+code=cl" class="sref">clost");
1300ost"}
1301ost"
1302ost"static int htb_change_classost"(struct Qdiscost" *schost", u32ost" "a href="+code=classid" class="sref">classidost",
1303ost"                            "a href="+code=u32" class="sref">u32ost" "a href="+code=parentid" class="sref">parentidost", struct nlattrost" **tcaost",
1304ost"                            unsigned long *argost")
1305ost"{
1306ost"        int errost" = -"a href="+code=EINVAL" class="sref">EINVALost";
1307ost"        struct htb_schedost" *qost" = "a href="+code=qdisc_priv" class="sref">qdisc_privost"("a href="+code=sch" class="sref">schost");
1308ost"        struct htb_classost" *clost" = (struct htb_classost" *)*argost", *parentost";
1309ost"        struct nlattrost" *optost" = "a href="+code=tca" class="sref">tcaost"[TCA_OPTIONSost"];
1310ost"        struct qdisc_rate_tableost" *rtabost" = "a href="+code=NULL" class="sref">NULLctabost" = "a href="+code=NULL" class="sref">NULL1311ost"        struct nlattrost" *tbost"[__TCA_HTB_MAXost"];
1312ost"        struct tc_htb_optost" *hoptost";
1313ost"
1314ost"        < value="">
	comment">/* extract all subattrs from opt attr */
1315ost"        if (!"a href="+code=opt" class="sref">optost")
1316ost"                goto failureost";
1317ost"
1318ost"        errost" = nla_parse_nestedost"("a href="+code=tb" class="sref">tbost", TCA_HTB_MAXost", optost", htb_policyost");
1319ost"        if (errost" < 0)
1320ost"                goto failureost";
1321ost"
1322ost"        errost" = -"a href="+code=EINVAL" class="sref">EINVALost";
1323ost"        if ("a href="+code=tb" class="sref">tbost"[TCA_HTB_PARMSost"] == "a href="+code=NULL" class="sref">NULL1324ost"                goto failureost";
1325ost"
1326ost"        parentost" = "a href="+code=parentid" class="sref">parentidost" == "a href="+code=TC_H_ROOT" class="sref">TC_H_ROOTost" ? "a href="+code=NULL" class="sref">NULLhtb_findost"("a href="+code=parentid" class="sref">parentidost", "a href="+code=sch" class="sref">schost");
1327ost"
1328ost"        hoptost" = nla_dataost"("a href="+code=tb" class="sref">tbost"[TCA_HTB_PARMSost"]);
1329ost"
1330ost"        rtabost" = "a href="+code=qdisc_get_rtab" class="sref">qdisc_get_rtabost"(&"a href="+code=hopt" class="sref">hoptost"->rateost", "a href="+code=tb" class="sref">tbost"[TCA_HTB_RTABost"]);
1331ost"        ctabost" = "a href="+code=qdisc_get_rtab" class="sref">qdisc_get_rtabost"(&"a href="+code=hopt" class="sref">hoptost"->ceilost", "a href="+code=tb" class="sref">tbost"[TCA_HTB_CTABost"]);
1332ost"        if (!"a href="+code=rtab" class="sref">rtabost" || !"a href="+code=ctab" class="sref">ctabost")
1333ost"                goto failureost";
1334ost"
1335ost"        if (!"a href="+code=cl" class="sref">clost") {              < value="">
	comment">/* newue=""> */
1336ost"                struct Qdiscost" *new_qost";
1337ost"                int prioost";
1338ost"                struct {
1339ost"                        struct nlattrost"           nlaost";
1340ost"                        struct gnet_estimatorost"   optost";
1341ost"                } estost" = {
1342ost"                        ."a href="+code=nla" class="sref">nlaost" = {
1343ost"                                ."a href="+code=nla_len" class="sref">nla_lenost"        = nla_attr_sizeost"(sizeof(estost"."a href="+code=opt" class="sref">optost")),
1344ost"                                ."a href="+code=nla_type" class="sref">nla_typeost"       = "a href="+code=TCA_RATE" class="sref">TCA_RATEost",
1345ost"                        },
1346ost"                        ."a href="+code=opt" class="sref">optost" = {
1347ost"                                < value="">
	comment">/* 4s interval, 16s averaging constant */
1348ost"                                ."a href="+code=interval" class="sref">intervalost"       = 2,
1349ost"                                ."a href="+code=ewma_log" class="sref">ewma_logost"       = 2,
1350ost"                        },
1351ost"                };
1352ost"
1353ost"                " value="">
	comment">/* check for validue="">idu*/
1354ost"                if (!"a href="+code=classid" class="sref">classidost" || "a href="+code=TC_H_MAJ" class="sref">TC_H_MAJost"("a href="+code=classid" class="sref">classidost" ^ "a href="+code=sch" class="sref">schost"->handleost") ||
1355ost"                    htb_findost"("a href="+code=classid" class="sref">classidost", "a href="+code=sch" class="sref">schost"))
1356ost"                        goto failureost";
1357ost"
1358ost"                " value="">
	comment">/* check maximal depthu*/
1359ost"                if ("a href="+code=parent" class="sref">parentost" && "a href="+code=parent" class="sref">parentost"->parentost" && "a href="+code=parent" class="sref">parentost"->parentost"->level1360ost"                        pr_errost"(" value="">
	string">"htb: tree is too deep\n");
1361ost"                        goto failureost";
1362ost"                }
1363ost"                "a href="+code=err" class="sref">errost" = -"a href="+code=ENOBUFS" class="sref">ENOBUFSost";
1364ost"                "a href="+code=cl" class="sref">clost" = "a href="+code=kzalloc" class="sref">kzallocost"(sizeof(*clost"), "a href="+code=GFP_KERNEL" class="sref">GFP_KERNELost");
1365ost"                if (!"a href="+code=cl" class="sref">clost")
1366ost"                        goto failureost";
1367ost"
1368ost"                "a href="+code=err" class="sref">errost" = gen_new_estimatorost"(&"a href="+code=cl" class="sref">clost"->bstatsost", &"a href="+code=cl" class="sref">clost"->rate_estost",
1369ost"                                        "a href="+code=qdisc_root_sleeping_lock" class="sref">qdisc_root_sleeping_lockost"("a href="+code=sch" class="sref">schost"),
1370ost"                                        "a href="+code=tca" class="sref">tcaost"[TCA_RATEost"] ? : &"a href="+code=est" class="sref">estost"."a href="+code=nla" class="sref">nlaost");
1371ost"                if (errost") {
1372ost"                        "a href="+code=kfree" class="sref">kfreeost"("a href="+code=cl" class="sref">clost");
1373ost"                        goto failureost";
1374ost"                }
1375ost"
1376ost"                "a href="+code=cl" class="sref">clost"->refcntost" = 1;
1377ost"                "a href="+code=cl" class="sref">clost"->childrenost" = 0;
1378ost"                "a href="+code=INIT_LIST_HEAD" class="sref">INIT_LIST_HEADost"(&"a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=drop_list" class="sref">drop_listost");
1379ost"                "a href="+code=RB_CLEAR_NODE" class="sref">RB_CLEAR_NODEost"(&"a href="+code=cl" class="sref">clost"->pq_nodeost");
1380ost"
1381ost"                for ("a href="+code=prio" class="sref">prioost" = 0; prioost" < "a href="+code=TC_HTB_NUMPRIO" class="sref">TC_HTB_NUMPRIOost"; prioost"++)
1382ost"                        "a href="+code=RB_CLEAR_NODE" class="sref">RB_CLEAR_NODEost"(&"a href="+code=cl" class="sref">clost"->nodeost"[prioost"]);
1383ost"
1384ost"                " value="">
	comment">/* create leaf qdisc early because it uses kmalloc(GFP_KERNEL)
1385ost"< value="">
	comment">                 * so that can't be used inside of sch_tree_lockosspan>
1386ost"< value="">
	comment">                 * -- thanks to Karlis Peisenieksosspan>
1387ost"< value="">
	comment">                 */
1388ost"                "a href="+code=new_q" class="sref">new_qost" = "a href="+code=qdisc_create_dflt" class="sref">qdisc_create_dfltost"("a href="+code=sch" class="sref">schost"->dev_queue1389ost"                                          &"a href="+code=pfifo_qdisc_ops" class="sref">pfifo_qdisc_opsost", "a href="+code=classid" class="sref">classidost");
1390ost"                "a href="+code=sch_tree_lock" class="sref">sch_tree_lockost"("a href="+code=sch" class="sref">schost");
1391ost"                if (parentost" && !"a href="+code=parent" class="sref">parentost"->level1392ost"                        unsigned int qlenost" = "a href="+code=parent" class="sref">parentost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t"->qost"."a href="+code=qlen" class="sref">qlenost";
1393ost"
1394ost"                        " value="">
	comment">/* turn parent into inner node */
1395ost"                        "a href="+code=qdisc_reset" class="sref">qdisc_resetost"("a href="+code=parent" class="sref">parentost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t");
1396ost"                        "a href="+code=qdisc_tree_decrease_qlen" class="sref">qdisc_tree_decrease_qlenost"("a href="+code=parent" class="sref">parentost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t", qlenost");
1397ost"                        "a href="+code=qdisc_destroy" class="sref">qdisc_destroyost"("a href="+code=parent" class="sref">parentost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qo/t");
1398ost"                        if (parentost"->prio_activityost")
1399ost"                                "a href="+code=htb_deactivate" class="sref">htb_deactivateost"("a href="+code=q" class="sref">qo/t", parentost");
1400ost"
1401ost"                        " value="">
	comment">/* remove from evt list because of level change */
1402ost"                        if (parentost"->cmodeost" != HTB_CAN_SENDost") {
1403ost"                                "a href="+code=htb_safe_rb_erase" class="sref">htb_safe_rb_eraseost"(&"a href="+code=parent" class="sref">parentost"->pq_nodeost", qo/t"->wait_pqost");
1404ost"                                "a href="+code=parent" class="sref">parentost"->cmodeost" = HTB_CAN_SENDost";
1405ost"                        }
1406ost"                        "a href="+code=parent" class="sref">parentost"->levelparentost"->parentost" ? "a href="+code=parent" class="sref">parentost"->parentost"->level1407ost"                                         : TC_HTB_MAXDEPTHost") - 1;
1408ost"                        memsetost"(&"a href="+code=parent" class="sref">parentost"->unost"."a href="+code=inner" class="sref">innerost", 0, sizeof(parentost"->unost"."a href="+code=inner" class="sref">innerost"));
1409ost"                }
1410ost"                " value="">
	comment">/* leaf (we) needs elementary qdisc */
1411ost"                "a href="+code=cl" class="sref">clost"->unost"."a href="+code=leaf" class="sref">leafost"."a href="+code=q" class="sref">qost" = "a href="+code=new_q" class="sref">new_qost" ? "a href="+code=new_q" class="sref">new_qost" : &"a href="+code=noop_qdisc" class="sref">noop_qdiscost";
1412ost"
1413ost"                "a href="+code=cl" class="sref">clost"->commolost"."a href="+code=classid" class="sref">classidost" = "a href="+code=classid" class="sref">classidost";
1414ost"                "a href="+code=cl" class="sref">clost"->parentost" = "a href="+code=parent" class="sref">parentost";
1415ost"
1416ost"                " value="">
	comment">/* setue=""> to be in HTB_CAN_SEND state */
1417ost"                "a href="+code=cl" class="sref">clost"->tokensost" = "a href="+code=hopt" class="sref">hoptost"->bufferost";
1418ost"                "a href="+code=cl" class="sref">clost"->ctokensost" = "a href="+code=hopt" class="sref">hoptost"->cbufferost";
1419ost"                "a href="+code=cl" class="sref">clost"->mbufferost" = 60 * "a href="+code=PSCHED_TICKS_PER_SEC" class="sref">PSCHED_TICKS_PER_SECost";        " value="">
	comment">/* 1min */
1420ost"                "a href="+code=cl" class="sref">clost"->t_cost" = "a href="+code=psched_get_time" class="sref">psched_get_timeost"();
1421ost"                "a href="+code=cl" class="sref">clost"->cmodeost" = HTB_CAN_SENDost";
1422ost"
1423ost"                " value="">
	comment">/* attach to the hash list and parent's family */
1424ost"                "a href="+code=qdisc_class_hash_insert" class="sref">qdisc_class_hash_insertost"(&"a href="+code=q" class="sref">qo/t"->clhashost", &"a href="+code=cl" class="sref">clost"->commolost");
1425ost"                if (parentost")
1426ost"                        "a href="+code=parent" class="sref">parentost"->childrenost"++;
1427ost"        } else {
1428ost"                if ("a href="+code=tca" class="sref">tcaost"[TCA_RATEost"]) {
1429ost"                        errost" = gen_replace_estimatorost"(&"a href="+code=cl" class="sref">clost"->bstatsost", &"a href="+code=cl" class="sref">clost"->rate_estost",
1430ost"                                                    "a href="+code=qdisc_root_sleeping_lock" class="sref">qdisc_root_sleeping_lockost"("a href="+code=sch" class="sref">schost"),
1431ost"                                                    "a href="+code=tca" class="sref">tcaost"[TCA_RATEost"]);
1432ost"                        if (errost")
1433ost"                                return errost";
1434ost"                }
1435ost"                "a href="+code=sch_tree_lock" class="sref">sch_tree_lockost"("a href="+code=sch" class="sref">schost");
1436ost"        }
1437ost"
1438ost"        " value="">
	comment">/* it used to be a nasty bug here, we have to check that nodeosspan>
1439ost"< value="">
	comment">         * is really leaf before changing cl->un.leaf !osspan>
1440ost"< value="">
	comment">         */
1441ost"        if (!"a href="+code=cl" class="sref">clost"->level1442ost"                "a href="+code=cl" class="sref">clost"->quantumost" = rtabost"->rateost"."a href="+code=rate" class="sref">rateost" / qo/t"->rate2quantumost";
1443ost"                if (!"a href="+code=hopt" class="sref">hoptost"->quantumost" && "a href="+code=cl" class="sref">clost"->quantumost" < 1000) {
1444ost"                        "a href="+code=pr_warning" class="sref">pr_warningost"(
1445ost"                               " value="">
	string">"HTB: quantum of e=""> %X is small. Consider r2q change.\n",
1446ost"                               "a href="+code=cl" class="sref">clost"->commolost"."a href="+code=classid" class="sref">classidost");
1447ost"                        "a href="+code=cl" class="sref">clost"->quantumost" = 1000;
1448ost"                }
1449ost"                if (!"a href="+code=hopt" class="sref">hoptost"->quantumost" && "a href="+code=cl" class="sref">clost"->quantumost" > 200000) {
1450ost"                        "a href="+code=pr_warning" class="sref">pr_warningost"(
1451ost"                               " value="">
	string">"HTB: quantum of e=""> %X is big. Consider r2q change.\n",
1452ost"                               "a href="+code=cl" class="sref">clost"->commolost"."a href="+code=classid" class="sref">classidost");
1453ost"                        "a href="+code=cl" class="sref">clost"->quantumost" = 200000;
1454ost"                }
1455ost"                if (hoptost"->quantumost")
1456ost"                        "a href="+code=cl" class="sref">clost"->quantumost" = hoptost"->quantumost";
1457ost"                if (("a href="+code=cl" class="sref">clost"->prioost" = hoptost"->prioost") >= "a href="+code=TC_HTB_NUMPRIO" class="sref">TC_HTB_NUMPRIOost")
1458ost"                        "a href="+code=cl" class="sref">clost"->prioost" = TC_HTB_NUMPRIOost" - 1;
1459ost"        }
1460ost"
1461ost"        "a href="+code=cl" class="sref">clost"->bufferost" = "a href="+code=hopt" class="sref">hoptost"->bufferost";
1462ost"        "a href="+code=cl" class="sref">clost"->cbufferost" = "a href="+code=hopt" class="sref">hoptost"->cbufferost";
1463ost"        if ("a href="+code=cl" class="sref">clost"->rateost")
1464ost"                "a href="+code=qdisc_put_rtab" class="sref">qdisc_put_rtabost"("a href="+code=cl" class="sref">clost"->rateost");
1465ost"        "a href="+code=cl" class="sref">clost"->rateost" = rtabost";
1466ost"        if ("a href="+code=cl" class="sref">clost"->ceilost")
1467ost"                "a href="+code=qdisc_put_rtab" class="sref">qdisc_put_rtabost"("a href="+code=cl" class="sref">clost"->ceilost");
1468ost"        clost"->ceilost" = "a href="+code=ctab" class="sref">ctabost";
1469ost"        "a href="+code=sch_tree_unlock" class="sref">sch_tree_unlockost"("a href="+code=sch" class="sref">schost");
1470ost"
1471ost"        "a href="+code=qdisc_class_hash_grow" class="sref">qdisc_class_hash_growost"("a href="+code=sch" class="sref">schost", &"a href="+code=q" class="sref">qo/t"->clhashost");
1472ost"
1473ost"        *argost" = (unsigned long)clost";
1474ost"        return 0;
1475ost"
1476ost"failureost":
1477ost"        if ("a href="+code=rtab" class="sref">rtabost")
1478ost"                "a href="+code=qdisc_put_rtab" class="sref">qdisc_put_rtabost"("a href="+code=rtab" class="sref">rtabost");
1479ost"        if ("a href="+code=ctab" class="sref">ctabost")
1480ost"                "a href="+code=qdisc_put_rtab" class="sref">qdisc_put_rtabost"("a href="+code=ctab" class="sref">ctabost");
1481ost"        return errost";
1482ost"}
1483ost"
1484ost"static struct tcf_protoost" **htb_find_tcfost"(struct Qdiscost" *schost", unsigned long argost")
1485ost"{
1486ost"        struct htb_schedost" *qost" = "a href="+code=qdisc_priv" class="sref">qdisc_privost"("a href="+code=sch" class="sref">schost");
1487ost"        struct htb_classost" *clost" = (struct htb_classost" *)argost";
1488ost"        struct tcf_protoost" **flost" = "a href="+code=cl" class="sref">clost" ? &"a href="+code=cl" class="sref">clost"->filter_listost" : &"a href="+code=q" class="sref">qo/t"->filter_listost";
1489ost"
1490ost"        return flost";
1491ost"}
1492ost"
1493ost"static unsigned long htb_bind_filterost"(struct Qdiscost" *schost", unsigned long parentost",
1494ost"                                     "a href="+code=u32" class="sref">u32ost" "a href="+code=classid" class="sref">classidost")
1495ost"{
1496ost"        struct htb_classost" *clost" = htb_findost"("a href="+code=classid" class="sref">classidost", "a href="+code=sch" class="sref">schost");
1497ost"
1498ost"        " value="">
	comment">/*if (cl && !cl->level) return 0;
1499ost"< value="">
	comment">         * The line above used to be there to prevent attaching filter> to
1500ost"< value="">
	comment">         * leaves. But at least tc_index filter uses this just to getue="">
1501ost"< value="">
	comment">         * for other reasons so that we have to allow for it.
1502ost"< value="">
	comment">         * ----
1503ost"< value="">
	comment">         * 19.6.2002 As Werner explained it is ok - bind filter is just
1504ost"< value="">
	comment">         * another way to "lock" the e=""> - unlike "get" this lock can
1505ost"< value="">
	comment">         * be broken by e=""> during destroy IIUC.
1506ost"< value="">
	comment">         */
1507ost"        if ("a href="+code=cl" class="sref">clost")
1508ost"                "a href="+code=cl" class="sref">clost"->filter_cntost"++;
1509ost"        return (unsigned long)clost";
1510ost"}
1511ost"
1512ost"static void htb_unbind_filterost"(struct Qdiscost" *schost", unsigned long argost")
1513ost"{
1514ost"        struct htb_classost" *clost" = (struct htb_classost" *)argost";
1515ost"
1516ost"        if ("a href="+code=cl" class="sref">clost")
1517ost"                "a href="+code=cl" class="sref">clost"->filter_cntost"--;
1518ost"}
1519ost"
1520ost"static void htb_walkost"(struct Qdiscost" *schost", struct qdisc_walkerost" *argost")
1521ost"{
1522ost"        struct htb_schedost" *qost" = "a href="+code=qdisc_priv" class="sref">qdisc_privost"("a href="+code=sch" class="sref">schost");
1523ost"        struct htb_classost" *clost";
1524ost"        struct hlist_nodeost" *nost";
1525ost"        unsigned int iost";
1526ost"
1527ost"        if ("a href="+code=arg" class="sref">argost"->stopost")
1528ost"                return;
1529ost"
1530ost"        for ("a href="+code=i" class="sref">iost" = 0; iost" < "a href="+code=q" class="sref">qo/t"->clhashost"."a href="+code=hashsize" class="sref">hashsizeost"; iost"++) {
1531ost"                hlist_for_each_entryost"("a href="+code=cl" class="sref">clost", "a href="+code=l" class="sref">nost", &"a href="+code=q" class="sref">qo/t"->clhashost"."a href="+code=hash" class="sref">hashost"[iost"], "a href="+code=commol" class="sref">commolost"."a href="+code=hnode" class="sref">hnodeost") {
1532ost"                        if (argost"->countost" < "a href="+code=arg" class="sref">argost"->skipost") {
1533ost"                                argost"->countost"++;
1534ost"                                continue;
1535ost"                        }
1536ost"                        if (argost"->fnost"("a href="+code=sch" class="sref">schost", (unsigned long)clost", "a href="+code=arg" class="sref">argost") < 0) {
1537ost"                                "a href="+code=arg" class="sref">argost"->stopost" = 1;
1538ost"                                return;
1539ost"                        }
1540ost"                        "a href="+code=arg" class="sref">argost"->countost"++;
1541ost"                }
1542ost"        }
1543ost"}
1544ost"
1545ost"static const struct Qdisc_class_opsost" "a href="+code=htb_class_ops" class="sref">htb_class_opsost" = {
1546ost"        ."a href="+code=graft" class="sref">graftost"          =       "a href="+code=htb_graft" class="sref">htb_graftost",
1547ost"        ."a href="+code=leaf" class="sref">leafost"           =       "a href="+code=htb_leaf" class="sref">htb_leafost",
1548ost"        ."a href="+code=qlen_notify" class="sref">qlen_notifyost"    =       "a href="+code=htb_qlen_notify" class="sref">htb_qlen_notifyost",
1549ost"        ."a href="+code=get" class="sref">getost"            =       "a href="+code=htb_get" class="sref">htb_getost",
1550ost"        ."a href="+code=put" class="sref">putost"            =       "a href="+code=htb_put" class="sref">htb_putost",
1551ost"        ."a href="+code=change" class="sref">changeost"         =       "a href="+code=htb_change_class" class="sref">htb_change_classost",
1552ost"        ."a href="+code=delete" class="sref">deleteost"         =       "a href="+code=htb_delete" class="sref">htb_deleteost",
1553ost"        ."a href="+code=walk" class="sref">walkost"           =       "a href="+code=htb_walk" class="sref">htb_walkost",
1554ost"        ."a href="+code=tcf_chail" class="sref">tcf_chailost"      =       "a href="+code=htb_find_tcf" class="sref">htb_find_tcfost",
1555ost"        ."a href="+code=bind_tcf" class="sref">bind_tcfost"       =       "a href="+code=htb_bind_filter" class="sref">htb_bind_filterost",
1556ost"        ."a href="+code=unbind_tcf" class="sref">unbind_tcfost"     =       "a href="+code=htb_unbind_filter" class="sref">htb_unbind_filterost",
1557ost"        ."a href="+code=dump" class="sref">dumpost"           =       "a href="+code=htb_dump_class" class="sref">htb_dump_classost",
1558ost"        ."a href="+code=dump_stats" class="sref">dump_statsost"     =       "a href="+code=htb_dump_class_stats" class="sref">htb_dump_class_statsost",
1559ost"};
1560ost"
1561ost"static struct Qdisc_opsost" "a href="+code=htb_qdisc_ops" class="sref">htb_qdisc_opsost" "a href="+code=__read_mostly" class="sref">__read_mostlyost" = {
1562ost"        ."a href="+code=cl_ops" class="sref">cl_opsost"         =       &"a href="+code=htb_class_ops" class="sref">htb_class_opsost",
1563ost"        ."a href="+code=id" class="sref">idost"             =       " value="">
	string">"htb",
1564ost"        ."a href="+code=priv_size" class="sref">priv_sizeost"      =       sizeof(struct htb_schedost"),
1565ost"        ."a href="+code=enqueue" class="sref">enqueueost"        =       "a href="+code=htb_enqueue" class="sref">htb_enqueueost",
1566ost"        ."a href="+code=dequeue" class="sref">dequeueost"        =       "a href="+code=htb_dequeue" class="sref">htb_dequeueost",
1567ost"        ."a href="+code=peek" class="sref">peekost"           =       "a href="+code=qdisc_peek_dequeued" class="sref">qdisc_peek_dequeuedost",
1568ost"        ."a href="+code=drop" class="sref">dropost"           =       "a href="+code=htb_drop" class="sref">htb_dropost",
1569ost"        ."a href="+code=init" class="sref">initost"           =       "a href="+code=htb_init" class="sref">htb_initost",
1570ost"        ."a href="+code=reset" class="sref">resetost"          =       "a href="+code=htb_reset" class="sref">htb_resetost",
1571ost"        ."a href="+code=destroy" class="sref">destroyost"        =       "a href="+code=htb_destroy" class="sref">htb_destroyost",
1572ost"        ."a href="+code=dump" class="sref">dumpost"           =       "a href="+code=htb_dump" class="sref">htb_dumpost",
1573ost"        ."a href="+code=owner" class="sref">ownerost"          =       "a href="+code=THIS_MODULE" class="sref">THIS_MODULEost",
1574ost"};
1575ost"
1576ost"static int __initost" "a href="+code=htb_module_init" class="sref">htb_module_initost"(void)
1577ost"{
1578ost"        return register_qdiscost"(&"a href="+code=htb_qdisc_ops" class="sref">htb_qdisc_opsost");
1579ost"}
1580ost"static void __exitost" "a href="+code=htb_module_exit" class="sref">htb_module_exitost"(void)
1581ost"{
1582ost"        "a href="+code=unregister_qdisc" class="sref">unregister_qdiscost"(&"a href="+code=htb_qdisc_ops" class="sref">htb_qdisc_opsost");
1583ost"}
1584ost"
1585ost""a href="+code=module_init" class="sref">module_initost"("a href="+code=htb_module_init" class="sref">htb_module_initost")
1586ost"module_exitost"("a href="+code=htb_module_exit" class="sref">htb_module_exitost")
1587ost""a href="+code=MODULE_LICENSE" class="sref">MODULE_LICENSEost"(" value="">
	string">"GPL");
1588ost"


lxr.linux.no kindly hosted by Redpill Linpro ASost", provider of Linux consulting and operations services since 1995.