hc
2024-05-10 748e4f3d702def1a4bff191e0cf93b6a05340f01
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_NEST_LIMIT 4
32
+static DEFINE_PER_CPU(unsigned int, mirred_nest_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,69 @@
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;
207
+}
208
+
209
+static bool is_mirred_nested(void)
210
+{
211
+ return unlikely(__this_cpu_read(mirred_nest_level) > 1);
212
+}
213
+
214
+static int tcf_mirred_forward(bool want_ingress, struct sk_buff *skb)
215
+{
216
+ int err;
217
+
218
+ if (!want_ingress)
219
+ err = dev_queue_xmit(skb);
220
+ else if (is_mirred_nested())
221
+ err = netif_rx(skb);
222
+ else
223
+ err = netif_receive_skb(skb);
224
+
225
+ return err;
195226 }
196227
197228 static int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a,
....@@ -201,15 +232,27 @@
201232 struct sk_buff *skb2 = skb;
202233 bool m_mac_header_xmit;
203234 struct net_device *dev;
235
+ unsigned int nest_level;
204236 int retval, err = 0;
205237 bool use_reinsert;
206238 bool want_ingress;
207239 bool is_redirect;
240
+ bool expects_nh;
241
+ bool at_ingress;
208242 int m_eaction;
209243 int mac_len;
244
+ bool at_nh;
245
+
246
+ nest_level = __this_cpu_inc_return(mirred_nest_level);
247
+ if (unlikely(nest_level > MIRRED_NEST_LIMIT)) {
248
+ net_warn_ratelimited("Packet exceeded mirred recursion limit on dev %s\n",
249
+ netdev_name(skb->dev));
250
+ __this_cpu_dec(mirred_nest_level);
251
+ return TC_ACT_SHOT;
252
+ }
210253
211254 tcf_lastuse_update(&m->tcf_tm);
212
- bstats_cpu_update(this_cpu_ptr(m->common.cpu_bstats), skb);
255
+ tcf_action_update_bstats(&m->common, skb);
213256
214257 m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit);
215258 m_eaction = READ_ONCE(m->tcfm_eaction);
....@@ -220,7 +263,7 @@
220263 goto out;
221264 }
222265
223
- if (unlikely(!(dev->flags & IFF_UP))) {
266
+ if (unlikely(!(dev->flags & IFF_UP)) || !netif_carrier_ok(dev)) {
224267 net_notice_ratelimited("tc mirred to Houston: device %s is down\n",
225268 dev->name);
226269 goto out;
....@@ -231,7 +274,8 @@
231274 * ingress - that covers the TC S/W datapath.
232275 */
233276 is_redirect = tcf_mirred_is_act_redirect(m_eaction);
234
- use_reinsert = skb_at_tc_ingress(skb) && is_redirect &&
277
+ at_ingress = skb_at_tc_ingress(skb);
278
+ use_reinsert = at_ingress && is_redirect &&
235279 tcf_mirred_can_reinsert(retval);
236280 if (!use_reinsert) {
237281 skb2 = skb_clone(skb, GFP_ATOMIC);
....@@ -239,19 +283,24 @@
239283 goto out;
240284 }
241285
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
- */
246286 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);
287
+
288
+ /* All mirred/redirected skbs should clear previous ct info */
289
+ nf_reset_ct(skb2);
290
+ if (want_ingress && !at_ingress) /* drop dst for egress -> ingress */
291
+ skb_dst_drop(skb2);
292
+
293
+ expects_nh = want_ingress || !m_mac_header_xmit;
294
+ at_nh = skb->data == skb_network_header(skb);
295
+ if (at_nh != expects_nh) {
296
+ mac_len = skb_at_tc_ingress(skb) ? skb->mac_len :
297
+ skb_network_header(skb) - skb_mac_header(skb);
298
+ if (expects_nh) {
299
+ /* target device/action expect data at nh */
251300 skb_pull_rcsum(skb2, mac_len);
252301 } else {
253
- /* caught at ingress, act egress: push mac */
254
- skb_push_rcsum(skb2, skb->mac_len);
302
+ /* target device/action expect data at mac */
303
+ skb_push_rcsum(skb2, mac_len);
255304 }
256305 }
257306
....@@ -260,39 +309,38 @@
260309
261310 /* mirror is always swallowed */
262311 if (is_redirect) {
263
- skb2->tc_redirected = 1;
264
- skb2->tc_from_ingress = skb2->tc_at_ingress;
312
+ skb_set_redirected(skb2, skb2->tc_at_ingress);
265313
266314 /* let's the caller reinsert the packet, if possible */
267315 if (use_reinsert) {
268316 res->ingress = want_ingress;
269
- res->qstats = this_cpu_ptr(m->common.cpu_qstats);
270
- return TC_ACT_REINSERT;
317
+ err = tcf_mirred_forward(res->ingress, skb);
318
+ if (err)
319
+ tcf_action_inc_overlimit_qstats(&m->common);
320
+ __this_cpu_dec(mirred_nest_level);
321
+ return TC_ACT_CONSUMED;
271322 }
272323 }
273324
274
- if (!want_ingress)
275
- err = dev_queue_xmit(skb2);
276
- else
277
- err = netif_receive_skb(skb2);
278
-
325
+ err = tcf_mirred_forward(want_ingress, skb2);
279326 if (err) {
280327 out:
281
- qstats_overlimit_inc(this_cpu_ptr(m->common.cpu_qstats));
328
+ tcf_action_inc_overlimit_qstats(&m->common);
282329 if (tcf_mirred_is_act_redirect(m_eaction))
283330 retval = TC_ACT_SHOT;
284331 }
332
+ __this_cpu_dec(mirred_nest_level);
285333
286334 return retval;
287335 }
288336
289
-static void tcf_stats_update(struct tc_action *a, u64 bytes, u32 packets,
290
- u64 lastuse)
337
+static void tcf_stats_update(struct tc_action *a, u64 bytes, u64 packets,
338
+ u64 drops, u64 lastuse, bool hw)
291339 {
292340 struct tcf_mirred *m = to_mirred(a);
293341 struct tcf_t *tm = &m->tcf_tm;
294342
295
- _bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), bytes, packets);
343
+ tcf_action_update_stats(a, bytes, packets, drops, hw);
296344 tm->lastuse = max_t(u64, tm->lastuse, lastuse);
297345 }
298346
....@@ -342,8 +390,7 @@
342390 return tcf_generic_walker(tn, skb, cb, type, ops, extack);
343391 }
344392
345
-static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index,
346
- struct netlink_ext_ack *extack)
393
+static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index)
347394 {
348395 struct tc_action_net *tn = net_generic(net, mirred_net_id);
349396
....@@ -380,28 +427,39 @@
380427 .notifier_call = mirred_device_event,
381428 };
382429
383
-static struct net_device *tcf_mirred_get_dev(const struct tc_action *a)
430
+static void tcf_mirred_dev_put(void *priv)
431
+{
432
+ struct net_device *dev = priv;
433
+
434
+ dev_put(dev);
435
+}
436
+
437
+static struct net_device *
438
+tcf_mirred_get_dev(const struct tc_action *a,
439
+ tc_action_priv_destructor *destructor)
384440 {
385441 struct tcf_mirred *m = to_mirred(a);
386442 struct net_device *dev;
387443
388444 rcu_read_lock();
389445 dev = rcu_dereference(m->tcfm_dev);
390
- if (dev)
446
+ if (dev) {
391447 dev_hold(dev);
448
+ *destructor = tcf_mirred_dev_put;
449
+ }
392450 rcu_read_unlock();
393451
394452 return dev;
395453 }
396454
397
-static void tcf_mirred_put_dev(struct net_device *dev)
455
+static size_t tcf_mirred_get_fill_size(const struct tc_action *act)
398456 {
399
- dev_put(dev);
457
+ return nla_total_size(sizeof(struct tc_mirred));
400458 }
401459
402460 static struct tc_action_ops act_mirred_ops = {
403461 .kind = "mirred",
404
- .type = TCA_ACT_MIRRED,
462
+ .id = TCA_ID_MIRRED,
405463 .owner = THIS_MODULE,
406464 .act = tcf_mirred_act,
407465 .stats_update = tcf_stats_update,
....@@ -410,9 +468,9 @@
410468 .init = tcf_mirred_init,
411469 .walk = tcf_mirred_walker,
412470 .lookup = tcf_mirred_search,
471
+ .get_fill_size = tcf_mirred_get_fill_size,
413472 .size = sizeof(struct tcf_mirred),
414473 .get_dev = tcf_mirred_get_dev,
415
- .put_dev = tcf_mirred_put_dev,
416474 };
417475
418476 static __net_init int mirred_init_net(struct net *net)