summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bridge/Makefile2
-rw-r--r--net/bridge/br_forward.c3
-rw-r--r--net/bridge/br_if.c10
-rw-r--r--net/bridge/br_input.c2
-rw-r--r--net/bridge/br_private.h37
-rw-r--r--net/bridge/br_switchdev.c57
-rw-r--r--net/core/dev.c10
-rw-r--r--net/switchdev/switchdev.c85
8 files changed, 107 insertions, 99 deletions
diff --git a/net/bridge/Makefile b/net/bridge/Makefile
index a1cda5d4718d..0aefc011b668 100644
--- a/net/bridge/Makefile
+++ b/net/bridge/Makefile
@@ -20,4 +20,6 @@ bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.o
20 20
21bridge-$(CONFIG_BRIDGE_VLAN_FILTERING) += br_vlan.o 21bridge-$(CONFIG_BRIDGE_VLAN_FILTERING) += br_vlan.o
22 22
23bridge-$(CONFIG_NET_SWITCHDEV) += br_switchdev.o
24
23obj-$(CONFIG_NETFILTER) += netfilter/ 25obj-$(CONFIG_NETFILTER) += netfilter/
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 63a83d8d7da3..32a02de39cd2 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -29,7 +29,8 @@ static inline int should_deliver(const struct net_bridge_port *p,
29 29
30 vg = nbp_vlan_group_rcu(p); 30 vg = nbp_vlan_group_rcu(p);
31 return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) && 31 return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
32 br_allowed_egress(vg, skb) && p->state == BR_STATE_FORWARDING; 32 br_allowed_egress(vg, skb) && p->state == BR_STATE_FORWARDING &&
33 nbp_switchdev_allowed_egress(p, skb);
33} 34}
34 35
35int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) 36int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index f2fede05d32c..1da3221845f1 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -545,6 +545,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
545 if (err) 545 if (err)
546 goto err5; 546 goto err5;
547 547
548 err = nbp_switchdev_mark_set(p);
549 if (err)
550 goto err6;
551
548 dev_disable_lro(dev); 552 dev_disable_lro(dev);
549 553
550 list_add_rcu(&p->list, &br->port_list); 554 list_add_rcu(&p->list, &br->port_list);
@@ -566,7 +570,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
566 err = nbp_vlan_init(p); 570 err = nbp_vlan_init(p);
567 if (err) { 571 if (err) {
568 netdev_err(dev, "failed to initialize vlan filtering on this port\n"); 572 netdev_err(dev, "failed to initialize vlan filtering on this port\n");
569 goto err6; 573 goto err7;
570 } 574 }
571 575
572 spin_lock_bh(&br->lock); 576 spin_lock_bh(&br->lock);
@@ -589,12 +593,12 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
589 593
590 return 0; 594 return 0;
591 595
592err6: 596err7:
593 list_del_rcu(&p->list); 597 list_del_rcu(&p->list);
594 br_fdb_delete_by_port(br, p, 0, 1); 598 br_fdb_delete_by_port(br, p, 0, 1);
595 nbp_update_port_count(br); 599 nbp_update_port_count(br);
600err6:
596 netdev_upper_dev_unlink(dev, br->dev); 601 netdev_upper_dev_unlink(dev, br->dev);
597
598err5: 602err5:
599 dev->priv_flags &= ~IFF_BRIDGE_PORT; 603 dev->priv_flags &= ~IFF_BRIDGE_PORT;
600 netdev_rx_handler_unregister(dev); 604 netdev_rx_handler_unregister(dev);
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 8e486203d133..3132cfc80e9d 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -145,6 +145,8 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
145 if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid)) 145 if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid))
146 goto out; 146 goto out;
147 147
148 nbp_switchdev_frame_mark(p, skb);
149
148 /* insert into forwarding database after filtering to avoid spoofing */ 150 /* insert into forwarding database after filtering to avoid spoofing */
149 br = p->br; 151 br = p->br;
150 if (p->flags & BR_LEARNING) 152 if (p->flags & BR_LEARNING)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index aac2a6e6b008..2379b2b865c9 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -251,6 +251,9 @@ struct net_bridge_port
251#ifdef CONFIG_BRIDGE_VLAN_FILTERING 251#ifdef CONFIG_BRIDGE_VLAN_FILTERING
252 struct net_bridge_vlan_group __rcu *vlgrp; 252 struct net_bridge_vlan_group __rcu *vlgrp;
253#endif 253#endif
254#ifdef CONFIG_NET_SWITCHDEV
255 int offload_fwd_mark;
256#endif
254}; 257};
255 258
256#define br_auto_port(p) ((p)->flags & BR_AUTO_MASK) 259#define br_auto_port(p) ((p)->flags & BR_AUTO_MASK)
@@ -359,6 +362,11 @@ struct net_bridge
359 struct timer_list gc_timer; 362 struct timer_list gc_timer;
360 struct kobject *ifobj; 363 struct kobject *ifobj;
361 u32 auto_cnt; 364 u32 auto_cnt;
365
366#ifdef CONFIG_NET_SWITCHDEV
367 int offload_fwd_mark;
368#endif
369
362#ifdef CONFIG_BRIDGE_VLAN_FILTERING 370#ifdef CONFIG_BRIDGE_VLAN_FILTERING
363 struct net_bridge_vlan_group __rcu *vlgrp; 371 struct net_bridge_vlan_group __rcu *vlgrp;
364 u8 vlan_enabled; 372 u8 vlan_enabled;
@@ -381,6 +389,10 @@ struct br_input_skb_cb {
381#ifdef CONFIG_BRIDGE_VLAN_FILTERING 389#ifdef CONFIG_BRIDGE_VLAN_FILTERING
382 bool vlan_filtered; 390 bool vlan_filtered;
383#endif 391#endif
392
393#ifdef CONFIG_NET_SWITCHDEV
394 int offload_fwd_mark;
395#endif
384}; 396};
385 397
386#define BR_INPUT_SKB_CB(__skb) ((struct br_input_skb_cb *)(__skb)->cb) 398#define BR_INPUT_SKB_CB(__skb) ((struct br_input_skb_cb *)(__skb)->cb)
@@ -1034,4 +1046,29 @@ static inline int br_sysfs_addbr(struct net_device *dev) { return 0; }
1034static inline void br_sysfs_delbr(struct net_device *dev) { return; } 1046static inline void br_sysfs_delbr(struct net_device *dev) { return; }
1035#endif /* CONFIG_SYSFS */ 1047#endif /* CONFIG_SYSFS */
1036 1048
1049/* br_switchdev.c */
1050#ifdef CONFIG_NET_SWITCHDEV
1051int nbp_switchdev_mark_set(struct net_bridge_port *p);
1052void nbp_switchdev_frame_mark(const struct net_bridge_port *p,
1053 struct sk_buff *skb);
1054bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p,
1055 const struct sk_buff *skb);
1056#else
1057static inline int nbp_switchdev_mark_set(struct net_bridge_port *p)
1058{
1059 return 0;
1060}
1061
1062static inline void nbp_switchdev_frame_mark(const struct net_bridge_port *p,
1063 struct sk_buff *skb)
1064{
1065}
1066
1067static inline bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p,
1068 const struct sk_buff *skb)
1069{
1070 return true;
1071}
1072#endif /* CONFIG_NET_SWITCHDEV */
1073
1037#endif 1074#endif
diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c
new file mode 100644
index 000000000000..f4097b900de1
--- /dev/null
+++ b/net/bridge/br_switchdev.c
@@ -0,0 +1,57 @@
1#include <linux/kernel.h>
2#include <linux/list.h>
3#include <linux/netdevice.h>
4#include <linux/rtnetlink.h>
5#include <linux/skbuff.h>
6#include <net/switchdev.h>
7
8#include "br_private.h"
9
10static int br_switchdev_mark_get(struct net_bridge *br, struct net_device *dev)
11{
12 struct net_bridge_port *p;
13
14 /* dev is yet to be added to the port list. */
15 list_for_each_entry(p, &br->port_list, list) {
16 if (switchdev_port_same_parent_id(dev, p->dev))
17 return p->offload_fwd_mark;
18 }
19
20 return ++br->offload_fwd_mark;
21}
22
23int nbp_switchdev_mark_set(struct net_bridge_port *p)
24{
25 struct switchdev_attr attr = {
26 .orig_dev = p->dev,
27 .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID,
28 };
29 int err;
30
31 ASSERT_RTNL();
32
33 err = switchdev_port_attr_get(p->dev, &attr);
34 if (err) {
35 if (err == -EOPNOTSUPP)
36 return 0;
37 return err;
38 }
39
40 p->offload_fwd_mark = br_switchdev_mark_get(p->br, p->dev);
41
42 return 0;
43}
44
45void nbp_switchdev_frame_mark(const struct net_bridge_port *p,
46 struct sk_buff *skb)
47{
48 if (skb->offload_fwd_mark && !WARN_ON_ONCE(!p->offload_fwd_mark))
49 BR_INPUT_SKB_CB(skb)->offload_fwd_mark = p->offload_fwd_mark;
50}
51
52bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p,
53 const struct sk_buff *skb)
54{
55 return !skb->offload_fwd_mark ||
56 BR_INPUT_SKB_CB(skb)->offload_fwd_mark != p->offload_fwd_mark;
57}
diff --git a/net/core/dev.c b/net/core/dev.c
index 7feae74ca928..1d5c6dda1988 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3355,16 +3355,6 @@ static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv)
3355 else 3355 else
3356 skb_dst_force(skb); 3356 skb_dst_force(skb);
3357 3357
3358#ifdef CONFIG_NET_SWITCHDEV
3359 /* Don't forward if offload device already forwarded */
3360 if (skb->offload_fwd_mark &&
3361 skb->offload_fwd_mark == dev->offload_fwd_mark) {
3362 consume_skb(skb);
3363 rc = NET_XMIT_SUCCESS;
3364 goto out;
3365 }
3366#endif
3367
3368 txq = netdev_pick_tx(dev, skb, accel_priv); 3358 txq = netdev_pick_tx(dev, skb, accel_priv);
3369 q = rcu_dereference_bh(txq->qdisc); 3359 q = rcu_dereference_bh(txq->qdisc);
3370 3360
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index 2c683f24d557..1031a0327fff 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -1305,88 +1305,3 @@ bool switchdev_port_same_parent_id(struct net_device *a,
1305 return netdev_phys_item_id_same(&a_attr.u.ppid, &b_attr.u.ppid); 1305 return netdev_phys_item_id_same(&a_attr.u.ppid, &b_attr.u.ppid);
1306} 1306}
1307EXPORT_SYMBOL_GPL(switchdev_port_same_parent_id); 1307EXPORT_SYMBOL_GPL(switchdev_port_same_parent_id);
1308
1309static u32 switchdev_port_fwd_mark_get(struct net_device *dev,
1310 struct net_device *group_dev)
1311{
1312 struct net_device *lower_dev;
1313 struct list_head *iter;
1314
1315 netdev_for_each_lower_dev(group_dev, lower_dev, iter) {
1316 if (lower_dev == dev)
1317 continue;
1318 if (switchdev_port_same_parent_id(dev, lower_dev))
1319 return lower_dev->offload_fwd_mark;
1320 return switchdev_port_fwd_mark_get(dev, lower_dev);
1321 }
1322
1323 return dev->ifindex;
1324}
1325
1326static void switchdev_port_fwd_mark_reset(struct net_device *group_dev,
1327 u32 old_mark, u32 *reset_mark)
1328{
1329 struct net_device *lower_dev;
1330 struct list_head *iter;
1331
1332 netdev_for_each_lower_dev(group_dev, lower_dev, iter) {
1333 if (lower_dev->offload_fwd_mark == old_mark) {
1334 if (!*reset_mark)
1335 *reset_mark = lower_dev->ifindex;
1336 lower_dev->offload_fwd_mark = *reset_mark;
1337 }
1338 switchdev_port_fwd_mark_reset(lower_dev, old_mark, reset_mark);
1339 }
1340}
1341
1342/**
1343 * switchdev_port_fwd_mark_set - Set port offload forwarding mark
1344 *
1345 * @dev: port device
1346 * @group_dev: containing device
1347 * @joining: true if dev is joining group; false if leaving group
1348 *
1349 * An ungrouped port's offload mark is just its ifindex. A grouped
1350 * port's (member of a bridge, for example) offload mark is the ifindex
1351 * of one of the ports in the group with the same parent (switch) ID.
1352 * Ports on the same device in the same group will have the same mark.
1353 *
1354 * Example:
1355 *
1356 * br0 ifindex=9
1357 * sw1p1 ifindex=2 mark=2
1358 * sw1p2 ifindex=3 mark=2
1359 * sw2p1 ifindex=4 mark=5
1360 * sw2p2 ifindex=5 mark=5
1361 *
1362 * If sw2p2 leaves the bridge, we'll have:
1363 *
1364 * br0 ifindex=9
1365 * sw1p1 ifindex=2 mark=2
1366 * sw1p2 ifindex=3 mark=2
1367 * sw2p1 ifindex=4 mark=4
1368 * sw2p2 ifindex=5 mark=5
1369 */
1370void switchdev_port_fwd_mark_set(struct net_device *dev,
1371 struct net_device *group_dev,
1372 bool joining)
1373{
1374 u32 mark = dev->ifindex;
1375 u32 reset_mark = 0;
1376
1377 if (group_dev) {
1378 ASSERT_RTNL();
1379 if (joining)
1380 mark = switchdev_port_fwd_mark_get(dev, group_dev);
1381 else if (dev->offload_fwd_mark == mark)
1382 /* Ohoh, this port was the mark reference port,
1383 * but it's leaving the group, so reset the
1384 * mark for the remaining ports in the group.
1385 */
1386 switchdev_port_fwd_mark_reset(group_dev, mark,
1387 &reset_mark);
1388 }
1389
1390 dev->offload_fwd_mark = mark;
1391}
1392EXPORT_SYMBOL_GPL(switchdev_port_fwd_mark_set);