forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/net/sched/act_mirred.c
....@@ -1,15 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * net/sched/act_mirred.c packet mirroring and redirect actions
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: Jamal Hadi Salim (2002-4)
106 *
117 * TODO: Add ingress support (and socket redirect support)
12
- *
138 */
149
1510 #include <linux/types.h>
....@@ -24,6 +19,7 @@
2419 #include <linux/if_arp.h>
2520 #include <net/net_namespace.h>
2621 #include <net/netlink.h>
22
+#include <net/dst.h>
2723 #include <net/pkt_sched.h>
2824 #include <net/pkt_cls.h>
2925 #include <linux/tc_act/tc_mirred.h>
....@@ -31,6 +27,9 @@
3127
3228 static LIST_HEAD(mirred_list);
3329 static DEFINE_SPINLOCK(mirred_list_lock);
30
+
31
+#define MIRRED_RECURSION_LIMIT 4
32
+static DEFINE_PER_CPU(unsigned int, mirred_rec_level);
3433
3534 static bool tcf_mirred_is_act_redirect(int action)
3635 {
....@@ -94,10 +93,12 @@
9493 static int tcf_mirred_init(struct net *net, struct nlattr *nla,
9594 struct nlattr *est, struct tc_action **a,
9695 int ovr, int bind, bool rtnl_held,
97
- struct netlink_ext_ack *extack)
96
+ struct tcf_proto *tp,
97
+ u32 flags, struct netlink_ext_ack *extack)
9898 {
9999 struct tc_action_net *tn = net_generic(net, mirred_net_id);
100100 struct nlattr *tb[TCA_MIRRED_MAX + 1];
101
+ struct tcf_chain *goto_ch = NULL;
101102 bool mac_header_xmit = false;
102103 struct tc_mirred *parm;
103104 struct tcf_mirred *m;
....@@ -110,7 +111,8 @@
110111 NL_SET_ERR_MSG_MOD(extack, "Mirred requires attributes to be passed");
111112 return -EINVAL;
112113 }
113
- ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy, extack);
114
+ ret = nla_parse_nested_deprecated(tb, TCA_MIRRED_MAX, nla,
115
+ mirred_policy, extack);
114116 if (ret < 0)
115117 return ret;
116118 if (!tb[TCA_MIRRED_PARMS]) {
....@@ -147,8 +149,8 @@
147149 NL_SET_ERR_MSG_MOD(extack, "Specified device does not exist");
148150 return -EINVAL;
149151 }
150
- ret = tcf_idr_create(tn, index, est, a,
151
- &act_mirred_ops, bind, true);
152
+ ret = tcf_idr_create_from_flags(tn, index, est, a,
153
+ &act_mirred_ops, bind, flags);
152154 if (ret) {
153155 tcf_idr_cleanup(tn, index);
154156 return ret;
....@@ -158,40 +160,50 @@
158160 tcf_idr_release(*a, bind);
159161 return -EEXIST;
160162 }
161
- m = to_mirred(*a);
162163
164
+ m = to_mirred(*a);
163165 if (ret == ACT_P_CREATED)
164166 INIT_LIST_HEAD(&m->tcfm_list);
165167
168
+ err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
169
+ if (err < 0)
170
+ goto release_idr;
171
+
166172 spin_lock_bh(&m->tcf_lock);
167
- m->tcf_action = parm->action;
168
- m->tcfm_eaction = parm->eaction;
169173
170174 if (parm->ifindex) {
171175 dev = dev_get_by_index(net, parm->ifindex);
172176 if (!dev) {
173177 spin_unlock_bh(&m->tcf_lock);
174
- tcf_idr_release(*a, bind);
175
- return -ENODEV;
178
+ err = -ENODEV;
179
+ goto put_chain;
176180 }
177181 mac_header_xmit = dev_is_mac_header_xmit(dev);
178
- rcu_swap_protected(m->tcfm_dev, dev,
179
- lockdep_is_held(&m->tcf_lock));
182
+ dev = rcu_replace_pointer(m->tcfm_dev, dev,
183
+ lockdep_is_held(&m->tcf_lock));
180184 if (dev)
181185 dev_put(dev);
182186 m->tcfm_mac_header_xmit = mac_header_xmit;
183187 }
188
+ goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
189
+ m->tcfm_eaction = parm->eaction;
184190 spin_unlock_bh(&m->tcf_lock);
191
+ if (goto_ch)
192
+ tcf_chain_put_by_act(goto_ch);
185193
186194 if (ret == ACT_P_CREATED) {
187195 spin_lock(&mirred_list_lock);
188196 list_add(&m->tcfm_list, &mirred_list);
189197 spin_unlock(&mirred_list_lock);
190
-
191
- tcf_idr_insert(tn, *a);
192198 }
193199
194200 return ret;
201
+put_chain:
202
+ if (goto_ch)
203
+ tcf_chain_put_by_act(goto_ch);
204
+release_idr:
205
+ tcf_idr_release(*a, bind);
206
+ return err;
195207 }
196208
197209 static int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a,
....@@ -201,15 +213,27 @@
201213 struct sk_buff *skb2 = skb;
202214 bool m_mac_header_xmit;
203215 struct net_device *dev;
216
+ unsigned int rec_level;
204217 int retval, err = 0;
205218 bool use_reinsert;
206219 bool want_ingress;
207220 bool is_redirect;
221
+ bool expects_nh;
222
+ bool at_ingress;
208223 int m_eaction;
209224 int mac_len;
225
+ bool at_nh;
226
+
227
+ rec_level = __this_cpu_inc_return(mirred_rec_level);
228
+ if (unlikely(rec_level > MIRRED_RECURSION_LIMIT)) {
229
+ net_warn_ratelimited("Packet exceeded mirred recursion limit on dev %s\n",
230
+ netdev_name(skb->dev));
231
+ __this_cpu_dec(mirred_rec_level);
232
+ return TC_ACT_SHOT;
233
+ }
210234
211235 tcf_lastuse_update(&m->tcf_tm);
212
- bstats_cpu_update(this_cpu_ptr(m->common.cpu_bstats), skb);
236
+ tcf_action_update_bstats(&m->common, skb);
213237
214238 m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit);
215239 m_eaction = READ_ONCE(m->tcfm_eaction);
....@@ -231,7 +255,8 @@
231255 * ingress - that covers the TC S/W datapath.
232256 */
233257 is_redirect = tcf_mirred_is_act_redirect(m_eaction);
234
- use_reinsert = skb_at_tc_ingress(skb) && is_redirect &&
258
+ at_ingress = skb_at_tc_ingress(skb);
259
+ use_reinsert = at_ingress && is_redirect &&
235260 tcf_mirred_can_reinsert(retval);
236261 if (!use_reinsert) {
237262 skb2 = skb_clone(skb, GFP_ATOMIC);
....@@ -239,19 +264,24 @@
239264 goto out;
240265 }
241266
242
- /* If action's target direction differs than filter's direction,
243
- * and devices expect a mac header on xmit, then mac push/pull is
244
- * needed.
245
- */
246267 want_ingress = tcf_mirred_act_wants_ingress(m_eaction);
247
- if (skb_at_tc_ingress(skb) != want_ingress && m_mac_header_xmit) {
248
- if (!skb_at_tc_ingress(skb)) {
249
- /* caught at egress, act ingress: pull mac */
250
- mac_len = skb_network_header(skb) - skb_mac_header(skb);
268
+
269
+ /* All mirred/redirected skbs should clear previous ct info */
270
+ nf_reset_ct(skb2);
271
+ if (want_ingress && !at_ingress) /* drop dst for egress -> ingress */
272
+ skb_dst_drop(skb2);
273
+
274
+ expects_nh = want_ingress || !m_mac_header_xmit;
275
+ at_nh = skb->data == skb_network_header(skb);
276
+ if (at_nh != expects_nh) {
277
+ mac_len = skb_at_tc_ingress(skb) ? skb->mac_len :
278
+ skb_network_header(skb) - skb_mac_header(skb);
279
+ if (expects_nh) {
280
+ /* target device/action expect data at nh */
251281 skb_pull_rcsum(skb2, mac_len);
252282 } else {
253
- /* caught at ingress, act egress: push mac */
254
- skb_push_rcsum(skb2, skb->mac_len);
283
+ /* target device/action expect data at mac */
284
+ skb_push_rcsum(skb2, mac_len);
255285 }
256286 }
257287
....@@ -260,14 +290,15 @@
260290
261291 /* mirror is always swallowed */
262292 if (is_redirect) {
263
- skb2->tc_redirected = 1;
264
- skb2->tc_from_ingress = skb2->tc_at_ingress;
293
+ skb_set_redirected(skb2, skb2->tc_at_ingress);
265294
266295 /* let's the caller reinsert the packet, if possible */
267296 if (use_reinsert) {
268297 res->ingress = want_ingress;
269
- res->qstats = this_cpu_ptr(m->common.cpu_qstats);
270
- return TC_ACT_REINSERT;
298
+ if (skb_tc_reinsert(skb, res))
299
+ tcf_action_inc_overlimit_qstats(&m->common);
300
+ __this_cpu_dec(mirred_rec_level);
301
+ return TC_ACT_CONSUMED;
271302 }
272303 }
273304
....@@ -278,21 +309,22 @@
278309
279310 if (err) {
280311 out:
281
- qstats_overlimit_inc(this_cpu_ptr(m->common.cpu_qstats));
312
+ tcf_action_inc_overlimit_qstats(&m->common);
282313 if (tcf_mirred_is_act_redirect(m_eaction))
283314 retval = TC_ACT_SHOT;
284315 }
316
+ __this_cpu_dec(mirred_rec_level);
285317
286318 return retval;
287319 }
288320
289
-static void tcf_stats_update(struct tc_action *a, u64 bytes, u32 packets,
290
- u64 lastuse)
321
+static void tcf_stats_update(struct tc_action *a, u64 bytes, u64 packets,
322
+ u64 drops, u64 lastuse, bool hw)
291323 {
292324 struct tcf_mirred *m = to_mirred(a);
293325 struct tcf_t *tm = &m->tcf_tm;
294326
295
- _bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), bytes, packets);
327
+ tcf_action_update_stats(a, bytes, packets, drops, hw);
296328 tm->lastuse = max_t(u64, tm->lastuse, lastuse);
297329 }
298330
....@@ -342,8 +374,7 @@
342374 return tcf_generic_walker(tn, skb, cb, type, ops, extack);
343375 }
344376
345
-static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index,
346
- struct netlink_ext_ack *extack)
377
+static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index)
347378 {
348379 struct tc_action_net *tn = net_generic(net, mirred_net_id);
349380
....@@ -380,28 +411,39 @@
380411 .notifier_call = mirred_device_event,
381412 };
382413
383
-static struct net_device *tcf_mirred_get_dev(const struct tc_action *a)
414
+static void tcf_mirred_dev_put(void *priv)
415
+{
416
+ struct net_device *dev = priv;
417
+
418
+ dev_put(dev);
419
+}
420
+
421
+static struct net_device *
422
+tcf_mirred_get_dev(const struct tc_action *a,
423
+ tc_action_priv_destructor *destructor)
384424 {
385425 struct tcf_mirred *m = to_mirred(a);
386426 struct net_device *dev;
387427
388428 rcu_read_lock();
389429 dev = rcu_dereference(m->tcfm_dev);
390
- if (dev)
430
+ if (dev) {
391431 dev_hold(dev);
432
+ *destructor = tcf_mirred_dev_put;
433
+ }
392434 rcu_read_unlock();
393435
394436 return dev;
395437 }
396438
397
-static void tcf_mirred_put_dev(struct net_device *dev)
439
+static size_t tcf_mirred_get_fill_size(const struct tc_action *act)
398440 {
399
- dev_put(dev);
441
+ return nla_total_size(sizeof(struct tc_mirred));
400442 }
401443
402444 static struct tc_action_ops act_mirred_ops = {
403445 .kind = "mirred",
404
- .type = TCA_ACT_MIRRED,
446
+ .id = TCA_ID_MIRRED,
405447 .owner = THIS_MODULE,
406448 .act = tcf_mirred_act,
407449 .stats_update = tcf_stats_update,
....@@ -410,9 +452,9 @@
410452 .init = tcf_mirred_init,
411453 .walk = tcf_mirred_walker,
412454 .lookup = tcf_mirred_search,
455
+ .get_fill_size = tcf_mirred_get_fill_size,
413456 .size = sizeof(struct tcf_mirred),
414457 .get_dev = tcf_mirred_get_dev,
415
- .put_dev = tcf_mirred_put_dev,
416458 };
417459
418460 static __net_init int mirred_init_net(struct net *net)