hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/net/sched/act_sample.c
....@@ -1,10 +1,7 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * net/sched/act_sample.c - Packet sampling tc action
34 * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
4
- *
5
- * This program is free software; you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License version 2 as
7
- * published by the Free Software Foundation.
85 */
96
107 #include <linux/types.h>
....@@ -22,6 +19,7 @@
2219 #include <linux/tc_act/tc_sample.h>
2320 #include <net/tc_act/tc_sample.h>
2421 #include <net/psample.h>
22
+#include <net/pkt_cls.h>
2523
2624 #include <linux/if_arp.h>
2725
....@@ -37,13 +35,14 @@
3735
3836 static int tcf_sample_init(struct net *net, struct nlattr *nla,
3937 struct nlattr *est, struct tc_action **a, int ovr,
40
- int bind, bool rtnl_held,
41
- struct netlink_ext_ack *extack)
38
+ int bind, bool rtnl_held, struct tcf_proto *tp,
39
+ u32 flags, struct netlink_ext_ack *extack)
4240 {
4341 struct tc_action_net *tn = net_generic(net, sample_net_id);
4442 struct nlattr *tb[TCA_SAMPLE_MAX + 1];
4543 struct psample_group *psample_group;
4644 u32 psample_group_num, rate, index;
45
+ struct tcf_chain *goto_ch = NULL;
4746 struct tc_sample *parm;
4847 struct tcf_sample *s;
4948 bool exists = false;
....@@ -51,11 +50,12 @@
5150
5251 if (!nla)
5352 return -EINVAL;
54
- ret = nla_parse_nested(tb, TCA_SAMPLE_MAX, nla, sample_policy, NULL);
53
+ ret = nla_parse_nested_deprecated(tb, TCA_SAMPLE_MAX, nla,
54
+ sample_policy, NULL);
5555 if (ret < 0)
5656 return ret;
57
- if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] ||
58
- !tb[TCA_SAMPLE_PSAMPLE_GROUP])
57
+
58
+ if (!tb[TCA_SAMPLE_PARMS])
5959 return -EINVAL;
6060
6161 parm = nla_data(tb[TCA_SAMPLE_PARMS]);
....@@ -69,7 +69,7 @@
6969
7070 if (!exists) {
7171 ret = tcf_idr_create(tn, index, est, a,
72
- &act_sample_ops, bind, true);
72
+ &act_sample_ops, bind, true, flags);
7373 if (ret) {
7474 tcf_idr_cleanup(tn, index);
7575 return ret;
....@@ -80,27 +80,37 @@
8080 return -EEXIST;
8181 }
8282
83
+ if (!tb[TCA_SAMPLE_RATE] || !tb[TCA_SAMPLE_PSAMPLE_GROUP]) {
84
+ NL_SET_ERR_MSG(extack, "sample rate and group are required");
85
+ err = -EINVAL;
86
+ goto release_idr;
87
+ }
88
+
89
+ err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
90
+ if (err < 0)
91
+ goto release_idr;
92
+
8393 rate = nla_get_u32(tb[TCA_SAMPLE_RATE]);
8494 if (!rate) {
8595 NL_SET_ERR_MSG(extack, "invalid sample rate");
86
- tcf_idr_release(*a, bind);
87
- return -EINVAL;
96
+ err = -EINVAL;
97
+ goto put_chain;
8898 }
8999 psample_group_num = nla_get_u32(tb[TCA_SAMPLE_PSAMPLE_GROUP]);
90100 psample_group = psample_group_get(net, psample_group_num);
91101 if (!psample_group) {
92
- tcf_idr_release(*a, bind);
93
- return -ENOMEM;
102
+ err = -ENOMEM;
103
+ goto put_chain;
94104 }
95105
96106 s = to_sample(*a);
97107
98108 spin_lock_bh(&s->tcf_lock);
99
- s->tcf_action = parm->action;
109
+ goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
100110 s->rate = rate;
101111 s->psample_group_num = psample_group_num;
102
- rcu_swap_protected(s->psample_group, psample_group,
103
- lockdep_is_held(&s->tcf_lock));
112
+ psample_group = rcu_replace_pointer(s->psample_group, psample_group,
113
+ lockdep_is_held(&s->tcf_lock));
104114
105115 if (tb[TCA_SAMPLE_TRUNC_SIZE]) {
106116 s->truncate = true;
....@@ -110,9 +120,16 @@
110120
111121 if (psample_group)
112122 psample_group_put(psample_group);
113
- if (ret == ACT_P_CREATED)
114
- tcf_idr_insert(tn, *a);
123
+ if (goto_ch)
124
+ tcf_chain_put_by_act(goto_ch);
125
+
115126 return ret;
127
+put_chain:
128
+ if (goto_ch)
129
+ tcf_chain_put_by_act(goto_ch);
130
+release_idr:
131
+ tcf_idr_release(*a, bind);
132
+ return err;
116133 }
117134
118135 static void tcf_sample_cleanup(struct tc_action *a)
....@@ -234,17 +251,40 @@
234251 return tcf_generic_walker(tn, skb, cb, type, ops, extack);
235252 }
236253
237
-static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index,
238
- struct netlink_ext_ack *extack)
254
+static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index)
239255 {
240256 struct tc_action_net *tn = net_generic(net, sample_net_id);
241257
242258 return tcf_idr_search(tn, a, index);
243259 }
244260
261
+static void tcf_psample_group_put(void *priv)
262
+{
263
+ struct psample_group *group = priv;
264
+
265
+ psample_group_put(group);
266
+}
267
+
268
+static struct psample_group *
269
+tcf_sample_get_group(const struct tc_action *a,
270
+ tc_action_priv_destructor *destructor)
271
+{
272
+ struct tcf_sample *s = to_sample(a);
273
+ struct psample_group *group;
274
+
275
+ group = rcu_dereference_protected(s->psample_group,
276
+ lockdep_is_held(&s->tcf_lock));
277
+ if (group) {
278
+ psample_group_take(group);
279
+ *destructor = tcf_psample_group_put;
280
+ }
281
+
282
+ return group;
283
+}
284
+
245285 static struct tc_action_ops act_sample_ops = {
246286 .kind = "sample",
247
- .type = TCA_ACT_SAMPLE,
287
+ .id = TCA_ID_SAMPLE,
248288 .owner = THIS_MODULE,
249289 .act = tcf_sample_act,
250290 .dump = tcf_sample_dump,
....@@ -252,6 +292,7 @@
252292 .cleanup = tcf_sample_cleanup,
253293 .walk = tcf_sample_walker,
254294 .lookup = tcf_sample_search,
295
+ .get_psample_group = tcf_sample_get_group,
255296 .size = sizeof(struct tcf_sample),
256297 };
257298