1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * net/sched/sch_gred.c Generic Random Early Detection queue.
5 * Authors: J Hadi Salim (hadi@cyberus.ca) 1998-2002
7 * 991129: - Bug fix with grio mode
8 * - a better sing. AvgQ mode with Grio(WRED)
9 * - A finer grained VQ dequeue based on sugestion
13 * For all the glorious comments look at include/net/red.h
16 #include <linux/slab.h>
17 #include <linux/module.h>
18 #include <linux/types.h>
19 #include <linux/kernel.h>
20 #include <linux/skbuff.h>
21 #include <net/pkt_cls.h>
22 #include <net/pkt_sched.h>
25 #define GRED_DEF_PRIO (MAX_DPs / 2)
26 #define GRED_VQ_MASK (MAX_DPs - 1)
28 #define GRED_VQ_RED_FLAGS (TC_RED_ECN | TC_RED_HARDDROP)
30 struct gred_sched_data
;
33 struct gred_sched_data
{
34 u32 limit
; /* HARD maximal queue length */
35 u32 DP
; /* the drop parameters */
36 u32 red_flags
; /* virtualQ version of red_flags */
37 u64 bytesin
; /* bytes seen on virtualQ so far*/
38 u32 packetsin
; /* packets seen on virtualQ so far*/
39 u32 backlog
; /* bytes on the virtualQ */
40 u8 prio
; /* the prio of this vq */
42 struct red_parms parms
;
44 struct red_stats stats
;
53 struct gred_sched_data
*tab
[MAX_DPs
];
58 struct red_vars wred_set
;
61 static inline int gred_wred_mode(struct gred_sched
*table
)
63 return test_bit(GRED_WRED_MODE
, &table
->flags
);
66 static inline void gred_enable_wred_mode(struct gred_sched
*table
)
68 __set_bit(GRED_WRED_MODE
, &table
->flags
);
71 static inline void gred_disable_wred_mode(struct gred_sched
*table
)
73 __clear_bit(GRED_WRED_MODE
, &table
->flags
);
76 static inline int gred_rio_mode(struct gred_sched
*table
)
78 return test_bit(GRED_RIO_MODE
, &table
->flags
);
81 static inline void gred_enable_rio_mode(struct gred_sched
*table
)
83 __set_bit(GRED_RIO_MODE
, &table
->flags
);
86 static inline void gred_disable_rio_mode(struct gred_sched
*table
)
88 __clear_bit(GRED_RIO_MODE
, &table
->flags
);
91 static inline int gred_wred_mode_check(struct Qdisc
*sch
)
93 struct gred_sched
*table
= qdisc_priv(sch
);
96 /* Really ugly O(n^2) but shouldn't be necessary too frequent. */
97 for (i
= 0; i
< table
->DPs
; i
++) {
98 struct gred_sched_data
*q
= table
->tab
[i
];
104 for (n
= i
+ 1; n
< table
->DPs
; n
++)
105 if (table
->tab
[n
] && table
->tab
[n
]->prio
== q
->prio
)
112 static inline unsigned int gred_backlog(struct gred_sched
*table
,
113 struct gred_sched_data
*q
,
116 if (gred_wred_mode(table
))
117 return sch
->qstats
.backlog
;
122 static inline u16
tc_index_to_dp(struct sk_buff
*skb
)
124 return skb
->tc_index
& GRED_VQ_MASK
;
127 static inline void gred_load_wred_set(const struct gred_sched
*table
,
128 struct gred_sched_data
*q
)
130 q
->vars
.qavg
= table
->wred_set
.qavg
;
131 q
->vars
.qidlestart
= table
->wred_set
.qidlestart
;
134 static inline void gred_store_wred_set(struct gred_sched
*table
,
135 struct gred_sched_data
*q
)
137 table
->wred_set
.qavg
= q
->vars
.qavg
;
138 table
->wred_set
.qidlestart
= q
->vars
.qidlestart
;
141 static int gred_use_ecn(struct gred_sched_data
*q
)
143 return q
->red_flags
& TC_RED_ECN
;
146 static int gred_use_harddrop(struct gred_sched_data
*q
)
148 return q
->red_flags
& TC_RED_HARDDROP
;
151 static bool gred_per_vq_red_flags_used(struct gred_sched
*table
)
155 /* Local per-vq flags couldn't have been set unless global are 0 */
156 if (table
->red_flags
)
158 for (i
= 0; i
< MAX_DPs
; i
++)
159 if (table
->tab
[i
] && table
->tab
[i
]->red_flags
)
164 static int gred_enqueue(struct sk_buff
*skb
, struct Qdisc
*sch
,
165 struct sk_buff
**to_free
)
167 struct gred_sched_data
*q
= NULL
;
168 struct gred_sched
*t
= qdisc_priv(sch
);
169 unsigned long qavg
= 0;
170 u16 dp
= tc_index_to_dp(skb
);
172 if (dp
>= t
->DPs
|| (q
= t
->tab
[dp
]) == NULL
) {
177 /* Pass through packets not assigned to a DP
178 * if no default DP has been configured. This
179 * allows for DP flows to be left untouched.
181 if (likely(sch
->qstats
.backlog
+ qdisc_pkt_len(skb
) <=
183 return qdisc_enqueue_tail(skb
, sch
);
188 /* fix tc_index? --could be controversial but needed for
190 skb
->tc_index
= (skb
->tc_index
& ~GRED_VQ_MASK
) | dp
;
193 /* sum up all the qaves of prios < ours to get the new qave */
194 if (!gred_wred_mode(t
) && gred_rio_mode(t
)) {
197 for (i
= 0; i
< t
->DPs
; i
++) {
198 if (t
->tab
[i
] && t
->tab
[i
]->prio
< q
->prio
&&
199 !red_is_idling(&t
->tab
[i
]->vars
))
200 qavg
+= t
->tab
[i
]->vars
.qavg
;
206 q
->bytesin
+= qdisc_pkt_len(skb
);
208 if (gred_wred_mode(t
))
209 gred_load_wred_set(t
, q
);
211 q
->vars
.qavg
= red_calc_qavg(&q
->parms
,
213 gred_backlog(t
, q
, sch
));
215 if (red_is_idling(&q
->vars
))
216 red_end_of_idle_period(&q
->vars
);
218 if (gred_wred_mode(t
))
219 gred_store_wred_set(t
, q
);
221 switch (red_action(&q
->parms
, &q
->vars
, q
->vars
.qavg
+ qavg
)) {
226 qdisc_qstats_overlimit(sch
);
227 if (!gred_use_ecn(q
) || !INET_ECN_set_ce(skb
)) {
228 q
->stats
.prob_drop
++;
229 goto congestion_drop
;
232 q
->stats
.prob_mark
++;
236 qdisc_qstats_overlimit(sch
);
237 if (gred_use_harddrop(q
) || !gred_use_ecn(q
) ||
238 !INET_ECN_set_ce(skb
)) {
239 q
->stats
.forced_drop
++;
240 goto congestion_drop
;
242 q
->stats
.forced_mark
++;
246 if (gred_backlog(t
, q
, sch
) + qdisc_pkt_len(skb
) <= q
->limit
) {
247 q
->backlog
+= qdisc_pkt_len(skb
);
248 return qdisc_enqueue_tail(skb
, sch
);
253 return qdisc_drop(skb
, sch
, to_free
);
256 qdisc_drop(skb
, sch
, to_free
);
260 static struct sk_buff
*gred_dequeue(struct Qdisc
*sch
)
263 struct gred_sched
*t
= qdisc_priv(sch
);
265 skb
= qdisc_dequeue_head(sch
);
268 struct gred_sched_data
*q
;
269 u16 dp
= tc_index_to_dp(skb
);
271 if (dp
>= t
->DPs
|| (q
= t
->tab
[dp
]) == NULL
) {
272 net_warn_ratelimited("GRED: Unable to relocate VQ 0x%x after dequeue, screwing up backlog\n",
273 tc_index_to_dp(skb
));
275 q
->backlog
-= qdisc_pkt_len(skb
);
277 if (gred_wred_mode(t
)) {
278 if (!sch
->qstats
.backlog
)
279 red_start_of_idle_period(&t
->wred_set
);
282 red_start_of_idle_period(&q
->vars
);
292 static void gred_reset(struct Qdisc
*sch
)
295 struct gred_sched
*t
= qdisc_priv(sch
);
297 qdisc_reset_queue(sch
);
299 for (i
= 0; i
< t
->DPs
; i
++) {
300 struct gred_sched_data
*q
= t
->tab
[i
];
305 red_restart(&q
->vars
);
310 static void gred_offload(struct Qdisc
*sch
, enum tc_gred_command command
)
312 struct gred_sched
*table
= qdisc_priv(sch
);
313 struct net_device
*dev
= qdisc_dev(sch
);
314 struct tc_gred_qopt_offload opt
= {
316 .handle
= sch
->handle
,
317 .parent
= sch
->parent
,
320 if (!tc_can_offload(dev
) || !dev
->netdev_ops
->ndo_setup_tc
)
323 if (command
== TC_GRED_REPLACE
) {
326 opt
.set
.grio_on
= gred_rio_mode(table
);
327 opt
.set
.wred_on
= gred_wred_mode(table
);
328 opt
.set
.dp_cnt
= table
->DPs
;
329 opt
.set
.dp_def
= table
->def
;
331 for (i
= 0; i
< table
->DPs
; i
++) {
332 struct gred_sched_data
*q
= table
->tab
[i
];
336 opt
.set
.tab
[i
].present
= true;
337 opt
.set
.tab
[i
].limit
= q
->limit
;
338 opt
.set
.tab
[i
].prio
= q
->prio
;
339 opt
.set
.tab
[i
].min
= q
->parms
.qth_min
>> q
->parms
.Wlog
;
340 opt
.set
.tab
[i
].max
= q
->parms
.qth_max
>> q
->parms
.Wlog
;
341 opt
.set
.tab
[i
].is_ecn
= gred_use_ecn(q
);
342 opt
.set
.tab
[i
].is_harddrop
= gred_use_harddrop(q
);
343 opt
.set
.tab
[i
].probability
= q
->parms
.max_P
;
344 opt
.set
.tab
[i
].backlog
= &q
->backlog
;
346 opt
.set
.qstats
= &sch
->qstats
;
349 dev
->netdev_ops
->ndo_setup_tc(dev
, TC_SETUP_QDISC_GRED
, &opt
);
352 static int gred_offload_dump_stats(struct Qdisc
*sch
)
354 struct gred_sched
*table
= qdisc_priv(sch
);
355 struct tc_gred_qopt_offload
*hw_stats
;
359 hw_stats
= kzalloc(sizeof(*hw_stats
), GFP_KERNEL
);
363 hw_stats
->command
= TC_GRED_STATS
;
364 hw_stats
->handle
= sch
->handle
;
365 hw_stats
->parent
= sch
->parent
;
367 for (i
= 0; i
< MAX_DPs
; i
++)
369 hw_stats
->stats
.xstats
[i
] = &table
->tab
[i
]->stats
;
371 ret
= qdisc_offload_dump_helper(sch
, TC_SETUP_QDISC_GRED
, hw_stats
);
372 /* Even if driver returns failure adjust the stats - in case offload
373 * ended but driver still wants to adjust the values.
375 for (i
= 0; i
< MAX_DPs
; i
++) {
378 table
->tab
[i
]->packetsin
+= hw_stats
->stats
.bstats
[i
].packets
;
379 table
->tab
[i
]->bytesin
+= hw_stats
->stats
.bstats
[i
].bytes
;
380 table
->tab
[i
]->backlog
+= hw_stats
->stats
.qstats
[i
].backlog
;
382 _bstats_update(&sch
->bstats
,
383 hw_stats
->stats
.bstats
[i
].bytes
,
384 hw_stats
->stats
.bstats
[i
].packets
);
385 sch
->qstats
.qlen
+= hw_stats
->stats
.qstats
[i
].qlen
;
386 sch
->qstats
.backlog
+= hw_stats
->stats
.qstats
[i
].backlog
;
387 sch
->qstats
.drops
+= hw_stats
->stats
.qstats
[i
].drops
;
388 sch
->qstats
.requeues
+= hw_stats
->stats
.qstats
[i
].requeues
;
389 sch
->qstats
.overlimits
+= hw_stats
->stats
.qstats
[i
].overlimits
;
396 static inline void gred_destroy_vq(struct gred_sched_data
*q
)
401 static int gred_change_table_def(struct Qdisc
*sch
, struct nlattr
*dps
,
402 struct netlink_ext_ack
*extack
)
404 struct gred_sched
*table
= qdisc_priv(sch
);
405 struct tc_gred_sopt
*sopt
;
406 bool red_flags_changed
;
412 sopt
= nla_data(dps
);
414 if (sopt
->DPs
> MAX_DPs
) {
415 NL_SET_ERR_MSG_MOD(extack
, "number of virtual queues too high");
418 if (sopt
->DPs
== 0) {
419 NL_SET_ERR_MSG_MOD(extack
,
420 "number of virtual queues can't be 0");
423 if (sopt
->def_DP
>= sopt
->DPs
) {
424 NL_SET_ERR_MSG_MOD(extack
, "default virtual queue above virtual queue count");
427 if (sopt
->flags
&& gred_per_vq_red_flags_used(table
)) {
428 NL_SET_ERR_MSG_MOD(extack
, "can't set per-Qdisc RED flags when per-virtual queue flags are used");
433 table
->DPs
= sopt
->DPs
;
434 table
->def
= sopt
->def_DP
;
435 red_flags_changed
= table
->red_flags
!= sopt
->flags
;
436 table
->red_flags
= sopt
->flags
;
439 * Every entry point to GRED is synchronized with the above code
440 * and the DP is checked against DPs, i.e. shadowed VQs can no
441 * longer be found so we can unlock right here.
443 sch_tree_unlock(sch
);
446 gred_enable_rio_mode(table
);
447 gred_disable_wred_mode(table
);
448 if (gred_wred_mode_check(sch
))
449 gred_enable_wred_mode(table
);
451 gred_disable_rio_mode(table
);
452 gred_disable_wred_mode(table
);
455 if (red_flags_changed
)
456 for (i
= 0; i
< table
->DPs
; i
++)
458 table
->tab
[i
]->red_flags
=
459 table
->red_flags
& GRED_VQ_RED_FLAGS
;
461 for (i
= table
->DPs
; i
< MAX_DPs
; i
++) {
463 pr_warn("GRED: Warning: Destroying shadowed VQ 0x%x\n",
465 gred_destroy_vq(table
->tab
[i
]);
466 table
->tab
[i
] = NULL
;
470 gred_offload(sch
, TC_GRED_REPLACE
);
474 static inline int gred_change_vq(struct Qdisc
*sch
, int dp
,
475 struct tc_gred_qopt
*ctl
, int prio
,
477 struct gred_sched_data
**prealloc
,
478 struct netlink_ext_ack
*extack
)
480 struct gred_sched
*table
= qdisc_priv(sch
);
481 struct gred_sched_data
*q
= table
->tab
[dp
];
483 if (!red_check_params(ctl
->qth_min
, ctl
->qth_max
, ctl
->Wlog
)) {
484 NL_SET_ERR_MSG_MOD(extack
, "invalid RED parameters");
489 table
->tab
[dp
] = q
= *prealloc
;
493 q
->red_flags
= table
->red_flags
& GRED_VQ_RED_FLAGS
;
498 if (ctl
->limit
> sch
->limit
)
499 q
->limit
= sch
->limit
;
501 q
->limit
= ctl
->limit
;
504 red_end_of_idle_period(&q
->vars
);
506 red_set_parms(&q
->parms
,
507 ctl
->qth_min
, ctl
->qth_max
, ctl
->Wlog
, ctl
->Plog
,
508 ctl
->Scell_log
, stab
, max_P
);
509 red_set_vars(&q
->vars
);
513 static const struct nla_policy gred_vq_policy
[TCA_GRED_VQ_MAX
+ 1] = {
514 [TCA_GRED_VQ_DP
] = { .type
= NLA_U32
},
515 [TCA_GRED_VQ_FLAGS
] = { .type
= NLA_U32
},
518 static const struct nla_policy gred_vqe_policy
[TCA_GRED_VQ_ENTRY_MAX
+ 1] = {
519 [TCA_GRED_VQ_ENTRY
] = { .type
= NLA_NESTED
},
522 static const struct nla_policy gred_policy
[TCA_GRED_MAX
+ 1] = {
523 [TCA_GRED_PARMS
] = { .len
= sizeof(struct tc_gred_qopt
) },
524 [TCA_GRED_STAB
] = { .len
= 256 },
525 [TCA_GRED_DPS
] = { .len
= sizeof(struct tc_gred_sopt
) },
526 [TCA_GRED_MAX_P
] = { .type
= NLA_U32
},
527 [TCA_GRED_LIMIT
] = { .type
= NLA_U32
},
528 [TCA_GRED_VQ_LIST
] = { .type
= NLA_NESTED
},
531 static void gred_vq_apply(struct gred_sched
*table
, const struct nlattr
*entry
)
533 struct nlattr
*tb
[TCA_GRED_VQ_MAX
+ 1];
536 nla_parse_nested_deprecated(tb
, TCA_GRED_VQ_MAX
, entry
,
537 gred_vq_policy
, NULL
);
539 dp
= nla_get_u32(tb
[TCA_GRED_VQ_DP
]);
541 if (tb
[TCA_GRED_VQ_FLAGS
])
542 table
->tab
[dp
]->red_flags
= nla_get_u32(tb
[TCA_GRED_VQ_FLAGS
]);
545 static void gred_vqs_apply(struct gred_sched
*table
, struct nlattr
*vqs
)
547 const struct nlattr
*attr
;
550 nla_for_each_nested(attr
, vqs
, rem
) {
551 switch (nla_type(attr
)) {
552 case TCA_GRED_VQ_ENTRY
:
553 gred_vq_apply(table
, attr
);
559 static int gred_vq_validate(struct gred_sched
*table
, u32 cdp
,
560 const struct nlattr
*entry
,
561 struct netlink_ext_ack
*extack
)
563 struct nlattr
*tb
[TCA_GRED_VQ_MAX
+ 1];
567 err
= nla_parse_nested_deprecated(tb
, TCA_GRED_VQ_MAX
, entry
,
568 gred_vq_policy
, extack
);
572 if (!tb
[TCA_GRED_VQ_DP
]) {
573 NL_SET_ERR_MSG_MOD(extack
, "Virtual queue with no index specified");
576 dp
= nla_get_u32(tb
[TCA_GRED_VQ_DP
]);
577 if (dp
>= table
->DPs
) {
578 NL_SET_ERR_MSG_MOD(extack
, "Virtual queue with index out of bounds");
581 if (dp
!= cdp
&& !table
->tab
[dp
]) {
582 NL_SET_ERR_MSG_MOD(extack
, "Virtual queue not yet instantiated");
586 if (tb
[TCA_GRED_VQ_FLAGS
]) {
587 u32 red_flags
= nla_get_u32(tb
[TCA_GRED_VQ_FLAGS
]);
589 if (table
->red_flags
&& table
->red_flags
!= red_flags
) {
590 NL_SET_ERR_MSG_MOD(extack
, "can't change per-virtual queue RED flags when per-Qdisc flags are used");
593 if (red_flags
& ~GRED_VQ_RED_FLAGS
) {
594 NL_SET_ERR_MSG_MOD(extack
,
595 "invalid RED flags specified");
603 static int gred_vqs_validate(struct gred_sched
*table
, u32 cdp
,
604 struct nlattr
*vqs
, struct netlink_ext_ack
*extack
)
606 const struct nlattr
*attr
;
609 err
= nla_validate_nested_deprecated(vqs
, TCA_GRED_VQ_ENTRY_MAX
,
610 gred_vqe_policy
, extack
);
614 nla_for_each_nested(attr
, vqs
, rem
) {
615 switch (nla_type(attr
)) {
616 case TCA_GRED_VQ_ENTRY
:
617 err
= gred_vq_validate(table
, cdp
, attr
, extack
);
622 NL_SET_ERR_MSG_MOD(extack
, "GRED_VQ_LIST can contain only entry attributes");
628 NL_SET_ERR_MSG_MOD(extack
, "Trailing data after parsing virtual queue list");
635 static int gred_change(struct Qdisc
*sch
, struct nlattr
*opt
,
636 struct netlink_ext_ack
*extack
)
638 struct gred_sched
*table
= qdisc_priv(sch
);
639 struct tc_gred_qopt
*ctl
;
640 struct nlattr
*tb
[TCA_GRED_MAX
+ 1];
641 int err
, prio
= GRED_DEF_PRIO
;
644 struct gred_sched_data
*prealloc
;
649 err
= nla_parse_nested_deprecated(tb
, TCA_GRED_MAX
, opt
, gred_policy
,
654 if (tb
[TCA_GRED_PARMS
] == NULL
&& tb
[TCA_GRED_STAB
] == NULL
) {
655 if (tb
[TCA_GRED_LIMIT
] != NULL
)
656 sch
->limit
= nla_get_u32(tb
[TCA_GRED_LIMIT
]);
657 return gred_change_table_def(sch
, tb
[TCA_GRED_DPS
], extack
);
660 if (tb
[TCA_GRED_PARMS
] == NULL
||
661 tb
[TCA_GRED_STAB
] == NULL
||
662 tb
[TCA_GRED_LIMIT
] != NULL
) {
663 NL_SET_ERR_MSG_MOD(extack
, "can't configure Qdisc and virtual queue at the same time");
667 max_P
= tb
[TCA_GRED_MAX_P
] ? nla_get_u32(tb
[TCA_GRED_MAX_P
]) : 0;
669 ctl
= nla_data(tb
[TCA_GRED_PARMS
]);
670 stab
= nla_data(tb
[TCA_GRED_STAB
]);
672 if (ctl
->DP
>= table
->DPs
) {
673 NL_SET_ERR_MSG_MOD(extack
, "virtual queue index above virtual queue count");
677 if (tb
[TCA_GRED_VQ_LIST
]) {
678 err
= gred_vqs_validate(table
, ctl
->DP
, tb
[TCA_GRED_VQ_LIST
],
684 if (gred_rio_mode(table
)) {
685 if (ctl
->prio
== 0) {
686 int def_prio
= GRED_DEF_PRIO
;
688 if (table
->tab
[table
->def
])
689 def_prio
= table
->tab
[table
->def
]->prio
;
691 printk(KERN_DEBUG
"GRED: DP %u does not have a prio "
692 "setting default to %d\n", ctl
->DP
, def_prio
);
699 prealloc
= kzalloc(sizeof(*prealloc
), GFP_KERNEL
);
702 err
= gred_change_vq(sch
, ctl
->DP
, ctl
, prio
, stab
, max_P
, &prealloc
,
705 goto err_unlock_free
;
707 if (tb
[TCA_GRED_VQ_LIST
])
708 gred_vqs_apply(table
, tb
[TCA_GRED_VQ_LIST
]);
710 if (gred_rio_mode(table
)) {
711 gred_disable_wred_mode(table
);
712 if (gred_wred_mode_check(sch
))
713 gred_enable_wred_mode(table
);
716 sch_tree_unlock(sch
);
719 gred_offload(sch
, TC_GRED_REPLACE
);
723 sch_tree_unlock(sch
);
728 static int gred_init(struct Qdisc
*sch
, struct nlattr
*opt
,
729 struct netlink_ext_ack
*extack
)
731 struct nlattr
*tb
[TCA_GRED_MAX
+ 1];
737 err
= nla_parse_nested_deprecated(tb
, TCA_GRED_MAX
, opt
, gred_policy
,
742 if (tb
[TCA_GRED_PARMS
] || tb
[TCA_GRED_STAB
]) {
743 NL_SET_ERR_MSG_MOD(extack
,
744 "virtual queue configuration can't be specified at initialization time");
748 if (tb
[TCA_GRED_LIMIT
])
749 sch
->limit
= nla_get_u32(tb
[TCA_GRED_LIMIT
]);
751 sch
->limit
= qdisc_dev(sch
)->tx_queue_len
752 * psched_mtu(qdisc_dev(sch
));
754 return gred_change_table_def(sch
, tb
[TCA_GRED_DPS
], extack
);
757 static int gred_dump(struct Qdisc
*sch
, struct sk_buff
*skb
)
759 struct gred_sched
*table
= qdisc_priv(sch
);
760 struct nlattr
*parms
, *vqs
, *opts
= NULL
;
763 struct tc_gred_sopt sopt
= {
765 .def_DP
= table
->def
,
766 .grio
= gred_rio_mode(table
),
767 .flags
= table
->red_flags
,
770 if (gred_offload_dump_stats(sch
))
771 goto nla_put_failure
;
773 opts
= nla_nest_start_noflag(skb
, TCA_OPTIONS
);
775 goto nla_put_failure
;
776 if (nla_put(skb
, TCA_GRED_DPS
, sizeof(sopt
), &sopt
))
777 goto nla_put_failure
;
779 for (i
= 0; i
< MAX_DPs
; i
++) {
780 struct gred_sched_data
*q
= table
->tab
[i
];
782 max_p
[i
] = q
? q
->parms
.max_P
: 0;
784 if (nla_put(skb
, TCA_GRED_MAX_P
, sizeof(max_p
), max_p
))
785 goto nla_put_failure
;
787 if (nla_put_u32(skb
, TCA_GRED_LIMIT
, sch
->limit
))
788 goto nla_put_failure
;
790 /* Old style all-in-one dump of VQs */
791 parms
= nla_nest_start_noflag(skb
, TCA_GRED_PARMS
);
793 goto nla_put_failure
;
795 for (i
= 0; i
< MAX_DPs
; i
++) {
796 struct gred_sched_data
*q
= table
->tab
[i
];
797 struct tc_gred_qopt opt
;
800 memset(&opt
, 0, sizeof(opt
));
803 /* hack -- fix at some point with proper message
804 This is how we indicate to tc that there is no VQ
807 opt
.DP
= MAX_DPs
+ i
;
811 opt
.limit
= q
->limit
;
813 opt
.backlog
= gred_backlog(table
, q
, sch
);
815 opt
.qth_min
= q
->parms
.qth_min
>> q
->parms
.Wlog
;
816 opt
.qth_max
= q
->parms
.qth_max
>> q
->parms
.Wlog
;
817 opt
.Wlog
= q
->parms
.Wlog
;
818 opt
.Plog
= q
->parms
.Plog
;
819 opt
.Scell_log
= q
->parms
.Scell_log
;
820 opt
.other
= q
->stats
.other
;
821 opt
.early
= q
->stats
.prob_drop
;
822 opt
.forced
= q
->stats
.forced_drop
;
823 opt
.pdrop
= q
->stats
.pdrop
;
824 opt
.packets
= q
->packetsin
;
825 opt
.bytesin
= q
->bytesin
;
827 if (gred_wred_mode(table
))
828 gred_load_wred_set(table
, q
);
830 qavg
= red_calc_qavg(&q
->parms
, &q
->vars
,
831 q
->vars
.qavg
>> q
->parms
.Wlog
);
832 opt
.qave
= qavg
>> q
->parms
.Wlog
;
835 if (nla_append(skb
, sizeof(opt
), &opt
) < 0)
836 goto nla_put_failure
;
839 nla_nest_end(skb
, parms
);
841 /* Dump the VQs again, in more structured way */
842 vqs
= nla_nest_start_noflag(skb
, TCA_GRED_VQ_LIST
);
844 goto nla_put_failure
;
846 for (i
= 0; i
< MAX_DPs
; i
++) {
847 struct gred_sched_data
*q
= table
->tab
[i
];
853 vq
= nla_nest_start_noflag(skb
, TCA_GRED_VQ_ENTRY
);
855 goto nla_put_failure
;
857 if (nla_put_u32(skb
, TCA_GRED_VQ_DP
, q
->DP
))
858 goto nla_put_failure
;
860 if (nla_put_u32(skb
, TCA_GRED_VQ_FLAGS
, q
->red_flags
))
861 goto nla_put_failure
;
864 if (nla_put_u64_64bit(skb
, TCA_GRED_VQ_STAT_BYTES
, q
->bytesin
,
866 goto nla_put_failure
;
867 if (nla_put_u32(skb
, TCA_GRED_VQ_STAT_PACKETS
, q
->packetsin
))
868 goto nla_put_failure
;
869 if (nla_put_u32(skb
, TCA_GRED_VQ_STAT_BACKLOG
,
870 gred_backlog(table
, q
, sch
)))
871 goto nla_put_failure
;
872 if (nla_put_u32(skb
, TCA_GRED_VQ_STAT_PROB_DROP
,
874 goto nla_put_failure
;
875 if (nla_put_u32(skb
, TCA_GRED_VQ_STAT_PROB_MARK
,
877 goto nla_put_failure
;
878 if (nla_put_u32(skb
, TCA_GRED_VQ_STAT_FORCED_DROP
,
879 q
->stats
.forced_drop
))
880 goto nla_put_failure
;
881 if (nla_put_u32(skb
, TCA_GRED_VQ_STAT_FORCED_MARK
,
882 q
->stats
.forced_mark
))
883 goto nla_put_failure
;
884 if (nla_put_u32(skb
, TCA_GRED_VQ_STAT_PDROP
, q
->stats
.pdrop
))
885 goto nla_put_failure
;
886 if (nla_put_u32(skb
, TCA_GRED_VQ_STAT_OTHER
, q
->stats
.other
))
887 goto nla_put_failure
;
889 nla_nest_end(skb
, vq
);
891 nla_nest_end(skb
, vqs
);
893 return nla_nest_end(skb
, opts
);
896 nla_nest_cancel(skb
, opts
);
900 static void gred_destroy(struct Qdisc
*sch
)
902 struct gred_sched
*table
= qdisc_priv(sch
);
905 for (i
= 0; i
< table
->DPs
; i
++) {
907 gred_destroy_vq(table
->tab
[i
]);
909 gred_offload(sch
, TC_GRED_DESTROY
);
912 static struct Qdisc_ops gred_qdisc_ops __read_mostly
= {
914 .priv_size
= sizeof(struct gred_sched
),
915 .enqueue
= gred_enqueue
,
916 .dequeue
= gred_dequeue
,
917 .peek
= qdisc_peek_head
,
920 .destroy
= gred_destroy
,
921 .change
= gred_change
,
923 .owner
= THIS_MODULE
,
926 static int __init
gred_module_init(void)
928 return register_qdisc(&gred_qdisc_ops
);
931 static void __exit
gred_module_exit(void)
933 unregister_qdisc(&gred_qdisc_ops
);
936 module_init(gred_module_init
)
937 module_exit(gred_module_exit
)
939 MODULE_LICENSE("GPL");