| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Fair Queue CoDel discipline |
|---|
| 3 | | - * |
|---|
| 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. |
|---|
| 8 | 4 | * |
|---|
| 9 | 5 | * Copyright (C) 2012,2015 Eric Dumazet <edumazet@google.com> |
|---|
| 10 | 6 | */ |
|---|
| .. | .. |
|---|
| 18 | 14 | #include <linux/errno.h> |
|---|
| 19 | 15 | #include <linux/init.h> |
|---|
| 20 | 16 | #include <linux/skbuff.h> |
|---|
| 21 | | -#include <linux/jhash.h> |
|---|
| 22 | 17 | #include <linux/slab.h> |
|---|
| 23 | 18 | #include <linux/vmalloc.h> |
|---|
| 24 | 19 | #include <net/netlink.h> |
|---|
| .. | .. |
|---|
| 49 | 44 | struct sk_buff *tail; |
|---|
| 50 | 45 | struct list_head flowchain; |
|---|
| 51 | 46 | int deficit; |
|---|
| 52 | | - u32 dropped; /* number of drops (or ECN marks) on this flow */ |
|---|
| 53 | 47 | struct codel_vars cvars; |
|---|
| 54 | 48 | }; /* please try to keep this structure <= 64 bytes */ |
|---|
| 55 | 49 | |
|---|
| .. | .. |
|---|
| 105 | 99 | case TC_ACT_QUEUED: |
|---|
| 106 | 100 | case TC_ACT_TRAP: |
|---|
| 107 | 101 | *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; |
|---|
| 108 | | - /* fall through */ |
|---|
| 102 | + fallthrough; |
|---|
| 109 | 103 | case TC_ACT_SHOT: |
|---|
| 110 | 104 | return 0; |
|---|
| 111 | 105 | } |
|---|
| .. | .. |
|---|
| 124 | 118 | struct sk_buff *skb = flow->head; |
|---|
| 125 | 119 | |
|---|
| 126 | 120 | flow->head = skb->next; |
|---|
| 127 | | - skb->next = NULL; |
|---|
| 121 | + skb_mark_not_on_list(skb); |
|---|
| 128 | 122 | return skb; |
|---|
| 129 | 123 | } |
|---|
| 130 | 124 | |
|---|
| .. | .. |
|---|
| 177 | 171 | __qdisc_drop(skb, to_free); |
|---|
| 178 | 172 | } while (++i < max_packets && len < threshold); |
|---|
| 179 | 173 | |
|---|
| 180 | | - flow->dropped += i; |
|---|
| 174 | + /* Tell codel to increase its signal strength also */ |
|---|
| 175 | + flow->cvars.count += i; |
|---|
| 181 | 176 | q->backlogs[idx] -= len; |
|---|
| 182 | 177 | q->memory_usage -= mem; |
|---|
| 183 | 178 | sch->qstats.drops += i; |
|---|
| .. | .. |
|---|
| 192 | 187 | struct fq_codel_sched_data *q = qdisc_priv(sch); |
|---|
| 193 | 188 | unsigned int idx, prev_backlog, prev_qlen; |
|---|
| 194 | 189 | struct fq_codel_flow *flow; |
|---|
| 195 | | - int uninitialized_var(ret); |
|---|
| 190 | + int ret; |
|---|
| 196 | 191 | unsigned int pkt_len; |
|---|
| 197 | 192 | bool memory_limited; |
|---|
| 198 | 193 | |
|---|
| .. | .. |
|---|
| 215 | 210 | list_add_tail(&flow->flowchain, &q->new_flows); |
|---|
| 216 | 211 | q->new_flow_count++; |
|---|
| 217 | 212 | flow->deficit = q->quantum; |
|---|
| 218 | | - flow->dropped = 0; |
|---|
| 219 | 213 | } |
|---|
| 220 | 214 | get_codel_cb(skb)->mem_usage = skb->truesize; |
|---|
| 221 | 215 | q->memory_usage += get_codel_cb(skb)->mem_usage; |
|---|
| .. | .. |
|---|
| 290 | 284 | struct sk_buff *skb; |
|---|
| 291 | 285 | struct fq_codel_flow *flow; |
|---|
| 292 | 286 | struct list_head *head; |
|---|
| 293 | | - u32 prev_drop_count, prev_ecn_mark; |
|---|
| 294 | 287 | |
|---|
| 295 | 288 | begin: |
|---|
| 296 | 289 | head = &q->new_flows; |
|---|
| .. | .. |
|---|
| 307 | 300 | goto begin; |
|---|
| 308 | 301 | } |
|---|
| 309 | 302 | |
|---|
| 310 | | - prev_drop_count = q->cstats.drop_count; |
|---|
| 311 | | - prev_ecn_mark = q->cstats.ecn_mark; |
|---|
| 312 | | - |
|---|
| 313 | 303 | skb = codel_dequeue(sch, &sch->qstats.backlog, &q->cparams, |
|---|
| 314 | 304 | &flow->cvars, &q->cstats, qdisc_pkt_len, |
|---|
| 315 | 305 | codel_get_enqueue_time, drop_func, dequeue_func); |
|---|
| 316 | | - |
|---|
| 317 | | - flow->dropped += q->cstats.drop_count - prev_drop_count; |
|---|
| 318 | | - flow->dropped += q->cstats.ecn_mark - prev_ecn_mark; |
|---|
| 319 | 306 | |
|---|
| 320 | 307 | if (!skb) { |
|---|
| 321 | 308 | /* force a pass through old_flows to prevent starvation */ |
|---|
| .. | .. |
|---|
| 360 | 347 | codel_vars_init(&flow->cvars); |
|---|
| 361 | 348 | } |
|---|
| 362 | 349 | memset(q->backlogs, 0, q->flows_cnt * sizeof(u32)); |
|---|
| 363 | | - sch->q.qlen = 0; |
|---|
| 364 | | - sch->qstats.backlog = 0; |
|---|
| 365 | 350 | q->memory_usage = 0; |
|---|
| 366 | 351 | } |
|---|
| 367 | 352 | |
|---|
| .. | .. |
|---|
| 388 | 373 | if (!opt) |
|---|
| 389 | 374 | return -EINVAL; |
|---|
| 390 | 375 | |
|---|
| 391 | | - err = nla_parse_nested(tb, TCA_FQ_CODEL_MAX, opt, fq_codel_policy, |
|---|
| 392 | | - NULL); |
|---|
| 376 | + err = nla_parse_nested_deprecated(tb, TCA_FQ_CODEL_MAX, opt, |
|---|
| 377 | + fq_codel_policy, NULL); |
|---|
| 393 | 378 | if (err < 0) |
|---|
| 394 | 379 | return err; |
|---|
| 395 | 380 | if (tb[TCA_FQ_CODEL_FLOWS]) { |
|---|
| .. | .. |
|---|
| 535 | 520 | struct fq_codel_sched_data *q = qdisc_priv(sch); |
|---|
| 536 | 521 | struct nlattr *opts; |
|---|
| 537 | 522 | |
|---|
| 538 | | - opts = nla_nest_start(skb, TCA_OPTIONS); |
|---|
| 523 | + opts = nla_nest_start_noflag(skb, TCA_OPTIONS); |
|---|
| 539 | 524 | if (opts == NULL) |
|---|
| 540 | 525 | goto nla_put_failure; |
|---|
| 541 | 526 | |
|---|
| .. | .. |
|---|
| 670 | 655 | sch_tree_unlock(sch); |
|---|
| 671 | 656 | } |
|---|
| 672 | 657 | qs.backlog = q->backlogs[idx]; |
|---|
| 673 | | - qs.drops = flow->dropped; |
|---|
| 658 | + qs.drops = 0; |
|---|
| 674 | 659 | } |
|---|
| 675 | 660 | if (gnet_stats_copy_queue(d, NULL, &qs, qs.qlen) < 0) |
|---|
| 676 | 661 | return -1; |
|---|
| .. | .. |
|---|
| 742 | 727 | module_exit(fq_codel_module_exit) |
|---|
| 743 | 728 | MODULE_AUTHOR("Eric Dumazet"); |
|---|
| 744 | 729 | MODULE_LICENSE("GPL"); |
|---|
| 730 | +MODULE_DESCRIPTION("Fair Queue CoDel discipline"); |
|---|