aboutsummaryrefslogtreecommitdiffstats
path: root/net/switchdev
diff options
context:
space:
mode:
authorScott Feldman <sfeldma@gmail.com>2015-07-18 21:24:50 -0400
committerDavid S. Miller <davem@davemloft.net>2015-07-20 21:32:44 -0400
commit1a3b2ec93d4277b121979321b4024b438cb09504 (patch)
treec57bf0a7563a0cfcdcda3c08ca90591c15d21f0a /net/switchdev
parentd754f98b502ad9a8c7570d494e1eaa0e6bc0350c (diff)
switchdev: add offload_fwd_mark generator helper
skb->offload_fwd_mark and dev->offload_fwd_mark are 32-bit and should be unique for device and may even be unique for a sub-set of ports within device, so add switchdev helper function to generate unique marks based on port's switch ID and group_ifindex. group_ifindex would typically be the container dev's ifindex, such as the bridge's ifindex. The generator uses a global hash table to store offload_fwd_marks hashed by {switch ID, group_ifindex} key. Signed-off-by: Scott Feldman <sfeldma@gmail.com> Acked-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/switchdev')
-rw-r--r--net/switchdev/switchdev.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index 4e5bba50ccff..33bafa2e703e 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -1039,3 +1039,106 @@ void switchdev_fib_ipv4_abort(struct fib_info *fi)
1039 fi->fib_net->ipv4.fib_offload_disabled = true; 1039 fi->fib_net->ipv4.fib_offload_disabled = true;
1040} 1040}
1041EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_abort); 1041EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_abort);
1042
1043static bool switchdev_port_same_parent_id(struct net_device *a,
1044 struct net_device *b)
1045{
1046 struct switchdev_attr a_attr = {
1047 .id = SWITCHDEV_ATTR_PORT_PARENT_ID,
1048 .flags = SWITCHDEV_F_NO_RECURSE,
1049 };
1050 struct switchdev_attr b_attr = {
1051 .id = SWITCHDEV_ATTR_PORT_PARENT_ID,
1052 .flags = SWITCHDEV_F_NO_RECURSE,
1053 };
1054
1055 if (switchdev_port_attr_get(a, &a_attr) ||
1056 switchdev_port_attr_get(b, &b_attr))
1057 return false;
1058
1059 return netdev_phys_item_id_same(&a_attr.u.ppid, &b_attr.u.ppid);
1060}
1061
1062static u32 switchdev_port_fwd_mark_get(struct net_device *dev,
1063 struct net_device *group_dev)
1064{
1065 struct net_device *lower_dev;
1066 struct list_head *iter;
1067
1068 netdev_for_each_lower_dev(group_dev, lower_dev, iter) {
1069 if (lower_dev == dev)
1070 continue;
1071 if (switchdev_port_same_parent_id(dev, lower_dev))
1072 return lower_dev->offload_fwd_mark;
1073 return switchdev_port_fwd_mark_get(dev, lower_dev);
1074 }
1075
1076 return dev->ifindex;
1077}
1078
1079static void switchdev_port_fwd_mark_reset(struct net_device *group_dev,
1080 u32 old_mark, u32 *reset_mark)
1081{
1082 struct net_device *lower_dev;
1083 struct list_head *iter;
1084
1085 netdev_for_each_lower_dev(group_dev, lower_dev, iter) {
1086 if (lower_dev->offload_fwd_mark == old_mark) {
1087 if (!*reset_mark)
1088 *reset_mark = lower_dev->ifindex;
1089 lower_dev->offload_fwd_mark = *reset_mark;
1090 }
1091 switchdev_port_fwd_mark_reset(lower_dev, old_mark, reset_mark);
1092 }
1093}
1094
1095/**
1096 * switchdev_port_fwd_mark_set - Set port offload forwarding mark
1097 *
1098 * @dev: port device
1099 * @group_dev: containing device
1100 * @joining: true if dev is joining group; false if leaving group
1101 *
1102 * An ungrouped port's offload mark is just its ifindex. A grouped
1103 * port's (member of a bridge, for example) offload mark is the ifindex
1104 * of one of the ports in the group with the same parent (switch) ID.
1105 * Ports on the same device in the same group will have the same mark.
1106 *
1107 * Example:
1108 *
1109 * br0 ifindex=9
1110 * sw1p1 ifindex=2 mark=2
1111 * sw1p2 ifindex=3 mark=2
1112 * sw2p1 ifindex=4 mark=5
1113 * sw2p2 ifindex=5 mark=5
1114 *
1115 * If sw2p2 leaves the bridge, we'll have:
1116 *
1117 * br0 ifindex=9
1118 * sw1p1 ifindex=2 mark=2
1119 * sw1p2 ifindex=3 mark=2
1120 * sw2p1 ifindex=4 mark=4
1121 * sw2p2 ifindex=5 mark=5
1122 */
1123void switchdev_port_fwd_mark_set(struct net_device *dev,
1124 struct net_device *group_dev,
1125 bool joining)
1126{
1127 u32 mark = dev->ifindex;
1128 u32 reset_mark = 0;
1129
1130 if (group_dev && joining) {
1131 mark = switchdev_port_fwd_mark_get(dev, group_dev);
1132 } else if (group_dev && !joining) {
1133 if (dev->offload_fwd_mark == mark)
1134 /* Ohoh, this port was the mark reference port,
1135 * but it's leaving the group, so reset the
1136 * mark for the remaining ports in the group.
1137 */
1138 switchdev_port_fwd_mark_reset(group_dev, mark,
1139 &reset_mark);
1140 }
1141
1142 dev->offload_fwd_mark = mark;
1143}
1144EXPORT_SYMBOL_GPL(switchdev_port_fwd_mark_set);