// SPDX-License-Identifier: GPL-2.0-or-later /* * net/sched/sch_gred.c Generic Random Early Detection queue. * * Authors: J Hadi Salim (hadi@cyberus.ca) 1998-2002 * * 991129: - Bug fix with grio mode * - a better sing. AvgQ mode with Grio(WRED) * - A finer grained VQ dequeue based on suggestion * from Ren Liu * - More error checks * * For all the glorious comments look at include/net/red.h
*/
struct gred_sched_data {
u32 limit; /* HARD maximal queue length */
u32 DP; /* the drop parameters */
u32 red_flags; /* virtualQ version of red_flags */
u64 bytesin; /* bytes seen on virtualQ so far*/
u32 packetsin; /* packets seen on virtualQ so far*/
u32 backlog; /* bytes on the virtualQ */
u8 prio; /* the prio of this vq */
/* Local per-vq flags couldn't have been set unless global are 0 */ if (table->red_flags) returnfalse; for (i = 0; i < MAX_DPs; i++) if (table->tab[i] && table->tab[i]->red_flags) returntrue; returnfalse;
}
q = t->tab[dp]; if (!q) { /* Pass through packets not assigned to a DP * if no default DP has been configured. This * allows for DP flows to be left untouched.
*/ if (likely(sch->qstats.backlog + qdisc_pkt_len(skb) <=
sch->limit)) return qdisc_enqueue_tail(skb, sch); else goto drop;
}
/* fix tc_index? --could be controversial but needed for
requeueing */
skb->tc_index = (skb->tc_index & ~GRED_VQ_MASK) | dp;
}
/* sum up all the qaves of prios < ours to get the new qave */ if (!gred_wred_mode(t) && gred_rio_mode(t)) { int i;
for (i = 0; i < t->DPs; i++) { if (t->tab[i] && t->tab[i]->prio < q->prio &&
!red_is_idling(&t->tab[i]->vars))
qavg += t->tab[i]->vars.qavg;
}
}
q->packetsin++;
q->bytesin += qdisc_pkt_len(skb);
if (gred_wred_mode(t))
gred_load_wred_set(t, q);
q->vars.qavg = red_calc_qavg(&q->parms,
&q->vars,
gred_backlog(t, q, sch));
if (red_is_idling(&q->vars))
red_end_of_idle_period(&q->vars);
if (gred_wred_mode(t))
gred_store_wred_set(t, q);
switch (red_action(&q->parms, &q->vars, q->vars.qavg + qavg)) { case RED_DONT_MARK: break;
case RED_PROB_MARK:
qdisc_qstats_overlimit(sch); if (!gred_use_ecn(q) || !INET_ECN_set_ce(skb)) {
q->stats.prob_drop++; goto congestion_drop;
}
q->stats.prob_mark++; break;
case RED_HARD_MARK:
qdisc_qstats_overlimit(sch); if (gred_use_harddrop(q) || !gred_use_ecn(q) ||
!INET_ECN_set_ce(skb)) {
q->stats.forced_drop++; goto congestion_drop;
}
q->stats.forced_mark++; break;
}
if (gred_backlog(t, q, sch) + qdisc_pkt_len(skb) <= q->limit) {
q->backlog += qdisc_pkt_len(skb); return qdisc_enqueue_tail(skb, sch);
}
if (skb) { struct gred_sched_data *q;
u16 dp = tc_index_to_dp(skb);
if (dp >= t->DPs || (q = t->tab[dp]) == NULL) {
net_warn_ratelimited("GRED: Unable to relocate VQ 0x%x after dequeue, screwing up backlog\n",
tc_index_to_dp(skb));
} else {
q->backlog -= qdisc_pkt_len(skb);
if (gred_wred_mode(t)) { if (!sch->qstats.backlog)
red_start_of_idle_period(&t->wred_set);
} else { if (!q->backlog)
red_start_of_idle_period(&q->vars);
}
}
for (i = 0; i < MAX_DPs; i++) {
gnet_stats_basic_sync_init(&hw_stats->stats.bstats[i]); if (table->tab[i])
hw_stats->stats.xstats[i] = &table->tab[i]->stats;
}
ret = qdisc_offload_dump_helper(sch, TC_SETUP_QDISC_GRED, hw_stats); /* Even if driver returns failure adjust the stats - in case offload * ended but driver still wants to adjust the values.
*/
sch_tree_lock(sch); for (i = 0; i < MAX_DPs; i++) { if (!table->tab[i]) continue;
table->tab[i]->packetsin += u64_stats_read(&hw_stats->stats.bstats[i].packets);
table->tab[i]->bytesin += u64_stats_read(&hw_stats->stats.bstats[i].bytes);
table->tab[i]->backlog += hw_stats->stats.qstats[i].backlog;
/* * Every entry point to GRED is synchronized with the above code * and the DP is checked against DPs, i.e. shadowed VQs can no * longer be found so we can unlock right here.
*/
sch_tree_unlock(sch);
if (sopt->grio) {
gred_enable_rio_mode(table);
gred_disable_wred_mode(table); if (gred_wred_mode_check(sch))
gred_enable_wred_mode(table);
} else {
gred_disable_rio_mode(table);
gred_disable_wred_mode(table);
}
if (red_flags_changed) for (i = 0; i < table->DPs; i++) if (table->tab[i])
table->tab[i]->red_flags =
table->red_flags & GRED_VQ_RED_FLAGS;
for (i = table->DPs; i < MAX_DPs; i++) { if (table->tab[i]) {
pr_warn("GRED: Warning: Destroying shadowed VQ 0x%x\n",
i);
gred_destroy_vq(table->tab[i]);
table->tab[i] = NULL;
}
}
if (!tb[TCA_GRED_VQ_DP]) {
NL_SET_ERR_MSG_MOD(extack, "Virtual queue with no index specified"); return -EINVAL;
}
dp = nla_get_u32(tb[TCA_GRED_VQ_DP]); if (dp >= table->DPs) {
NL_SET_ERR_MSG_MOD(extack, "Virtual queue with index out of bounds"); return -EINVAL;
} if (dp != cdp && !table->tab[dp]) {
NL_SET_ERR_MSG_MOD(extack, "Virtual queue not yet instantiated"); return -EINVAL;
}
if (tb[TCA_GRED_VQ_FLAGS]) {
u32 red_flags = nla_get_u32(tb[TCA_GRED_VQ_FLAGS]);
if (table->red_flags && table->red_flags != red_flags) {
NL_SET_ERR_MSG_MOD(extack, "can't change per-virtual queue RED flags when per-Qdisc flags are used"); return -EINVAL;
} if (red_flags & ~GRED_VQ_RED_FLAGS) {
NL_SET_ERR_MSG_MOD(extack, "invalid RED flags specified"); return -EINVAL;
}
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic Random Early Detection qdisc");
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.13Bemerkung:
(vorverarbeitet am 2026-06-07)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.