hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/net/sched/act_vlan.c
....@@ -1,10 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
3
- *
4
- * This program is free software; you can redistribute it and/or modify
5
- * it under the terms of the GNU General Public License as published by
6
- * the Free Software Foundation; either version 2 of the License, or
7
- * (at your option) any later version.
84 */
95
106 #include <linux/module.h>
....@@ -15,6 +11,7 @@
1511 #include <linux/if_vlan.h>
1612 #include <net/netlink.h>
1713 #include <net/pkt_sched.h>
14
+#include <net/pkt_cls.h>
1815
1916 #include <linux/tc_act/tc_vlan.h>
2017 #include <net/tc_act/tc_vlan.h>
....@@ -32,7 +29,7 @@
3229 u16 tci;
3330
3431 tcf_lastuse_update(&v->tcf_tm);
35
- bstats_cpu_update(this_cpu_ptr(v->common.cpu_bstats), skb);
32
+ tcf_action_update_bstats(&v->common, skb);
3633
3734 /* Ensure 'data' points at mac_header prior calling vlan manipulating
3835 * functions.
....@@ -63,7 +60,7 @@
6360 /* extract existing tag (and guarantee no hw-accel tag) */
6461 if (skb_vlan_tag_present(skb)) {
6562 tci = skb_vlan_tag_get(skb);
66
- skb->vlan_tci = 0;
63
+ __vlan_hwaccel_clear_tag(skb);
6764 } else {
6865 /* in-payload vlan tag, pop it */
6966 err = __skb_vlan_pop(skb, &tci);
....@@ -73,12 +70,22 @@
7370 /* replace the vid */
7471 tci = (tci & ~VLAN_VID_MASK) | p->tcfv_push_vid;
7572 /* replace prio bits, if tcfv_push_prio specified */
76
- if (p->tcfv_push_prio) {
73
+ if (p->tcfv_push_prio_exists) {
7774 tci &= ~VLAN_PRIO_MASK;
7875 tci |= p->tcfv_push_prio << VLAN_PRIO_SHIFT;
7976 }
8077 /* put updated tci as hwaccel tag */
8178 __vlan_hwaccel_put_tag(skb, p->tcfv_push_proto, tci);
79
+ break;
80
+ case TCA_VLAN_ACT_POP_ETH:
81
+ err = skb_eth_pop(skb);
82
+ if (err)
83
+ goto drop;
84
+ break;
85
+ case TCA_VLAN_ACT_PUSH_ETH:
86
+ err = skb_eth_push(skb, p->tcfv_push_dst, p->tcfv_push_src);
87
+ if (err)
88
+ goto drop;
8289 break;
8390 default:
8491 BUG();
....@@ -91,24 +98,30 @@
9198 return action;
9299
93100 drop:
94
- qstats_drop_inc(this_cpu_ptr(v->common.cpu_qstats));
101
+ tcf_action_inc_drop_qstats(&v->common);
95102 return TC_ACT_SHOT;
96103 }
97104
98105 static const struct nla_policy vlan_policy[TCA_VLAN_MAX + 1] = {
106
+ [TCA_VLAN_UNSPEC] = { .strict_start_type = TCA_VLAN_PUSH_ETH_DST },
99107 [TCA_VLAN_PARMS] = { .len = sizeof(struct tc_vlan) },
100108 [TCA_VLAN_PUSH_VLAN_ID] = { .type = NLA_U16 },
101109 [TCA_VLAN_PUSH_VLAN_PROTOCOL] = { .type = NLA_U16 },
102110 [TCA_VLAN_PUSH_VLAN_PRIORITY] = { .type = NLA_U8 },
111
+ [TCA_VLAN_PUSH_ETH_DST] = NLA_POLICY_ETH_ADDR,
112
+ [TCA_VLAN_PUSH_ETH_SRC] = NLA_POLICY_ETH_ADDR,
103113 };
104114
105115 static int tcf_vlan_init(struct net *net, struct nlattr *nla,
106116 struct nlattr *est, struct tc_action **a,
107117 int ovr, int bind, bool rtnl_held,
118
+ struct tcf_proto *tp, u32 flags,
108119 struct netlink_ext_ack *extack)
109120 {
110121 struct tc_action_net *tn = net_generic(net, vlan_net_id);
111122 struct nlattr *tb[TCA_VLAN_MAX + 1];
123
+ struct tcf_chain *goto_ch = NULL;
124
+ bool push_prio_exists = false;
112125 struct tcf_vlan_params *p;
113126 struct tc_vlan *parm;
114127 struct tcf_vlan *v;
....@@ -123,7 +136,8 @@
123136 if (!nla)
124137 return -EINVAL;
125138
126
- err = nla_parse_nested(tb, TCA_VLAN_MAX, nla, vlan_policy, NULL);
139
+ err = nla_parse_nested_deprecated(tb, TCA_VLAN_MAX, nla, vlan_policy,
140
+ NULL);
127141 if (err < 0)
128142 return err;
129143
....@@ -176,8 +190,20 @@
176190 push_proto = htons(ETH_P_8021Q);
177191 }
178192
179
- if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY])
193
+ push_prio_exists = !!tb[TCA_VLAN_PUSH_VLAN_PRIORITY];
194
+ if (push_prio_exists)
180195 push_prio = nla_get_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]);
196
+ break;
197
+ case TCA_VLAN_ACT_POP_ETH:
198
+ break;
199
+ case TCA_VLAN_ACT_PUSH_ETH:
200
+ if (!tb[TCA_VLAN_PUSH_ETH_DST] || !tb[TCA_VLAN_PUSH_ETH_SRC]) {
201
+ if (exists)
202
+ tcf_idr_release(*a, bind);
203
+ else
204
+ tcf_idr_cleanup(tn, index);
205
+ return -EINVAL;
206
+ }
181207 break;
182208 default:
183209 if (exists)
....@@ -189,8 +215,8 @@
189215 action = parm->v_action;
190216
191217 if (!exists) {
192
- ret = tcf_idr_create(tn, index, est, a,
193
- &act_vlan_ops, bind, true);
218
+ ret = tcf_idr_create_from_flags(tn, index, est, a,
219
+ &act_vlan_ops, bind, flags);
194220 if (ret) {
195221 tcf_idr_cleanup(tn, index);
196222 return ret;
....@@ -202,30 +228,48 @@
202228 return -EEXIST;
203229 }
204230
231
+ err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
232
+ if (err < 0)
233
+ goto release_idr;
234
+
205235 v = to_vlan(*a);
206236
207237 p = kzalloc(sizeof(*p), GFP_KERNEL);
208238 if (!p) {
209
- tcf_idr_release(*a, bind);
210
- return -ENOMEM;
239
+ err = -ENOMEM;
240
+ goto put_chain;
211241 }
212242
213243 p->tcfv_action = action;
214244 p->tcfv_push_vid = push_vid;
215245 p->tcfv_push_prio = push_prio;
246
+ p->tcfv_push_prio_exists = push_prio_exists || action == TCA_VLAN_ACT_PUSH;
216247 p->tcfv_push_proto = push_proto;
217248
249
+ if (action == TCA_VLAN_ACT_PUSH_ETH) {
250
+ nla_memcpy(&p->tcfv_push_dst, tb[TCA_VLAN_PUSH_ETH_DST],
251
+ ETH_ALEN);
252
+ nla_memcpy(&p->tcfv_push_src, tb[TCA_VLAN_PUSH_ETH_SRC],
253
+ ETH_ALEN);
254
+ }
255
+
218256 spin_lock_bh(&v->tcf_lock);
219
- v->tcf_action = parm->action;
220
- rcu_swap_protected(v->vlan_p, p, lockdep_is_held(&v->tcf_lock));
257
+ goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
258
+ p = rcu_replace_pointer(v->vlan_p, p, lockdep_is_held(&v->tcf_lock));
221259 spin_unlock_bh(&v->tcf_lock);
222260
261
+ if (goto_ch)
262
+ tcf_chain_put_by_act(goto_ch);
223263 if (p)
224264 kfree_rcu(p, rcu);
225265
226
- if (ret == ACT_P_CREATED)
227
- tcf_idr_insert(tn, *a);
228266 return ret;
267
+put_chain:
268
+ if (goto_ch)
269
+ tcf_chain_put_by_act(goto_ch);
270
+release_idr:
271
+ tcf_idr_release(*a, bind);
272
+ return err;
229273 }
230274
231275 static void tcf_vlan_cleanup(struct tc_action *a)
....@@ -267,6 +311,15 @@
267311 p->tcfv_push_prio))))
268312 goto nla_put_failure;
269313
314
+ if (p->tcfv_action == TCA_VLAN_ACT_PUSH_ETH) {
315
+ if (nla_put(skb, TCA_VLAN_PUSH_ETH_DST, ETH_ALEN,
316
+ p->tcfv_push_dst))
317
+ goto nla_put_failure;
318
+ if (nla_put(skb, TCA_VLAN_PUSH_ETH_SRC, ETH_ALEN,
319
+ p->tcfv_push_src))
320
+ goto nla_put_failure;
321
+ }
322
+
270323 tcf_tm_dump(&t, &v->tcf_tm);
271324 if (nla_put_64bit(skb, TCA_VLAN_TM, sizeof(t), &t, TCA_VLAN_PAD))
272325 goto nla_put_failure;
....@@ -290,8 +343,17 @@
290343 return tcf_generic_walker(tn, skb, cb, type, ops, extack);
291344 }
292345
293
-static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index,
294
- struct netlink_ext_ack *extack)
346
+static void tcf_vlan_stats_update(struct tc_action *a, u64 bytes, u64 packets,
347
+ u64 drops, u64 lastuse, bool hw)
348
+{
349
+ struct tcf_vlan *v = to_vlan(a);
350
+ struct tcf_t *tm = &v->tcf_tm;
351
+
352
+ tcf_action_update_stats(a, bytes, packets, drops, hw);
353
+ tm->lastuse = max_t(u64, tm->lastuse, lastuse);
354
+}
355
+
356
+static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index)
295357 {
296358 struct tc_action_net *tn = net_generic(net, vlan_net_id);
297359
....@@ -308,13 +370,14 @@
308370
309371 static struct tc_action_ops act_vlan_ops = {
310372 .kind = "vlan",
311
- .type = TCA_ACT_VLAN,
373
+ .id = TCA_ID_VLAN,
312374 .owner = THIS_MODULE,
313375 .act = tcf_vlan_act,
314376 .dump = tcf_vlan_dump,
315377 .init = tcf_vlan_init,
316378 .cleanup = tcf_vlan_cleanup,
317379 .walk = tcf_vlan_walker,
380
+ .stats_update = tcf_vlan_stats_update,
318381 .get_fill_size = tcf_vlan_get_fill_size,
319382 .lookup = tcf_vlan_search,
320383 .size = sizeof(struct tcf_vlan),