hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/net/sched/sch_api.c
....@@ -1,10 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * net/sched/sch_api.c Packet scheduler API.
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 *
....@@ -27,7 +23,6 @@
2723 #include <linux/kmod.h>
2824 #include <linux/list.h>
2925 #include <linux/hrtimer.h>
30
-#include <linux/lockdep.h>
3126 #include <linux/slab.h>
3227 #include <linux/hashtable.h>
3328
....@@ -36,6 +31,8 @@
3631 #include <net/netlink.h>
3732 #include <net/pkt_sched.h>
3833 #include <net/pkt_cls.h>
34
+
35
+#include <trace/events/qdisc.h>
3936
4037 /*
4138
....@@ -270,7 +267,8 @@
270267 root->handle == handle)
271268 return root;
272269
273
- hash_for_each_possible_rcu(qdisc_dev(root)->qdisc_hash, q, hash, handle) {
270
+ hash_for_each_possible_rcu(qdisc_dev(root)->qdisc_hash, q, hash, handle,
271
+ lockdep_rtnl_is_held()) {
274272 if (q->handle == handle)
275273 return q;
276274 }
....@@ -303,7 +301,7 @@
303301
304302 if (!handle)
305303 return NULL;
306
- q = qdisc_match_from_root(dev->qdisc, handle);
304
+ q = qdisc_match_from_root(rtnl_dereference(dev->qdisc), handle);
307305 if (q)
308306 goto out;
309307
....@@ -322,7 +320,7 @@
322320
323321 if (!handle)
324322 return NULL;
325
- q = qdisc_match_from_root(dev->qdisc, handle);
323
+ q = qdisc_match_from_root(rcu_dereference(dev->qdisc), handle);
326324 if (q)
327325 goto out;
328326
....@@ -336,7 +334,6 @@
336334 static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid)
337335 {
338336 unsigned long cl;
339
- struct Qdisc *leaf;
340337 const struct Qdisc_class_ops *cops = p->ops->cl_ops;
341338
342339 if (cops == NULL)
....@@ -345,8 +342,7 @@
345342
346343 if (cl == 0)
347344 return NULL;
348
- leaf = cops->leaf(p, cl);
349
- return leaf;
345
+ return cops->leaf(p, cl);
350346 }
351347
352348 /* Find queueing discipline by name */
....@@ -483,7 +479,8 @@
483479 u16 *tab = NULL;
484480 int err;
485481
486
- err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy, extack);
482
+ err = nla_parse_nested_deprecated(tb, TCA_STAB_MAX, opt, stab_policy,
483
+ extack);
487484 if (err < 0)
488485 return ERR_PTR(err);
489486 if (!tb[TCA_STAB_BASE]) {
....@@ -536,11 +533,6 @@
536533 return stab;
537534 }
538535
539
-static void stab_kfree_rcu(struct rcu_head *head)
540
-{
541
- kfree(container_of(head, struct qdisc_size_table, rcu));
542
-}
543
-
544536 void qdisc_put_stab(struct qdisc_size_table *tab)
545537 {
546538 if (!tab)
....@@ -548,7 +540,7 @@
548540
549541 if (--tab->refcnt == 0) {
550542 list_del(&tab->list);
551
- call_rcu_bh(&tab->rcu, stab_kfree_rcu);
543
+ kfree_rcu(tab, rcu);
552544 }
553545 }
554546 EXPORT_SYMBOL(qdisc_put_stab);
....@@ -557,7 +549,7 @@
557549 {
558550 struct nlattr *nest;
559551
560
- nest = nla_nest_start(skb, TCA_STAB);
552
+ nest = nla_nest_start_noflag(skb, TCA_STAB);
561553 if (nest == NULL)
562554 goto nla_put_failure;
563555 if (nla_put(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts))
....@@ -636,21 +628,28 @@
636628 }
637629 EXPORT_SYMBOL(qdisc_watchdog_init);
638630
639
-void qdisc_watchdog_schedule_ns(struct qdisc_watchdog *wd, u64 expires)
631
+void qdisc_watchdog_schedule_range_ns(struct qdisc_watchdog *wd, u64 expires,
632
+ u64 delta_ns)
640633 {
641634 if (test_bit(__QDISC_STATE_DEACTIVATED,
642635 &qdisc_root_sleeping(wd->qdisc)->state))
643636 return;
644637
645
- if (wd->last_expires == expires)
646
- return;
638
+ if (hrtimer_is_queued(&wd->timer)) {
639
+ /* If timer is already set in [expires, expires + delta_ns],
640
+ * do not reprogram it.
641
+ */
642
+ if (wd->last_expires - expires <= delta_ns)
643
+ return;
644
+ }
647645
648646 wd->last_expires = expires;
649
- hrtimer_start(&wd->timer,
650
- ns_to_ktime(expires),
651
- HRTIMER_MODE_ABS_PINNED);
647
+ hrtimer_start_range_ns(&wd->timer,
648
+ ns_to_ktime(expires),
649
+ delta_ns,
650
+ HRTIMER_MODE_ABS_PINNED);
652651 }
653
-EXPORT_SYMBOL(qdisc_watchdog_schedule_ns);
652
+EXPORT_SYMBOL(qdisc_watchdog_schedule_range_ns);
654653
655654 void qdisc_watchdog_cancel(struct qdisc_watchdog *wd)
656655 {
....@@ -768,8 +767,7 @@
768767 return 0;
769768 }
770769
771
-void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n,
772
- unsigned int len)
770
+void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len)
773771 {
774772 bool qdisc_is_offloaded = sch->flags & TCQ_F_OFFLOADED;
775773 const struct Qdisc_class_ops *cops;
....@@ -817,6 +815,71 @@
817815 rcu_read_unlock();
818816 }
819817 EXPORT_SYMBOL(qdisc_tree_reduce_backlog);
818
+
819
+int qdisc_offload_dump_helper(struct Qdisc *sch, enum tc_setup_type type,
820
+ void *type_data)
821
+{
822
+ struct net_device *dev = qdisc_dev(sch);
823
+ int err;
824
+
825
+ sch->flags &= ~TCQ_F_OFFLOADED;
826
+ if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
827
+ return 0;
828
+
829
+ err = dev->netdev_ops->ndo_setup_tc(dev, type, type_data);
830
+ if (err == -EOPNOTSUPP)
831
+ return 0;
832
+
833
+ if (!err)
834
+ sch->flags |= TCQ_F_OFFLOADED;
835
+
836
+ return err;
837
+}
838
+EXPORT_SYMBOL(qdisc_offload_dump_helper);
839
+
840
+void qdisc_offload_graft_helper(struct net_device *dev, struct Qdisc *sch,
841
+ struct Qdisc *new, struct Qdisc *old,
842
+ enum tc_setup_type type, void *type_data,
843
+ struct netlink_ext_ack *extack)
844
+{
845
+ bool any_qdisc_is_offloaded;
846
+ int err;
847
+
848
+ if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
849
+ return;
850
+
851
+ err = dev->netdev_ops->ndo_setup_tc(dev, type, type_data);
852
+
853
+ /* Don't report error if the graft is part of destroy operation. */
854
+ if (!err || !new || new == &noop_qdisc)
855
+ return;
856
+
857
+ /* Don't report error if the parent, the old child and the new
858
+ * one are not offloaded.
859
+ */
860
+ any_qdisc_is_offloaded = new->flags & TCQ_F_OFFLOADED;
861
+ any_qdisc_is_offloaded |= sch && sch->flags & TCQ_F_OFFLOADED;
862
+ any_qdisc_is_offloaded |= old && old->flags & TCQ_F_OFFLOADED;
863
+
864
+ if (any_qdisc_is_offloaded)
865
+ NL_SET_ERR_MSG(extack, "Offloading graft operation failed.");
866
+}
867
+EXPORT_SYMBOL(qdisc_offload_graft_helper);
868
+
869
+static void qdisc_offload_graft_root(struct net_device *dev,
870
+ struct Qdisc *new, struct Qdisc *old,
871
+ struct netlink_ext_ack *extack)
872
+{
873
+ struct tc_root_qopt_offload graft_offload = {
874
+ .command = TC_ROOT_GRAFT,
875
+ .handle = new ? new->handle : 0,
876
+ .ingress = (new && new->flags & TCQ_F_INGRESS) ||
877
+ (old && old->flags & TCQ_F_INGRESS),
878
+ };
879
+
880
+ qdisc_offload_graft_helper(dev, NULL, new, old,
881
+ TC_SETUP_ROOT_QDISC, &graft_offload, extack);
882
+}
820883
821884 static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
822885 u32 portid, u32 seq, u16 flags, int event)
....@@ -949,6 +1012,19 @@
9491012 qdisc_put(old);
9501013 }
9511014
1015
+static void qdisc_clear_nolock(struct Qdisc *sch)
1016
+{
1017
+ sch->flags &= ~TCQ_F_NOLOCK;
1018
+ if (!(sch->flags & TCQ_F_CPUSTATS))
1019
+ return;
1020
+
1021
+ free_percpu(sch->cpu_bstats);
1022
+ free_percpu(sch->cpu_qstats);
1023
+ sch->cpu_bstats = NULL;
1024
+ sch->cpu_qstats = NULL;
1025
+ sch->flags &= ~TCQ_F_CPUSTATS;
1026
+}
1027
+
9521028 /* Graft qdisc "new" to class "classid" of qdisc "parent" or
9531029 * to device "dev".
9541030 *
....@@ -965,16 +1041,15 @@
9651041 {
9661042 struct Qdisc *q = old;
9671043 struct net *net = dev_net(dev);
968
- int err = 0;
9691044
9701045 if (parent == NULL) {
9711046 unsigned int i, num_q, ingress;
1047
+ struct netdev_queue *dev_queue;
9721048
9731049 ingress = 0;
9741050 num_q = dev->num_tx_queues;
9751051 if ((q && q->flags & TCQ_F_INGRESS) ||
9761052 (new && new->flags & TCQ_F_INGRESS)) {
977
- num_q = 1;
9781053 ingress = 1;
9791054 if (!dev_ingress_queue(dev)) {
9801055 NL_SET_ERR_MSG(extack, "Device does not have an ingress queue");
....@@ -985,30 +1060,33 @@
9851060 if (dev->flags & IFF_UP)
9861061 dev_deactivate(dev);
9871062
1063
+ qdisc_offload_graft_root(dev, new, old, extack);
1064
+
9881065 if (new && new->ops->attach)
9891066 goto skip;
9901067
991
- for (i = 0; i < num_q; i++) {
992
- struct netdev_queue *dev_queue = dev_ingress_queue(dev);
993
-
994
- if (!ingress)
1068
+ if (!ingress) {
1069
+ for (i = 0; i < num_q; i++) {
9951070 dev_queue = netdev_get_tx_queue(dev, i);
1071
+ old = dev_graft_qdisc(dev_queue, new);
9961072
997
- old = dev_graft_qdisc(dev_queue, new);
998
- if (new && i > 0)
999
- qdisc_refcount_inc(new);
1000
-
1001
- if (!ingress)
1073
+ if (new && i > 0)
1074
+ qdisc_refcount_inc(new);
10021075 qdisc_put(old);
1076
+ }
1077
+ } else {
1078
+ dev_queue = dev_ingress_queue(dev);
1079
+ old = dev_graft_qdisc(dev_queue, new);
10031080 }
10041081
10051082 skip:
10061083 if (!ingress) {
1007
- notify_and_destroy(net, skb, n, classid,
1008
- dev->qdisc, new);
1084
+ old = rtnl_dereference(dev->qdisc);
10091085 if (new && !new->ops->attach)
10101086 qdisc_refcount_inc(new);
1011
- dev->qdisc = new ? : &noop_qdisc;
1087
+ rcu_assign_pointer(dev->qdisc, new ? : &noop_qdisc);
1088
+
1089
+ notify_and_destroy(net, skb, n, classid, old, new);
10121090
10131091 if (new && new->ops->attach)
10141092 new->ops->attach(new);
....@@ -1020,28 +1098,33 @@
10201098 dev_activate(dev);
10211099 } else {
10221100 const struct Qdisc_class_ops *cops = parent->ops->cl_ops;
1101
+ unsigned long cl;
1102
+ int err;
10231103
10241104 /* Only support running class lockless if parent is lockless */
1025
- if (new && (new->flags & TCQ_F_NOLOCK) &&
1026
- parent && !(parent->flags & TCQ_F_NOLOCK))
1027
- new->flags &= ~TCQ_F_NOLOCK;
1105
+ if (new && (new->flags & TCQ_F_NOLOCK) && !(parent->flags & TCQ_F_NOLOCK))
1106
+ qdisc_clear_nolock(new);
10281107
1029
- err = -EOPNOTSUPP;
1030
- if (cops && cops->graft) {
1031
- unsigned long cl = cops->find(parent, classid);
1108
+ if (!cops || !cops->graft)
1109
+ return -EOPNOTSUPP;
10321110
1033
- if (cl) {
1034
- err = cops->graft(parent, cl, new, &old,
1035
- extack);
1036
- } else {
1037
- NL_SET_ERR_MSG(extack, "Specified class not found");
1038
- err = -ENOENT;
1039
- }
1111
+ cl = cops->find(parent, classid);
1112
+ if (!cl) {
1113
+ NL_SET_ERR_MSG(extack, "Specified class not found");
1114
+ return -ENOENT;
10401115 }
1041
- if (!err)
1042
- notify_and_destroy(net, skb, n, classid, old, new);
1116
+
1117
+ if (new && new->ops == &noqueue_qdisc_ops) {
1118
+ NL_SET_ERR_MSG(extack, "Cannot assign noqueue to a class");
1119
+ return -EINVAL;
1120
+ }
1121
+
1122
+ err = cops->graft(parent, cl, new, &old, extack);
1123
+ if (err)
1124
+ return err;
1125
+ notify_and_destroy(net, skb, n, classid, old, new);
10431126 }
1044
- return err;
1127
+ return 0;
10451128 }
10461129
10471130 static int qdisc_block_indexes_set(struct Qdisc *sch, struct nlattr **tca,
....@@ -1077,10 +1160,6 @@
10771160 }
10781161 return 0;
10791162 }
1080
-
1081
-/* lockdep annotation is needed for ingress; egress gets it only for name */
1082
-static struct lock_class_key qdisc_tx_lock;
1083
-static struct lock_class_key qdisc_rx_lock;
10841163
10851164 /*
10861165 Allocate and initialize new qdisc.
....@@ -1144,17 +1223,22 @@
11441223 sch->parent = parent;
11451224
11461225 if (handle == TC_H_INGRESS) {
1147
- sch->flags |= TCQ_F_INGRESS;
1226
+ if (!(sch->flags & TCQ_F_INGRESS)) {
1227
+ NL_SET_ERR_MSG(extack,
1228
+ "Specified parent ID is reserved for ingress and clsact Qdiscs");
1229
+ err = -EINVAL;
1230
+ goto err_out3;
1231
+ }
11481232 handle = TC_H_MAKE(TC_H_INGRESS, 0);
1149
- lockdep_set_class(qdisc_lock(sch), &qdisc_rx_lock);
11501233 } else {
11511234 if (handle == 0) {
11521235 handle = qdisc_alloc_handle(dev);
1153
- err = -ENOMEM;
1154
- if (handle == 0)
1236
+ if (handle == 0) {
1237
+ NL_SET_ERR_MSG(extack, "Maximum number of qdisc handles was exceeded");
1238
+ err = -ENOSPC;
11551239 goto err_out3;
1240
+ }
11561241 }
1157
- lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock);
11581242 if (!netif_is_multiqueue(dev))
11591243 sch->flags |= TCQ_F_ONETXQUEUE;
11601244 }
....@@ -1191,7 +1275,7 @@
11911275 rcu_assign_pointer(sch->stab, stab);
11921276 }
11931277 if (tca[TCA_RATE]) {
1194
- net_seqlock_t *running;
1278
+ seqcount_t *running;
11951279
11961280 err = -EOPNOTSUPP;
11971281 if (sch->flags & TCQ_F_MQROOT) {
....@@ -1219,6 +1303,7 @@
12191303 }
12201304
12211305 qdisc_hash_add(sch, false);
1306
+ trace_qdisc_create(ops, dev, parent);
12221307
12231308 return sch;
12241309
....@@ -1333,8 +1418,7 @@
13331418 }
13341419
13351420 const struct nla_policy rtm_tca_policy[TCA_MAX + 1] = {
1336
- [TCA_KIND] = { .type = NLA_NUL_STRING,
1337
- .len = IFNAMSIZ - 1 },
1421
+ [TCA_KIND] = { .type = NLA_STRING },
13381422 [TCA_RATE] = { .type = NLA_BINARY,
13391423 .len = sizeof(struct tc_estimator) },
13401424 [TCA_STAB] = { .type = NLA_NESTED },
....@@ -1364,8 +1448,8 @@
13641448 !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
13651449 return -EPERM;
13661450
1367
- err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, rtm_tca_policy,
1368
- extack);
1451
+ err = nlmsg_parse_deprecated(n, sizeof(*tcm), tca, TCA_MAX,
1452
+ rtm_tca_policy, extack);
13691453 if (err < 0)
13701454 return err;
13711455
....@@ -1387,7 +1471,7 @@
13871471 q = dev_ingress_queue(dev)->qdisc_sleeping;
13881472 }
13891473 } else {
1390
- q = dev->qdisc;
1474
+ q = rtnl_dereference(dev->qdisc);
13911475 }
13921476 if (!q) {
13931477 NL_SET_ERR_MSG(extack, "Cannot find specified qdisc on specified device");
....@@ -1429,10 +1513,28 @@
14291513 return 0;
14301514 }
14311515
1516
+static bool req_create_or_replace(struct nlmsghdr *n)
1517
+{
1518
+ return (n->nlmsg_flags & NLM_F_CREATE &&
1519
+ n->nlmsg_flags & NLM_F_REPLACE);
1520
+}
1521
+
1522
+static bool req_create_exclusive(struct nlmsghdr *n)
1523
+{
1524
+ return (n->nlmsg_flags & NLM_F_CREATE &&
1525
+ n->nlmsg_flags & NLM_F_EXCL);
1526
+}
1527
+
1528
+static bool req_change(struct nlmsghdr *n)
1529
+{
1530
+ return (!(n->nlmsg_flags & NLM_F_CREATE) &&
1531
+ !(n->nlmsg_flags & NLM_F_REPLACE) &&
1532
+ !(n->nlmsg_flags & NLM_F_EXCL));
1533
+}
1534
+
14321535 /*
14331536 * Create/change qdisc.
14341537 */
1435
-
14361538 static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
14371539 struct netlink_ext_ack *extack)
14381540 {
....@@ -1449,8 +1551,8 @@
14491551
14501552 replay:
14511553 /* Reinit, just in case something touches this. */
1452
- err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, rtm_tca_policy,
1453
- extack);
1554
+ err = nlmsg_parse_deprecated(n, sizeof(*tcm), tca, TCA_MAX,
1555
+ rtm_tca_policy, extack);
14541556 if (err < 0)
14551557 return err;
14561558
....@@ -1476,7 +1578,7 @@
14761578 q = dev_ingress_queue(dev)->qdisc_sleeping;
14771579 }
14781580 } else {
1479
- q = dev->qdisc;
1581
+ q = rtnl_dereference(dev->qdisc);
14801582 }
14811583
14821584 /* It may be default qdisc, ignore it */
....@@ -1505,10 +1607,19 @@
15051607 NL_SET_ERR_MSG(extack, "Invalid qdisc name");
15061608 return -EINVAL;
15071609 }
1610
+ if (q->flags & TCQ_F_INGRESS) {
1611
+ NL_SET_ERR_MSG(extack,
1612
+ "Cannot regraft ingress or clsact Qdiscs");
1613
+ return -EINVAL;
1614
+ }
15081615 if (q == p ||
15091616 (p && check_loop(q, p, 0))) {
15101617 NL_SET_ERR_MSG(extack, "Qdisc parent/child loop detected");
15111618 return -ELOOP;
1619
+ }
1620
+ if (clid == TC_H_INGRESS) {
1621
+ NL_SET_ERR_MSG(extack, "Ingress cannot graft directly");
1622
+ return -EINVAL;
15121623 }
15131624 qdisc_refcount_inc(q);
15141625 goto graft;
....@@ -1520,27 +1631,35 @@
15201631 *
15211632 * We know, that some child q is already
15221633 * attached to this parent and have choice:
1523
- * either to change it or to create/graft new one.
1634
+ * 1) change it or 2) create/graft new one.
1635
+ * If the requested qdisc kind is different
1636
+ * than the existing one, then we choose graft.
1637
+ * If they are the same then this is "change"
1638
+ * operation - just let it fallthrough..
15241639 *
15251640 * 1. We are allowed to create/graft only
1526
- * if CREATE and REPLACE flags are set.
1641
+ * if the request is explicitly stating
1642
+ * "please create if it doesn't exist".
15271643 *
1528
- * 2. If EXCL is set, requestor wanted to say,
1529
- * that qdisc tcm_handle is not expected
1644
+ * 2. If the request is to exclusive create
1645
+ * then the qdisc tcm_handle is not expected
15301646 * to exist, so that we choose create/graft too.
15311647 *
15321648 * 3. The last case is when no flags are set.
1649
+ * This will happen when for example tc
1650
+ * utility issues a "change" command.
15331651 * Alas, it is sort of hole in API, we
15341652 * cannot decide what to do unambiguously.
1535
- * For now we select create/graft, if
1536
- * user gave KIND, which does not match existing.
1653
+ * For now we select create/graft.
15371654 */
1538
- if ((n->nlmsg_flags & NLM_F_CREATE) &&
1539
- (n->nlmsg_flags & NLM_F_REPLACE) &&
1540
- ((n->nlmsg_flags & NLM_F_EXCL) ||
1541
- (tca[TCA_KIND] &&
1542
- nla_strcmp(tca[TCA_KIND], q->ops->id))))
1543
- goto create_n_graft;
1655
+ if (tca[TCA_KIND] &&
1656
+ nla_strcmp(tca[TCA_KIND], q->ops->id)) {
1657
+ if (req_create_or_replace(n) ||
1658
+ req_create_exclusive(n))
1659
+ goto create_n_graft;
1660
+ else if (req_change(n))
1661
+ goto create_n_graft2;
1662
+ }
15441663 }
15451664 }
15461665 } else {
....@@ -1574,6 +1693,7 @@
15741693 NL_SET_ERR_MSG(extack, "Qdisc not found. To create specify NLM_F_CREATE flag");
15751694 return -ENOENT;
15761695 }
1696
+create_n_graft2:
15771697 if (clid == TC_H_INGRESS) {
15781698 if (dev_ingress_queue(dev)) {
15791699 q = qdisc_create(dev, dev_ingress_queue(dev), p,
....@@ -1684,8 +1804,8 @@
16841804 idx = 0;
16851805 ASSERT_RTNL();
16861806
1687
- err = nlmsg_parse(nlh, sizeof(struct tcmsg), tca, TCA_MAX,
1688
- rtm_tca_policy, NULL);
1807
+ err = nlmsg_parse_deprecated(nlh, sizeof(struct tcmsg), tca, TCA_MAX,
1808
+ rtm_tca_policy, cb->extack);
16891809 if (err < 0)
16901810 return err;
16911811
....@@ -1698,7 +1818,8 @@
16981818 s_q_idx = 0;
16991819 q_idx = 0;
17001820
1701
- if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx,
1821
+ if (tc_dump_qdisc_root(rtnl_dereference(dev->qdisc),
1822
+ skb, cb, &q_idx, s_q_idx,
17021823 true, tca[TCA_DUMP_INVISIBLE]) < 0)
17031824 goto done;
17041825
....@@ -1778,6 +1899,7 @@
17781899 {
17791900 struct sk_buff *skb;
17801901 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
1902
+ int err = 0;
17811903
17821904 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
17831905 if (!skb)
....@@ -1788,8 +1910,11 @@
17881910 return -EINVAL;
17891911 }
17901912
1791
- return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1792
- n->nlmsg_flags & NLM_F_ECHO);
1913
+ err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1914
+ n->nlmsg_flags & NLM_F_ECHO);
1915
+ if (err > 0)
1916
+ err = 0;
1917
+ return err;
17931918 }
17941919
17951920 static int tclass_del_notify(struct net *net,
....@@ -1820,8 +1945,11 @@
18201945 return err;
18211946 }
18221947
1823
- return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1824
- n->nlmsg_flags & NLM_F_ECHO);
1948
+ err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1949
+ n->nlmsg_flags & NLM_F_ECHO);
1950
+ if (err > 0)
1951
+ err = 0;
1952
+ return err;
18251953 }
18261954
18271955 #ifdef CONFIG_NET_CLS
....@@ -1847,36 +1975,57 @@
18471975 return 0;
18481976 }
18491977
1978
+struct tc_bind_class_args {
1979
+ struct qdisc_walker w;
1980
+ unsigned long new_cl;
1981
+ u32 portid;
1982
+ u32 clid;
1983
+};
1984
+
1985
+static int tc_bind_class_walker(struct Qdisc *q, unsigned long cl,
1986
+ struct qdisc_walker *w)
1987
+{
1988
+ struct tc_bind_class_args *a = (struct tc_bind_class_args *)w;
1989
+ const struct Qdisc_class_ops *cops = q->ops->cl_ops;
1990
+ struct tcf_block *block;
1991
+ struct tcf_chain *chain;
1992
+
1993
+ block = cops->tcf_block(q, cl, NULL);
1994
+ if (!block)
1995
+ return 0;
1996
+ for (chain = tcf_get_next_chain(block, NULL);
1997
+ chain;
1998
+ chain = tcf_get_next_chain(block, chain)) {
1999
+ struct tcf_proto *tp;
2000
+
2001
+ for (tp = tcf_get_next_proto(chain, NULL, true);
2002
+ tp; tp = tcf_get_next_proto(chain, tp, true)) {
2003
+ struct tcf_bind_args arg = {};
2004
+
2005
+ arg.w.fn = tcf_node_bind;
2006
+ arg.classid = a->clid;
2007
+ arg.base = cl;
2008
+ arg.cl = a->new_cl;
2009
+ tp->ops->walk(tp, &arg.w, true);
2010
+ }
2011
+ }
2012
+
2013
+ return 0;
2014
+}
2015
+
18502016 static void tc_bind_tclass(struct Qdisc *q, u32 portid, u32 clid,
18512017 unsigned long new_cl)
18522018 {
18532019 const struct Qdisc_class_ops *cops = q->ops->cl_ops;
1854
- struct tcf_block *block;
1855
- struct tcf_chain *chain;
1856
- unsigned long cl;
2020
+ struct tc_bind_class_args args = {};
18572021
1858
- cl = cops->find(q, portid);
1859
- if (!cl)
1860
- return;
18612022 if (!cops->tcf_block)
18622023 return;
1863
- block = cops->tcf_block(q, cl, NULL);
1864
- if (!block)
1865
- return;
1866
- list_for_each_entry(chain, &block->chain_list, list) {
1867
- struct tcf_proto *tp;
1868
-
1869
- for (tp = rtnl_dereference(chain->filter_chain);
1870
- tp; tp = rtnl_dereference(tp->next)) {
1871
- struct tcf_bind_args arg = {};
1872
-
1873
- arg.w.fn = tcf_node_bind;
1874
- arg.classid = clid;
1875
- arg.base = cl;
1876
- arg.cl = new_cl;
1877
- tp->ops->walk(tp, &arg.w);
1878
- }
1879
- }
2024
+ args.portid = portid;
2025
+ args.clid = clid;
2026
+ args.new_cl = new_cl;
2027
+ args.w.fn = tc_bind_class_walker;
2028
+ q->ops->cl_ops->walk(q, &args.w);
18802029 }
18812030
18822031 #else
....@@ -1908,8 +2057,8 @@
19082057 !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
19092058 return -EPERM;
19102059
1911
- err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, rtm_tca_policy,
1912
- extack);
2060
+ err = nlmsg_parse_deprecated(n, sizeof(*tcm), tca, TCA_MAX,
2061
+ rtm_tca_policy, extack);
19132062 if (err < 0)
19142063 return err;
19152064
....@@ -1946,7 +2095,7 @@
19462095 } else if (qid1) {
19472096 qid = qid1;
19482097 } else if (qid == 0)
1949
- qid = dev->qdisc->handle;
2098
+ qid = rtnl_dereference(dev->qdisc)->handle;
19502099
19512100 /* Now qid is genuine qdisc handle consistent
19522101 * both with parent and child.
....@@ -1957,7 +2106,7 @@
19572106 portid = TC_H_MAKE(qid, portid);
19582107 } else {
19592108 if (qid == 0)
1960
- qid = dev->qdisc->handle;
2109
+ qid = rtnl_dereference(dev->qdisc)->handle;
19612110 }
19622111
19632112 /* OK. Locate qdisc */
....@@ -2118,7 +2267,8 @@
21182267 s_t = cb->args[0];
21192268 t = 0;
21202269
2121
- if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t, true) < 0)
2270
+ if (tc_dump_tclass_root(rtnl_dereference(dev->qdisc),
2271
+ skb, tcm, cb, &t, s_t, true) < 0)
21222272 goto done;
21232273
21242274 dev_queue = dev_ingress_queue(dev);