summaryrefslogtreecommitdiffstats
path: root/net/switchdev/switchdev.c
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@mellanox.com>2016-08-25 12:42:37 -0400
committerDavid S. Miller <davem@davemloft.net>2016-08-26 16:13:36 -0400
commit6bc506b4fb065eac3d89ca1ce37082e174493d9e (patch)
treeb2ce45bcdf47c388d9d0977af7bf511685a00e6e /net/switchdev/switchdev.c
parent5c326ab49e5ee014ba5314c076fe9b93fd8b0406 (diff)
bridge: switchdev: Add forward mark support for stacked devices
switchdev_port_fwd_mark_set() is used to set the 'offload_fwd_mark' of port netdevs so that packets being flooded by the device won't be flooded twice. It works by assigning a unique identifier (the ifindex of the first bridge port) to bridge ports sharing the same parent ID. This prevents packets from being flooded twice by the same switch, but will flood packets through bridge ports belonging to a different switch. This method is problematic when stacked devices are taken into account, such as VLANs. In such cases, a physical port netdev can have upper devices being members in two different bridges, thus requiring two different 'offload_fwd_mark's to be configured on the port netdev, which is impossible. The main problem is that packet and netdev marking is performed at the physical netdev level, whereas flooding occurs between bridge ports, which are not necessarily port netdevs. Instead, packet and netdev marking should really be done in the bridge driver with the switch driver only telling it which packets it already forwarded. The bridge driver will mark such packets using the mark assigned to the ingress bridge port and will prevent the packet from being forwarded through any bridge port sharing the same mark (i.e. having the same parent ID). Remove the current switchdev 'offload_fwd_mark' implementation and instead implement the proposed method. In addition, make rocker - the sole user of the mark - use the proposed method. Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r--net/switchdev/switchdev.c85
1 files changed, 0 insertions, 85 deletions
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);