hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/net/sched/sch_tbf.c
....@@ -1,15 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * net/sched/sch_tbf.c Token Bucket Filter queue.
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.
84 *
95 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
106 * Dmitry Torokhov <dtor@mail.ru> - allow attaching inner qdiscs -
117 * original idea by Martin Devera
12
- *
138 */
149
1510 #include <linux/module.h>
....@@ -20,6 +15,7 @@
2015 #include <linux/skbuff.h>
2116 #include <net/netlink.h>
2217 #include <net/sch_generic.h>
18
+#include <net/pkt_cls.h>
2319 #include <net/pkt_sched.h>
2420
2521
....@@ -142,6 +138,52 @@
142138 return len;
143139 }
144140
141
+static void tbf_offload_change(struct Qdisc *sch)
142
+{
143
+ struct tbf_sched_data *q = qdisc_priv(sch);
144
+ struct net_device *dev = qdisc_dev(sch);
145
+ struct tc_tbf_qopt_offload qopt;
146
+
147
+ if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
148
+ return;
149
+
150
+ qopt.command = TC_TBF_REPLACE;
151
+ qopt.handle = sch->handle;
152
+ qopt.parent = sch->parent;
153
+ qopt.replace_params.rate = q->rate;
154
+ qopt.replace_params.max_size = q->max_size;
155
+ qopt.replace_params.qstats = &sch->qstats;
156
+
157
+ dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_TBF, &qopt);
158
+}
159
+
160
+static void tbf_offload_destroy(struct Qdisc *sch)
161
+{
162
+ struct net_device *dev = qdisc_dev(sch);
163
+ struct tc_tbf_qopt_offload qopt;
164
+
165
+ if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
166
+ return;
167
+
168
+ qopt.command = TC_TBF_DESTROY;
169
+ qopt.handle = sch->handle;
170
+ qopt.parent = sch->parent;
171
+ dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_TBF, &qopt);
172
+}
173
+
174
+static int tbf_offload_dump(struct Qdisc *sch)
175
+{
176
+ struct tc_tbf_qopt_offload qopt;
177
+
178
+ qopt.command = TC_TBF_STATS;
179
+ qopt.handle = sch->handle;
180
+ qopt.parent = sch->parent;
181
+ qopt.stats.bstats = &sch->bstats;
182
+ qopt.stats.qstats = &sch->qstats;
183
+
184
+ return qdisc_offload_dump_helper(sch, TC_SETUP_QDISC_TBF, &qopt);
185
+}
186
+
145187 /* GSO packet is too big, segment it so that tbf can transmit
146188 * each segment in time
147189 */
....@@ -160,9 +202,8 @@
160202 return qdisc_drop(skb, sch, to_free);
161203
162204 nb = 0;
163
- while (segs) {
164
- nskb = segs->next;
165
- segs->next = NULL;
205
+ skb_list_walk_safe(segs, segs, nskb) {
206
+ skb_mark_not_on_list(segs);
166207 qdisc_skb_cb(segs)->pkt_len = segs->len;
167208 len += segs->len;
168209 ret = qdisc_enqueue(segs, q->qdisc, to_free);
....@@ -172,7 +213,6 @@
172213 } else {
173214 nb++;
174215 }
175
- segs = nskb;
176216 }
177217 sch->q.qlen += nb;
178218 if (nb > 1)
....@@ -185,6 +225,7 @@
185225 struct sk_buff **to_free)
186226 {
187227 struct tbf_sched_data *q = qdisc_priv(sch);
228
+ unsigned int len = qdisc_pkt_len(skb);
188229 int ret;
189230
190231 if (qdisc_pkt_len(skb) > q->max_size) {
....@@ -200,7 +241,7 @@
200241 return ret;
201242 }
202243
203
- qdisc_qstats_backlog_inc(sch, skb);
244
+ sch->qstats.backlog += len;
204245 sch->q.qlen++;
205246 return NET_XMIT_SUCCESS;
206247 }
....@@ -275,8 +316,6 @@
275316 struct tbf_sched_data *q = qdisc_priv(sch);
276317
277318 qdisc_reset(q->qdisc);
278
- sch->qstats.backlog = 0;
279
- sch->q.qlen = 0;
280319 q->t_c = ktime_get_ns();
281320 q->tokens = q->buffer;
282321 q->ptokens = q->mtu;
....@@ -301,13 +340,15 @@
301340 struct nlattr *tb[TCA_TBF_MAX + 1];
302341 struct tc_tbf_qopt *qopt;
303342 struct Qdisc *child = NULL;
343
+ struct Qdisc *old = NULL;
304344 struct psched_ratecfg rate;
305345 struct psched_ratecfg peak;
306346 u64 max_size;
307347 s64 buffer, mtu;
308348 u64 rate64 = 0, prate64 = 0;
309349
310
- err = nla_parse_nested(tb, TCA_TBF_MAX, opt, tbf_policy, NULL);
350
+ err = nla_parse_nested_deprecated(tb, TCA_TBF_MAX, opt, tbf_policy,
351
+ NULL);
311352 if (err < 0)
312353 return err;
313354
....@@ -390,9 +431,8 @@
390431
391432 sch_tree_lock(sch);
392433 if (child) {
393
- qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
394
- q->qdisc->qstats.backlog);
395
- qdisc_put(q->qdisc);
434
+ qdisc_tree_flush_backlog(q->qdisc);
435
+ old = q->qdisc;
396436 q->qdisc = child;
397437 }
398438 q->limit = qopt->limit;
....@@ -412,7 +452,10 @@
412452 memcpy(&q->peak, &peak, sizeof(struct psched_ratecfg));
413453
414454 sch_tree_unlock(sch);
455
+ qdisc_put(old);
415456 err = 0;
457
+
458
+ tbf_offload_change(sch);
416459 done:
417460 return err;
418461 }
....@@ -438,6 +481,7 @@
438481 struct tbf_sched_data *q = qdisc_priv(sch);
439482
440483 qdisc_watchdog_cancel(&q->watchdog);
484
+ tbf_offload_destroy(sch);
441485 qdisc_put(q->qdisc);
442486 }
443487
....@@ -446,9 +490,13 @@
446490 struct tbf_sched_data *q = qdisc_priv(sch);
447491 struct nlattr *nest;
448492 struct tc_tbf_qopt opt;
493
+ int err;
449494
450
- sch->qstats.backlog = q->qdisc->qstats.backlog;
451
- nest = nla_nest_start(skb, TCA_OPTIONS);
495
+ err = tbf_offload_dump(sch);
496
+ if (err)
497
+ return err;
498
+
499
+ nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
452500 if (nest == NULL)
453501 goto nla_put_failure;
454502