Blame view
net/sched/act_skbedit.c
10.2 KB
9952f6918 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
ca9b0e27e pkt_action: add n... |
2 3 4 |
/* * Copyright (c) 2008, Intel Corporation. * |
ca9b0e27e pkt_action: add n... |
5 6 7 8 9 10 11 12 13 14 |
* Author: Alexander Duyck <alexander.h.duyck@intel.com> */ #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/skbuff.h> #include <linux/rtnetlink.h> #include <net/netlink.h> #include <net/pkt_sched.h> |
e7e3728bd net:sched: add ac... |
15 16 17 |
#include <net/ip.h> #include <net/ipv6.h> #include <net/dsfield.h> |
ec7727bb2 net/sched: act_sk... |
18 |
#include <net/pkt_cls.h> |
ca9b0e27e pkt_action: add n... |
19 20 21 |
#include <linux/tc_act/tc_skbedit.h> #include <net/tc_act/tc_skbedit.h> |
c7d03a00b netns: make struc... |
22 |
static unsigned int skbedit_net_id; |
a85a970af net_sched: move t... |
23 |
static struct tc_action_ops act_skbedit_ops; |
ddf97ccdd net_sched: add ne... |
24 |
|
45da1dac6 net: sched: act_s... |
25 26 |
static int tcf_skbedit_act(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) |
ca9b0e27e pkt_action: add n... |
27 |
{ |
a85a970af net_sched: move t... |
28 |
struct tcf_skbedit *d = to_skbedit(a); |
c749cdda9 net/sched: act_sk... |
29 30 |
struct tcf_skbedit_params *params; int action; |
ca9b0e27e pkt_action: add n... |
31 |
|
9c4a4e488 net sched: action... |
32 |
tcf_lastuse_update(&d->tcf_tm); |
6f3dfb0dc net/sched: skbedi... |
33 |
bstats_cpu_update(this_cpu_ptr(d->common.cpu_bstats), skb); |
ca9b0e27e pkt_action: add n... |
34 |
|
7fd4b288e tc/act: remove un... |
35 |
params = rcu_dereference_bh(d->params); |
c749cdda9 net/sched: act_sk... |
36 37 38 39 40 |
action = READ_ONCE(d->tcf_action); if (params->flags & SKBEDIT_F_PRIORITY) skb->priority = params->priority; if (params->flags & SKBEDIT_F_INHERITDSFIELD) { |
e7e3728bd net:sched: add ac... |
41 |
int wlen = skb_network_offset(skb); |
d7bf2ebeb sched: consistent... |
42 |
switch (skb_protocol(skb, true)) { |
e7e3728bd net:sched: add ac... |
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
case htons(ETH_P_IP): wlen += sizeof(struct iphdr); if (!pskb_may_pull(skb, wlen)) goto err; skb->priority = ipv4_get_dsfield(ip_hdr(skb)) >> 2; break; case htons(ETH_P_IPV6): wlen += sizeof(struct ipv6hdr); if (!pskb_may_pull(skb, wlen)) goto err; skb->priority = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2; break; } } |
c749cdda9 net/sched: act_sk... |
58 59 60 61 62 63 |
if (params->flags & SKBEDIT_F_QUEUE_MAPPING && skb->dev->real_num_tx_queues > params->queue_mapping) skb_set_queue_mapping(skb, params->queue_mapping); if (params->flags & SKBEDIT_F_MARK) { skb->mark &= ~params->mask; skb->mark |= params->mark & params->mask; |
4fe77d82e skbedit: allow th... |
64 |
} |
c749cdda9 net/sched: act_sk... |
65 66 |
if (params->flags & SKBEDIT_F_PTYPE) skb->pkt_type = params->ptype; |
c749cdda9 net/sched: act_sk... |
67 |
return action; |
7fd4b288e tc/act: remove un... |
68 |
|
e7e3728bd net:sched: add ac... |
69 |
err: |
6f3dfb0dc net/sched: skbedi... |
70 |
qstats_drop_inc(this_cpu_ptr(d->common.cpu_qstats)); |
7fd4b288e tc/act: remove un... |
71 |
return TC_ACT_SHOT; |
ca9b0e27e pkt_action: add n... |
72 |
} |
837cb17dd sched: act_skbedi... |
73 |
static void tcf_skbedit_stats_update(struct tc_action *a, u64 bytes, |
4b61d3e8d net: qos offload ... |
74 75 |
u64 packets, u64 drops, u64 lastuse, bool hw) |
837cb17dd sched: act_skbedi... |
76 77 78 |
{ struct tcf_skbedit *d = to_skbedit(a); struct tcf_t *tm = &d->tcf_tm; |
4b61d3e8d net: qos offload ... |
79 |
tcf_action_update_stats(a, bytes, packets, drops, hw); |
837cb17dd sched: act_skbedi... |
80 81 |
tm->lastuse = max_t(u64, tm->lastuse, lastuse); } |
ca9b0e27e pkt_action: add n... |
82 83 84 85 |
static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = { [TCA_SKBEDIT_PARMS] = { .len = sizeof(struct tc_skbedit) }, [TCA_SKBEDIT_PRIORITY] = { .len = sizeof(u32) }, [TCA_SKBEDIT_QUEUE_MAPPING] = { .len = sizeof(u16) }, |
1c55d62e7 pkt_sched: skbedi... |
86 |
[TCA_SKBEDIT_MARK] = { .len = sizeof(u32) }, |
ff202ee1e net sched actions... |
87 |
[TCA_SKBEDIT_PTYPE] = { .len = sizeof(u16) }, |
4fe77d82e skbedit: allow th... |
88 |
[TCA_SKBEDIT_MASK] = { .len = sizeof(u32) }, |
e7e3728bd net:sched: add ac... |
89 |
[TCA_SKBEDIT_FLAGS] = { .len = sizeof(u64) }, |
ca9b0e27e pkt_action: add n... |
90 |
}; |
c1b52739e pkt_sched: namesp... |
91 |
static int tcf_skbedit_init(struct net *net, struct nlattr *nla, |
a85a970af net_sched: move t... |
92 |
struct nlattr *est, struct tc_action **a, |
789871bb2 net: sched: imple... |
93 |
int ovr, int bind, bool rtnl_held, |
abbb0d336 net: sched: exten... |
94 |
struct tcf_proto *tp, u32 act_flags, |
789871bb2 net: sched: imple... |
95 |
struct netlink_ext_ack *extack) |
ca9b0e27e pkt_action: add n... |
96 |
{ |
ddf97ccdd net_sched: add ne... |
97 |
struct tc_action_net *tn = net_generic(net, skbedit_net_id); |
6d7a8df6d net: sched: act_s... |
98 |
struct tcf_skbedit_params *params_new; |
ca9b0e27e pkt_action: add n... |
99 |
struct nlattr *tb[TCA_SKBEDIT_MAX + 1]; |
ec7727bb2 net/sched: act_sk... |
100 |
struct tcf_chain *goto_ch = NULL; |
ca9b0e27e pkt_action: add n... |
101 102 |
struct tc_skbedit *parm; struct tcf_skbedit *d; |
4fe77d82e skbedit: allow th... |
103 |
u32 flags = 0, *priority = NULL, *mark = NULL, *mask = NULL; |
ff202ee1e net sched actions... |
104 |
u16 *queue_mapping = NULL, *ptype = NULL; |
b2313077e net_sched: make t... |
105 106 |
bool exists = false; int ret = 0, err; |
7be8ef2cd net: sched: use t... |
107 |
u32 index; |
ca9b0e27e pkt_action: add n... |
108 109 110 |
if (nla == NULL) return -EINVAL; |
8cb081746 netlink: make val... |
111 112 |
err = nla_parse_nested_deprecated(tb, TCA_SKBEDIT_MAX, nla, skbedit_policy, NULL); |
ca9b0e27e pkt_action: add n... |
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
if (err < 0) return err; if (tb[TCA_SKBEDIT_PARMS] == NULL) return -EINVAL; if (tb[TCA_SKBEDIT_PRIORITY] != NULL) { flags |= SKBEDIT_F_PRIORITY; priority = nla_data(tb[TCA_SKBEDIT_PRIORITY]); } if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) { flags |= SKBEDIT_F_QUEUE_MAPPING; queue_mapping = nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING]); } |
1c55d62e7 pkt_sched: skbedi... |
128 |
|
ff202ee1e net sched actions... |
129 130 131 132 133 134 |
if (tb[TCA_SKBEDIT_PTYPE] != NULL) { ptype = nla_data(tb[TCA_SKBEDIT_PTYPE]); if (!skb_pkt_type_ok(*ptype)) return -EINVAL; flags |= SKBEDIT_F_PTYPE; } |
1c55d62e7 pkt_sched: skbedi... |
135 136 137 138 |
if (tb[TCA_SKBEDIT_MARK] != NULL) { flags |= SKBEDIT_F_MARK; mark = nla_data(tb[TCA_SKBEDIT_MARK]); } |
4fe77d82e skbedit: allow th... |
139 140 141 142 |
if (tb[TCA_SKBEDIT_MASK] != NULL) { flags |= SKBEDIT_F_MASK; mask = nla_data(tb[TCA_SKBEDIT_MASK]); } |
e7e3728bd net:sched: add ac... |
143 144 145 146 147 148 |
if (tb[TCA_SKBEDIT_FLAGS] != NULL) { u64 *pure_flags = nla_data(tb[TCA_SKBEDIT_FLAGS]); if (*pure_flags & SKBEDIT_F_INHERITDSFIELD) flags |= SKBEDIT_F_INHERITDSFIELD; } |
ca9b0e27e pkt_action: add n... |
149 |
parm = nla_data(tb[TCA_SKBEDIT_PARMS]); |
7be8ef2cd net: sched: use t... |
150 151 |
index = parm->index; err = tcf_idr_check_alloc(tn, &index, a, bind); |
0190c1d45 net: sched: atomi... |
152 153 154 |
if (err < 0) return err; exists = err; |
5e1567aeb net sched: skbedi... |
155 156 157 158 |
if (exists && bind) return 0; if (!flags) { |
af5d01842 net sched actions... |
159 160 |
if (exists) tcf_idr_release(*a, bind); |
0190c1d45 net: sched: atomi... |
161 |
else |
7be8ef2cd net: sched: use t... |
162 |
tcf_idr_cleanup(tn, index); |
5e1567aeb net sched: skbedi... |
163 164 165 166 |
return -EINVAL; } if (!exists) { |
7be8ef2cd net: sched: use t... |
167 |
ret = tcf_idr_create(tn, index, est, a, |
e38226786 net: sched: updat... |
168 |
&act_skbedit_ops, bind, true, 0); |
0190c1d45 net: sched: atomi... |
169 |
if (ret) { |
7be8ef2cd net: sched: use t... |
170 |
tcf_idr_cleanup(tn, index); |
86062033f net_sched: act: h... |
171 |
return ret; |
0190c1d45 net: sched: atomi... |
172 |
} |
ca9b0e27e pkt_action: add n... |
173 |
|
a85a970af net_sched: move t... |
174 |
d = to_skbedit(*a); |
ca9b0e27e pkt_action: add n... |
175 176 |
ret = ACT_P_CREATED; } else { |
a85a970af net_sched: move t... |
177 |
d = to_skbedit(*a); |
4e8ddd7f1 net: sched: don't... |
178 179 |
if (!ovr) { tcf_idr_release(*a, bind); |
ca9b0e27e pkt_action: add n... |
180 |
return -EEXIST; |
4e8ddd7f1 net: sched: don't... |
181 |
} |
ca9b0e27e pkt_action: add n... |
182 |
} |
ec7727bb2 net/sched: act_sk... |
183 184 185 |
err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); if (err < 0) goto release_idr; |
ca9b0e27e pkt_action: add n... |
186 |
|
c749cdda9 net/sched: act_sk... |
187 188 |
params_new = kzalloc(sizeof(*params_new), GFP_KERNEL); if (unlikely(!params_new)) { |
ec7727bb2 net/sched: act_sk... |
189 190 |
err = -ENOMEM; goto put_chain; |
c749cdda9 net/sched: act_sk... |
191 192 193 |
} params_new->flags = flags; |
ca9b0e27e pkt_action: add n... |
194 |
if (flags & SKBEDIT_F_PRIORITY) |
c749cdda9 net/sched: act_sk... |
195 |
params_new->priority = *priority; |
ca9b0e27e pkt_action: add n... |
196 |
if (flags & SKBEDIT_F_QUEUE_MAPPING) |
c749cdda9 net/sched: act_sk... |
197 |
params_new->queue_mapping = *queue_mapping; |
1c55d62e7 pkt_sched: skbedi... |
198 |
if (flags & SKBEDIT_F_MARK) |
c749cdda9 net/sched: act_sk... |
199 |
params_new->mark = *mark; |
ff202ee1e net sched actions... |
200 |
if (flags & SKBEDIT_F_PTYPE) |
c749cdda9 net/sched: act_sk... |
201 |
params_new->ptype = *ptype; |
4fe77d82e skbedit: allow th... |
202 |
/* default behaviour is to use all the bits */ |
c749cdda9 net/sched: act_sk... |
203 |
params_new->mask = 0xffffffff; |
4fe77d82e skbedit: allow th... |
204 |
if (flags & SKBEDIT_F_MASK) |
c749cdda9 net/sched: act_sk... |
205 |
params_new->mask = *mask; |
1c55d62e7 pkt_sched: skbedi... |
206 |
|
6d7a8df6d net: sched: act_s... |
207 |
spin_lock_bh(&d->tcf_lock); |
ec7727bb2 net/sched: act_sk... |
208 |
goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); |
445d37493 net/sched: Replac... |
209 210 |
params_new = rcu_replace_pointer(d->params, params_new, lockdep_is_held(&d->tcf_lock)); |
6d7a8df6d net: sched: act_s... |
211 212 213 |
spin_unlock_bh(&d->tcf_lock); if (params_new) kfree_rcu(params_new, rcu); |
ec7727bb2 net/sched: act_sk... |
214 215 |
if (goto_ch) tcf_chain_put_by_act(goto_ch); |
ca9b0e27e pkt_action: add n... |
216 |
|
ca9b0e27e pkt_action: add n... |
217 |
return ret; |
ec7727bb2 net/sched: act_sk... |
218 219 220 221 222 223 |
put_chain: if (goto_ch) tcf_chain_put_by_act(goto_ch); release_idr: tcf_idr_release(*a, bind); return err; |
ca9b0e27e pkt_action: add n... |
224 |
} |
cc7ec456f net_sched: cleanups |
225 226 |
static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) |
ca9b0e27e pkt_action: add n... |
227 228 |
{ unsigned char *b = skb_tail_pointer(skb); |
a85a970af net_sched: move t... |
229 |
struct tcf_skbedit *d = to_skbedit(a); |
c749cdda9 net/sched: act_sk... |
230 |
struct tcf_skbedit_params *params; |
1c40be12f net sched: fix so... |
231 232 |
struct tc_skbedit opt = { .index = d->tcf_index, |
036bb4432 net: sched: chang... |
233 234 |
.refcnt = refcount_read(&d->tcf_refcnt) - ref, .bindcnt = atomic_read(&d->tcf_bindcnt) - bind, |
1c40be12f net sched: fix so... |
235 |
}; |
e7e3728bd net:sched: add ac... |
236 |
u64 pure_flags = 0; |
c749cdda9 net/sched: act_sk... |
237 |
struct tcf_t t; |
6d7a8df6d net: sched: act_s... |
238 239 240 241 |
spin_lock_bh(&d->tcf_lock); params = rcu_dereference_protected(d->params, lockdep_is_held(&d->tcf_lock)); opt.action = d->tcf_action; |
ca9b0e27e pkt_action: add n... |
242 |
|
1b34ec43c pkt_sched: Stop u... |
243 244 |
if (nla_put(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt)) goto nla_put_failure; |
c749cdda9 net/sched: act_sk... |
245 246 |
if ((params->flags & SKBEDIT_F_PRIORITY) && nla_put_u32(skb, TCA_SKBEDIT_PRIORITY, params->priority)) |
1b34ec43c pkt_sched: Stop u... |
247 |
goto nla_put_failure; |
c749cdda9 net/sched: act_sk... |
248 249 |
if ((params->flags & SKBEDIT_F_QUEUE_MAPPING) && nla_put_u16(skb, TCA_SKBEDIT_QUEUE_MAPPING, params->queue_mapping)) |
1b34ec43c pkt_sched: Stop u... |
250 |
goto nla_put_failure; |
c749cdda9 net/sched: act_sk... |
251 252 |
if ((params->flags & SKBEDIT_F_MARK) && nla_put_u32(skb, TCA_SKBEDIT_MARK, params->mark)) |
1b34ec43c pkt_sched: Stop u... |
253 |
goto nla_put_failure; |
c749cdda9 net/sched: act_sk... |
254 255 |
if ((params->flags & SKBEDIT_F_PTYPE) && nla_put_u16(skb, TCA_SKBEDIT_PTYPE, params->ptype)) |
ff202ee1e net sched actions... |
256 |
goto nla_put_failure; |
c749cdda9 net/sched: act_sk... |
257 258 |
if ((params->flags & SKBEDIT_F_MASK) && nla_put_u32(skb, TCA_SKBEDIT_MASK, params->mask)) |
4fe77d82e skbedit: allow th... |
259 |
goto nla_put_failure; |
c749cdda9 net/sched: act_sk... |
260 |
if (params->flags & SKBEDIT_F_INHERITDSFIELD) |
e7e3728bd net:sched: add ac... |
261 262 263 264 |
pure_flags |= SKBEDIT_F_INHERITDSFIELD; if (pure_flags != 0 && nla_put(skb, TCA_SKBEDIT_FLAGS, sizeof(pure_flags), &pure_flags)) goto nla_put_failure; |
48d8ee169 net sched actions... |
265 266 |
tcf_tm_dump(&t, &d->tcf_tm); |
9854518ea sched: align nlat... |
267 |
if (nla_put_64bit(skb, TCA_SKBEDIT_TM, sizeof(t), &t, TCA_SKBEDIT_PAD)) |
1b34ec43c pkt_sched: Stop u... |
268 |
goto nla_put_failure; |
6d7a8df6d net: sched: act_s... |
269 |
spin_unlock_bh(&d->tcf_lock); |
ca9b0e27e pkt_action: add n... |
270 271 272 |
return skb->len; nla_put_failure: |
6d7a8df6d net: sched: act_s... |
273 |
spin_unlock_bh(&d->tcf_lock); |
ca9b0e27e pkt_action: add n... |
274 275 276 |
nlmsg_trim(skb, b); return -1; } |
c749cdda9 net/sched: act_sk... |
277 278 279 280 281 282 283 284 285 |
static void tcf_skbedit_cleanup(struct tc_action *a) { struct tcf_skbedit *d = to_skbedit(a); struct tcf_skbedit_params *params; params = rcu_dereference_protected(d->params, 1); if (params) kfree_rcu(params, rcu); } |
ddf97ccdd net_sched: add ne... |
286 287 |
static int tcf_skbedit_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, |
417801055 net: sched: act: ... |
288 289 |
const struct tc_action_ops *ops, struct netlink_ext_ack *extack) |
ddf97ccdd net_sched: add ne... |
290 291 |
{ struct tc_action_net *tn = net_generic(net, skbedit_net_id); |
b36201455 net: sched: act: ... |
292 |
return tcf_generic_walker(tn, skb, cb, type, ops, extack); |
ddf97ccdd net_sched: add ne... |
293 |
} |
f061b48c1 Revert "net: sche... |
294 |
static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index) |
ddf97ccdd net_sched: add ne... |
295 296 |
{ struct tc_action_net *tn = net_generic(net, skbedit_net_id); |
65a206c01 net/sched: Change... |
297 |
return tcf_idr_search(tn, a, index); |
ddf97ccdd net_sched: add ne... |
298 |
} |
e1fea322f net sched: update... |
299 300 301 302 303 304 305 306 307 308 |
static size_t tcf_skbedit_get_fill_size(const struct tc_action *act) { return nla_total_size(sizeof(struct tc_skbedit)) + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_PRIORITY */ + nla_total_size(sizeof(u16)) /* TCA_SKBEDIT_QUEUE_MAPPING */ + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_MARK */ + nla_total_size(sizeof(u16)) /* TCA_SKBEDIT_PTYPE */ + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_MASK */ + nla_total_size_64bit(sizeof(u64)); /* TCA_SKBEDIT_FLAGS */ } |
ca9b0e27e pkt_action: add n... |
309 310 |
static struct tc_action_ops act_skbedit_ops = { .kind = "skbedit", |
eddd2cf19 net: Change TCA_A... |
311 |
.id = TCA_ID_SKBEDIT, |
ca9b0e27e pkt_action: add n... |
312 |
.owner = THIS_MODULE, |
45da1dac6 net: sched: act_s... |
313 |
.act = tcf_skbedit_act, |
837cb17dd sched: act_skbedi... |
314 |
.stats_update = tcf_skbedit_stats_update, |
ca9b0e27e pkt_action: add n... |
315 |
.dump = tcf_skbedit_dump, |
ca9b0e27e pkt_action: add n... |
316 |
.init = tcf_skbedit_init, |
c749cdda9 net/sched: act_sk... |
317 |
.cleanup = tcf_skbedit_cleanup, |
ddf97ccdd net_sched: add ne... |
318 |
.walk = tcf_skbedit_walker, |
e1fea322f net sched: update... |
319 |
.get_fill_size = tcf_skbedit_get_fill_size, |
ddf97ccdd net_sched: add ne... |
320 |
.lookup = tcf_skbedit_search, |
a85a970af net_sched: move t... |
321 |
.size = sizeof(struct tcf_skbedit), |
ddf97ccdd net_sched: add ne... |
322 323 324 325 326 |
}; static __net_init int skbedit_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, skbedit_net_id); |
981471bd3 net_sched: fix a ... |
327 |
return tc_action_net_init(net, tn, &act_skbedit_ops); |
ddf97ccdd net_sched: add ne... |
328 |
} |
039af9c66 net_sched: switch... |
329 |
static void __net_exit skbedit_exit_net(struct list_head *net_list) |
ddf97ccdd net_sched: add ne... |
330 |
{ |
039af9c66 net_sched: switch... |
331 |
tc_action_net_exit(net_list, skbedit_net_id); |
ddf97ccdd net_sched: add ne... |
332 333 334 335 |
} static struct pernet_operations skbedit_net_ops = { .init = skbedit_init_net, |
039af9c66 net_sched: switch... |
336 |
.exit_batch = skbedit_exit_net, |
ddf97ccdd net_sched: add ne... |
337 338 |
.id = &skbedit_net_id, .size = sizeof(struct tc_action_net), |
ca9b0e27e pkt_action: add n... |
339 340 341 342 343 344 345 346 |
}; MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>"); MODULE_DESCRIPTION("SKB Editing"); MODULE_LICENSE("GPL"); static int __init skbedit_init_module(void) { |
ddf97ccdd net_sched: add ne... |
347 |
return tcf_register_action(&act_skbedit_ops, &skbedit_net_ops); |
ca9b0e27e pkt_action: add n... |
348 349 350 351 |
} static void __exit skbedit_cleanup_module(void) { |
ddf97ccdd net_sched: add ne... |
352 |
tcf_unregister_action(&act_skbedit_ops, &skbedit_net_ops); |
ca9b0e27e pkt_action: add n... |
353 354 355 356 |
} module_init(skbedit_init_module); module_exit(skbedit_cleanup_module); |