2 * net/sched/sch_red.c Random Early Detection queue.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
12 * J Hadi Salim 980914: computation fixes
13 * Alexey Makarenko <makar@phoenix.kharkov.ua> 990814: qave on idle link was calculated incorrectly.
14 * J Hadi Salim 980816: ECN support
17 #include <linux/module.h>
18 #include <linux/types.h>
19 #include <linux/kernel.h>
20 #include <linux/skbuff.h>
21 #include <net/pkt_sched.h>
22 #include <net/inet_ecn.h>
26 /* Parameters, settable by user:
27 -----------------------------
29 limit - bytes (must be > qth_max + burst)
31 Hard limit on queue length, should be chosen >qth_max
32 to allow packet bursts. This parameter does not
33 affect the algorithms behaviour and can be chosen
34 arbitrarily high (well, less than ram size)
35 Really, this limit will never be reached
36 if RED works correctly.
39 struct red_sched_data
{
40 u32 limit
; /* HARD maximal queue length */
42 struct timer_list adapt_timer
;
43 struct red_parms parms
;
45 struct red_stats stats
;
49 static inline int red_use_ecn(struct red_sched_data
*q
)
51 return q
->flags
& TC_RED_ECN
;
54 static inline int red_use_harddrop(struct red_sched_data
*q
)
56 return q
->flags
& TC_RED_HARDDROP
;
59 static int red_enqueue(struct sk_buff
*skb
, struct Qdisc
*sch
)
61 struct red_sched_data
*q
= qdisc_priv(sch
);
62 struct Qdisc
*child
= q
->qdisc
;
65 q
->vars
.qavg
= red_calc_qavg(&q
->parms
,
67 child
->qstats
.backlog
);
69 if (red_is_idling(&q
->vars
))
70 red_end_of_idle_period(&q
->vars
);
72 switch (red_action(&q
->parms
, &q
->vars
, q
->vars
.qavg
)) {
77 qdisc_qstats_overlimit(sch
);
78 if (!red_use_ecn(q
) || !INET_ECN_set_ce(skb
)) {
87 qdisc_qstats_overlimit(sch
);
88 if (red_use_harddrop(q
) || !red_use_ecn(q
) ||
89 !INET_ECN_set_ce(skb
)) {
90 q
->stats
.forced_drop
++;
94 q
->stats
.forced_mark
++;
98 ret
= qdisc_enqueue(skb
, child
);
99 if (likely(ret
== NET_XMIT_SUCCESS
)) {
100 qdisc_qstats_backlog_inc(sch
, skb
);
102 } else if (net_xmit_drop_count(ret
)) {
104 qdisc_qstats_drop(sch
);
109 qdisc_drop(skb
, sch
);
113 static struct sk_buff
*red_dequeue(struct Qdisc
*sch
)
116 struct red_sched_data
*q
= qdisc_priv(sch
);
117 struct Qdisc
*child
= q
->qdisc
;
119 skb
= child
->dequeue(child
);
121 qdisc_bstats_update(sch
, skb
);
122 qdisc_qstats_backlog_dec(sch
, skb
);
125 if (!red_is_idling(&q
->vars
))
126 red_start_of_idle_period(&q
->vars
);
131 static struct sk_buff
*red_peek(struct Qdisc
*sch
)
133 struct red_sched_data
*q
= qdisc_priv(sch
);
134 struct Qdisc
*child
= q
->qdisc
;
136 return child
->ops
->peek(child
);
139 static void red_reset(struct Qdisc
*sch
)
141 struct red_sched_data
*q
= qdisc_priv(sch
);
143 qdisc_reset(q
->qdisc
);
144 sch
->qstats
.backlog
= 0;
146 red_restart(&q
->vars
);
149 static void red_destroy(struct Qdisc
*sch
)
151 struct red_sched_data
*q
= qdisc_priv(sch
);
153 del_timer_sync(&q
->adapt_timer
);
154 qdisc_destroy(q
->qdisc
);
157 static const struct nla_policy red_policy
[TCA_RED_MAX
+ 1] = {
158 [TCA_RED_PARMS
] = { .len
= sizeof(struct tc_red_qopt
) },
159 [TCA_RED_STAB
] = { .len
= RED_STAB_SIZE
},
160 [TCA_RED_MAX_P
] = { .type
= NLA_U32
},
163 static int red_change(struct Qdisc
*sch
, struct nlattr
*opt
)
165 struct red_sched_data
*q
= qdisc_priv(sch
);
166 struct nlattr
*tb
[TCA_RED_MAX
+ 1];
167 struct tc_red_qopt
*ctl
;
168 struct Qdisc
*child
= NULL
;
175 err
= nla_parse_nested(tb
, TCA_RED_MAX
, opt
, red_policy
);
179 if (tb
[TCA_RED_PARMS
] == NULL
||
180 tb
[TCA_RED_STAB
] == NULL
)
183 max_P
= tb
[TCA_RED_MAX_P
] ? nla_get_u32(tb
[TCA_RED_MAX_P
]) : 0;
185 ctl
= nla_data(tb
[TCA_RED_PARMS
]);
187 if (ctl
->limit
> 0) {
188 child
= fifo_create_dflt(sch
, &bfifo_qdisc_ops
, ctl
->limit
);
190 return PTR_ERR(child
);
194 q
->flags
= ctl
->flags
;
195 q
->limit
= ctl
->limit
;
197 qdisc_tree_reduce_backlog(q
->qdisc
, q
->qdisc
->q
.qlen
,
198 q
->qdisc
->qstats
.backlog
);
199 qdisc_destroy(q
->qdisc
);
203 red_set_parms(&q
->parms
,
204 ctl
->qth_min
, ctl
->qth_max
, ctl
->Wlog
,
205 ctl
->Plog
, ctl
->Scell_log
,
206 nla_data(tb
[TCA_RED_STAB
]),
208 red_set_vars(&q
->vars
);
210 del_timer(&q
->adapt_timer
);
211 if (ctl
->flags
& TC_RED_ADAPTATIVE
)
212 mod_timer(&q
->adapt_timer
, jiffies
+ HZ
/2);
214 if (!q
->qdisc
->q
.qlen
)
215 red_start_of_idle_period(&q
->vars
);
217 sch_tree_unlock(sch
);
221 static inline void red_adaptative_timer(unsigned long arg
)
223 struct Qdisc
*sch
= (struct Qdisc
*)arg
;
224 struct red_sched_data
*q
= qdisc_priv(sch
);
225 spinlock_t
*root_lock
= qdisc_lock(qdisc_root_sleeping(sch
));
227 spin_lock(root_lock
);
228 red_adaptative_algo(&q
->parms
, &q
->vars
);
229 mod_timer(&q
->adapt_timer
, jiffies
+ HZ
/2);
230 spin_unlock(root_lock
);
233 static int red_init(struct Qdisc
*sch
, struct nlattr
*opt
)
235 struct red_sched_data
*q
= qdisc_priv(sch
);
237 q
->qdisc
= &noop_qdisc
;
238 setup_timer(&q
->adapt_timer
, red_adaptative_timer
, (unsigned long)sch
);
239 return red_change(sch
, opt
);
242 static int red_dump(struct Qdisc
*sch
, struct sk_buff
*skb
)
244 struct red_sched_data
*q
= qdisc_priv(sch
);
245 struct nlattr
*opts
= NULL
;
246 struct tc_red_qopt opt
= {
249 .qth_min
= q
->parms
.qth_min
>> q
->parms
.Wlog
,
250 .qth_max
= q
->parms
.qth_max
>> q
->parms
.Wlog
,
251 .Wlog
= q
->parms
.Wlog
,
252 .Plog
= q
->parms
.Plog
,
253 .Scell_log
= q
->parms
.Scell_log
,
256 sch
->qstats
.backlog
= q
->qdisc
->qstats
.backlog
;
257 opts
= nla_nest_start(skb
, TCA_OPTIONS
);
259 goto nla_put_failure
;
260 if (nla_put(skb
, TCA_RED_PARMS
, sizeof(opt
), &opt
) ||
261 nla_put_u32(skb
, TCA_RED_MAX_P
, q
->parms
.max_P
))
262 goto nla_put_failure
;
263 return nla_nest_end(skb
, opts
);
266 nla_nest_cancel(skb
, opts
);
270 static int red_dump_stats(struct Qdisc
*sch
, struct gnet_dump
*d
)
272 struct red_sched_data
*q
= qdisc_priv(sch
);
273 struct tc_red_xstats st
= {
274 .early
= q
->stats
.prob_drop
+ q
->stats
.forced_drop
,
275 .pdrop
= q
->stats
.pdrop
,
276 .other
= q
->stats
.other
,
277 .marked
= q
->stats
.prob_mark
+ q
->stats
.forced_mark
,
280 return gnet_stats_copy_app(d
, &st
, sizeof(st
));
283 static int red_dump_class(struct Qdisc
*sch
, unsigned long cl
,
284 struct sk_buff
*skb
, struct tcmsg
*tcm
)
286 struct red_sched_data
*q
= qdisc_priv(sch
);
288 tcm
->tcm_handle
|= TC_H_MIN(1);
289 tcm
->tcm_info
= q
->qdisc
->handle
;
293 static int red_graft(struct Qdisc
*sch
, unsigned long arg
, struct Qdisc
*new,
296 struct red_sched_data
*q
= qdisc_priv(sch
);
301 *old
= qdisc_replace(sch
, new, &q
->qdisc
);
305 static struct Qdisc
*red_leaf(struct Qdisc
*sch
, unsigned long arg
)
307 struct red_sched_data
*q
= qdisc_priv(sch
);
311 static unsigned long red_get(struct Qdisc
*sch
, u32 classid
)
316 static void red_put(struct Qdisc
*sch
, unsigned long arg
)
320 static void red_walk(struct Qdisc
*sch
, struct qdisc_walker
*walker
)
323 if (walker
->count
>= walker
->skip
)
324 if (walker
->fn(sch
, 1, walker
) < 0) {
332 static const struct Qdisc_class_ops red_class_ops
= {
338 .dump
= red_dump_class
,
341 static struct Qdisc_ops red_qdisc_ops __read_mostly
= {
343 .priv_size
= sizeof(struct red_sched_data
),
344 .cl_ops
= &red_class_ops
,
345 .enqueue
= red_enqueue
,
346 .dequeue
= red_dequeue
,
350 .destroy
= red_destroy
,
351 .change
= red_change
,
353 .dump_stats
= red_dump_stats
,
354 .owner
= THIS_MODULE
,
357 static int __init
red_module_init(void)
359 return register_qdisc(&red_qdisc_ops
);
362 static void __exit
red_module_exit(void)
364 unregister_qdisc(&red_qdisc_ops
);
367 module_init(red_module_init
)
368 module_exit(red_module_exit
)
370 MODULE_LICENSE("GPL");