diff options
author | Scott Feldman <sfeldma@gmail.com> | 2015-07-18 21:24:50 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-07-20 21:32:44 -0400 |
commit | 1a3b2ec93d4277b121979321b4024b438cb09504 (patch) | |
tree | c57bf0a7563a0cfcdcda3c08ca90591c15d21f0a /net/switchdev | |
parent | d754f98b502ad9a8c7570d494e1eaa0e6bc0350c (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.c | 103 |
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 | } |
1041 | EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_abort); | 1041 | EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_abort); |
1042 | |||
1043 | static 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 | |||
1062 | static 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 | |||
1079 | static 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 | */ | ||
1123 | void 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 | } | ||
1144 | EXPORT_SYMBOL_GPL(switchdev_port_fwd_mark_set); | ||