.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * net/sched/act_sample.c - Packet sampling tc action |
---|
3 | 4 | * 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. |
---|
8 | 5 | */ |
---|
9 | 6 | |
---|
10 | 7 | #include <linux/types.h> |
---|
.. | .. |
---|
22 | 19 | #include <linux/tc_act/tc_sample.h> |
---|
23 | 20 | #include <net/tc_act/tc_sample.h> |
---|
24 | 21 | #include <net/psample.h> |
---|
| 22 | +#include <net/pkt_cls.h> |
---|
25 | 23 | |
---|
26 | 24 | #include <linux/if_arp.h> |
---|
27 | 25 | |
---|
.. | .. |
---|
37 | 35 | |
---|
38 | 36 | static int tcf_sample_init(struct net *net, struct nlattr *nla, |
---|
39 | 37 | 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) |
---|
42 | 40 | { |
---|
43 | 41 | struct tc_action_net *tn = net_generic(net, sample_net_id); |
---|
44 | 42 | struct nlattr *tb[TCA_SAMPLE_MAX + 1]; |
---|
45 | 43 | struct psample_group *psample_group; |
---|
46 | 44 | u32 psample_group_num, rate, index; |
---|
| 45 | + struct tcf_chain *goto_ch = NULL; |
---|
47 | 46 | struct tc_sample *parm; |
---|
48 | 47 | struct tcf_sample *s; |
---|
49 | 48 | bool exists = false; |
---|
.. | .. |
---|
51 | 50 | |
---|
52 | 51 | if (!nla) |
---|
53 | 52 | 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); |
---|
55 | 55 | if (ret < 0) |
---|
56 | 56 | return ret; |
---|
57 | 57 | if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] || |
---|
.. | .. |
---|
69 | 69 | |
---|
70 | 70 | if (!exists) { |
---|
71 | 71 | ret = tcf_idr_create(tn, index, est, a, |
---|
72 | | - &act_sample_ops, bind, true); |
---|
| 72 | + &act_sample_ops, bind, true, 0); |
---|
73 | 73 | if (ret) { |
---|
74 | 74 | tcf_idr_cleanup(tn, index); |
---|
75 | 75 | return ret; |
---|
.. | .. |
---|
79 | 79 | tcf_idr_release(*a, bind); |
---|
80 | 80 | return -EEXIST; |
---|
81 | 81 | } |
---|
| 82 | + err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); |
---|
| 83 | + if (err < 0) |
---|
| 84 | + goto release_idr; |
---|
82 | 85 | |
---|
83 | 86 | rate = nla_get_u32(tb[TCA_SAMPLE_RATE]); |
---|
84 | 87 | if (!rate) { |
---|
85 | 88 | NL_SET_ERR_MSG(extack, "invalid sample rate"); |
---|
86 | | - tcf_idr_release(*a, bind); |
---|
87 | | - return -EINVAL; |
---|
| 89 | + err = -EINVAL; |
---|
| 90 | + goto put_chain; |
---|
88 | 91 | } |
---|
89 | 92 | psample_group_num = nla_get_u32(tb[TCA_SAMPLE_PSAMPLE_GROUP]); |
---|
90 | 93 | psample_group = psample_group_get(net, psample_group_num); |
---|
91 | 94 | if (!psample_group) { |
---|
92 | | - tcf_idr_release(*a, bind); |
---|
93 | | - return -ENOMEM; |
---|
| 95 | + err = -ENOMEM; |
---|
| 96 | + goto put_chain; |
---|
94 | 97 | } |
---|
95 | 98 | |
---|
96 | 99 | s = to_sample(*a); |
---|
97 | 100 | |
---|
98 | 101 | spin_lock_bh(&s->tcf_lock); |
---|
99 | | - s->tcf_action = parm->action; |
---|
| 102 | + goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); |
---|
100 | 103 | s->rate = rate; |
---|
101 | 104 | s->psample_group_num = psample_group_num; |
---|
102 | | - rcu_swap_protected(s->psample_group, psample_group, |
---|
103 | | - lockdep_is_held(&s->tcf_lock)); |
---|
| 105 | + psample_group = rcu_replace_pointer(s->psample_group, psample_group, |
---|
| 106 | + lockdep_is_held(&s->tcf_lock)); |
---|
104 | 107 | |
---|
105 | 108 | if (tb[TCA_SAMPLE_TRUNC_SIZE]) { |
---|
106 | 109 | s->truncate = true; |
---|
.. | .. |
---|
110 | 113 | |
---|
111 | 114 | if (psample_group) |
---|
112 | 115 | psample_group_put(psample_group); |
---|
113 | | - if (ret == ACT_P_CREATED) |
---|
114 | | - tcf_idr_insert(tn, *a); |
---|
| 116 | + if (goto_ch) |
---|
| 117 | + tcf_chain_put_by_act(goto_ch); |
---|
| 118 | + |
---|
115 | 119 | return ret; |
---|
| 120 | +put_chain: |
---|
| 121 | + if (goto_ch) |
---|
| 122 | + tcf_chain_put_by_act(goto_ch); |
---|
| 123 | +release_idr: |
---|
| 124 | + tcf_idr_release(*a, bind); |
---|
| 125 | + return err; |
---|
116 | 126 | } |
---|
117 | 127 | |
---|
118 | 128 | static void tcf_sample_cleanup(struct tc_action *a) |
---|
.. | .. |
---|
234 | 244 | return tcf_generic_walker(tn, skb, cb, type, ops, extack); |
---|
235 | 245 | } |
---|
236 | 246 | |
---|
237 | | -static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index, |
---|
238 | | - struct netlink_ext_ack *extack) |
---|
| 247 | +static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index) |
---|
239 | 248 | { |
---|
240 | 249 | struct tc_action_net *tn = net_generic(net, sample_net_id); |
---|
241 | 250 | |
---|
242 | 251 | return tcf_idr_search(tn, a, index); |
---|
243 | 252 | } |
---|
244 | 253 | |
---|
| 254 | +static void tcf_psample_group_put(void *priv) |
---|
| 255 | +{ |
---|
| 256 | + struct psample_group *group = priv; |
---|
| 257 | + |
---|
| 258 | + psample_group_put(group); |
---|
| 259 | +} |
---|
| 260 | + |
---|
| 261 | +static struct psample_group * |
---|
| 262 | +tcf_sample_get_group(const struct tc_action *a, |
---|
| 263 | + tc_action_priv_destructor *destructor) |
---|
| 264 | +{ |
---|
| 265 | + struct tcf_sample *s = to_sample(a); |
---|
| 266 | + struct psample_group *group; |
---|
| 267 | + |
---|
| 268 | + group = rcu_dereference_protected(s->psample_group, |
---|
| 269 | + lockdep_is_held(&s->tcf_lock)); |
---|
| 270 | + if (group) { |
---|
| 271 | + psample_group_take(group); |
---|
| 272 | + *destructor = tcf_psample_group_put; |
---|
| 273 | + } |
---|
| 274 | + |
---|
| 275 | + return group; |
---|
| 276 | +} |
---|
| 277 | + |
---|
245 | 278 | static struct tc_action_ops act_sample_ops = { |
---|
246 | 279 | .kind = "sample", |
---|
247 | | - .type = TCA_ACT_SAMPLE, |
---|
| 280 | + .id = TCA_ID_SAMPLE, |
---|
248 | 281 | .owner = THIS_MODULE, |
---|
249 | 282 | .act = tcf_sample_act, |
---|
250 | 283 | .dump = tcf_sample_dump, |
---|
.. | .. |
---|
252 | 285 | .cleanup = tcf_sample_cleanup, |
---|
253 | 286 | .walk = tcf_sample_walker, |
---|
254 | 287 | .lookup = tcf_sample_search, |
---|
| 288 | + .get_psample_group = tcf_sample_get_group, |
---|
255 | 289 | .size = sizeof(struct tcf_sample), |
---|
256 | 290 | }; |
---|
257 | 291 | |
---|