diff options
author | Nikolay Aleksandrov <nikolay@cumulusnetworks.com> | 2017-09-27 09:12:44 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-09-29 01:02:55 -0400 |
commit | 5af48b59f35cf712793badabe1a574a0d0ce3bd3 (patch) | |
tree | d37a58d1a9d1dca19835760305f7a10be68aca5f | |
parent | de9c8a6a5f083b1106300c842108c2452b25a896 (diff) |
net: bridge: add per-port group_fwd_mask with less restrictions
We need to be able to transparently forward most link-local frames via
tunnels (e.g. vxlan, qinq). Currently the bridge's group_fwd_mask has a
mask which restricts the forwarding of STP and LACP, but we need to be able
to forward these over tunnels and control that forwarding on a per-port
basis thus add a new per-port group_fwd_mask option which only disallows
mac pause frames to be forwarded (they're always dropped anyway).
The patch does not change the current default situation - all of the others
are still restricted unless configured for forwarding.
We have successfully tested this patch with LACP and STP forwarding over
VxLAN and qinq tunnels.
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/uapi/linux/if_link.h | 1 | ||||
-rw-r--r-- | net/bridge/br_input.c | 1 | ||||
-rw-r--r-- | net/bridge/br_netlink.c | 14 | ||||
-rw-r--r-- | net/bridge/br_private.h | 10 | ||||
-rw-r--r-- | net/bridge/br_sysfs_if.c | 18 |
5 files changed, 42 insertions, 2 deletions
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 8d062c58d5cb..ea87bd708ee9 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h | |||
@@ -325,6 +325,7 @@ enum { | |||
325 | IFLA_BRPORT_MCAST_TO_UCAST, | 325 | IFLA_BRPORT_MCAST_TO_UCAST, |
326 | IFLA_BRPORT_VLAN_TUNNEL, | 326 | IFLA_BRPORT_VLAN_TUNNEL, |
327 | IFLA_BRPORT_BCAST_FLOOD, | 327 | IFLA_BRPORT_BCAST_FLOOD, |
328 | IFLA_BRPORT_GROUP_FWD_MASK, | ||
328 | __IFLA_BRPORT_MAX | 329 | __IFLA_BRPORT_MAX |
329 | }; | 330 | }; |
330 | #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) | 331 | #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 7637f58c1226..7cb613776b31 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -289,6 +289,7 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb) | |||
289 | * | 289 | * |
290 | * Others reserved for future standardization | 290 | * Others reserved for future standardization |
291 | */ | 291 | */ |
292 | fwd_mask |= p->group_fwd_mask; | ||
292 | switch (dest[5]) { | 293 | switch (dest[5]) { |
293 | case 0x00: /* Bridge Group Address */ | 294 | case 0x00: /* Bridge Group Address */ |
294 | /* If STP is turned off, | 295 | /* If STP is turned off, |
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 3bc890716c89..dea88a255d26 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -152,6 +152,7 @@ static inline size_t br_port_info_size(void) | |||
152 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING | 152 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING |
153 | + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MULTICAST_ROUTER */ | 153 | + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MULTICAST_ROUTER */ |
154 | #endif | 154 | #endif |
155 | + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_GROUP_FWD_MASK */ | ||
155 | + 0; | 156 | + 0; |
156 | } | 157 | } |
157 | 158 | ||
@@ -208,7 +209,8 @@ static int br_port_fill_attrs(struct sk_buff *skb, | |||
208 | p->topology_change_ack) || | 209 | p->topology_change_ack) || |
209 | nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending) || | 210 | nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending) || |
210 | nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(p->flags & | 211 | nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(p->flags & |
211 | BR_VLAN_TUNNEL))) | 212 | BR_VLAN_TUNNEL)) || |
213 | nla_put_u16(skb, IFLA_BRPORT_GROUP_FWD_MASK, p->group_fwd_mask)) | ||
212 | return -EMSGSIZE; | 214 | return -EMSGSIZE; |
213 | 215 | ||
214 | timerval = br_timer_value(&p->message_age_timer); | 216 | timerval = br_timer_value(&p->message_age_timer); |
@@ -637,6 +639,7 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = { | |||
637 | [IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NLA_U8 }, | 639 | [IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NLA_U8 }, |
638 | [IFLA_BRPORT_MCAST_FLOOD] = { .type = NLA_U8 }, | 640 | [IFLA_BRPORT_MCAST_FLOOD] = { .type = NLA_U8 }, |
639 | [IFLA_BRPORT_BCAST_FLOOD] = { .type = NLA_U8 }, | 641 | [IFLA_BRPORT_BCAST_FLOOD] = { .type = NLA_U8 }, |
642 | [IFLA_BRPORT_GROUP_FWD_MASK] = { .type = NLA_U16 }, | ||
640 | }; | 643 | }; |
641 | 644 | ||
642 | /* Change the state of the port and notify spanning tree */ | 645 | /* Change the state of the port and notify spanning tree */ |
@@ -773,6 +776,15 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) | |||
773 | return err; | 776 | return err; |
774 | } | 777 | } |
775 | #endif | 778 | #endif |
779 | |||
780 | if (tb[IFLA_BRPORT_GROUP_FWD_MASK]) { | ||
781 | u16 fwd_mask = nla_get_u16(tb[IFLA_BRPORT_GROUP_FWD_MASK]); | ||
782 | |||
783 | if (fwd_mask & BR_GROUPFWD_MACPAUSE) | ||
784 | return -EINVAL; | ||
785 | p->group_fwd_mask = fwd_mask; | ||
786 | } | ||
787 | |||
776 | br_port_flags_change(p, old_flags ^ p->flags); | 788 | br_port_flags_change(p, old_flags ^ p->flags); |
777 | return 0; | 789 | return 0; |
778 | } | 790 | } |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index e870cfc85b14..020c709a017f 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -36,7 +36,14 @@ | |||
36 | /* Control of forwarding link local multicast */ | 36 | /* Control of forwarding link local multicast */ |
37 | #define BR_GROUPFWD_DEFAULT 0 | 37 | #define BR_GROUPFWD_DEFAULT 0 |
38 | /* Don't allow forwarding of control protocols like STP, MAC PAUSE and LACP */ | 38 | /* Don't allow forwarding of control protocols like STP, MAC PAUSE and LACP */ |
39 | #define BR_GROUPFWD_RESTRICTED 0x0007u | 39 | enum { |
40 | BR_GROUPFWD_STP = BIT(0), | ||
41 | BR_GROUPFWD_MACPAUSE = BIT(1), | ||
42 | BR_GROUPFWD_LACP = BIT(2), | ||
43 | }; | ||
44 | |||
45 | #define BR_GROUPFWD_RESTRICTED (BR_GROUPFWD_STP | BR_GROUPFWD_MACPAUSE | \ | ||
46 | BR_GROUPFWD_LACP) | ||
40 | /* The Nearest Customer Bridge Group Address, 01-80-C2-00-00-[00,0B,0C,0D,0F] */ | 47 | /* The Nearest Customer Bridge Group Address, 01-80-C2-00-00-[00,0B,0C,0D,0F] */ |
41 | #define BR_GROUPFWD_8021AD 0xB801u | 48 | #define BR_GROUPFWD_8021AD 0xB801u |
42 | 49 | ||
@@ -268,6 +275,7 @@ struct net_bridge_port { | |||
268 | #ifdef CONFIG_NET_SWITCHDEV | 275 | #ifdef CONFIG_NET_SWITCHDEV |
269 | int offload_fwd_mark; | 276 | int offload_fwd_mark; |
270 | #endif | 277 | #endif |
278 | u16 group_fwd_mask; | ||
271 | }; | 279 | }; |
272 | 280 | ||
273 | #define br_auto_port(p) ((p)->flags & BR_AUTO_MASK) | 281 | #define br_auto_port(p) ((p)->flags & BR_AUTO_MASK) |
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 5d5d413a6cf8..9110d5e56085 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c | |||
@@ -165,6 +165,23 @@ static int store_flush(struct net_bridge_port *p, unsigned long v) | |||
165 | } | 165 | } |
166 | static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush); | 166 | static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush); |
167 | 167 | ||
168 | static ssize_t show_group_fwd_mask(struct net_bridge_port *p, char *buf) | ||
169 | { | ||
170 | return sprintf(buf, "%#x\n", p->group_fwd_mask); | ||
171 | } | ||
172 | |||
173 | static int store_group_fwd_mask(struct net_bridge_port *p, | ||
174 | unsigned long v) | ||
175 | { | ||
176 | if (v & BR_GROUPFWD_MACPAUSE) | ||
177 | return -EINVAL; | ||
178 | p->group_fwd_mask = v; | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | static BRPORT_ATTR(group_fwd_mask, S_IRUGO | S_IWUSR, show_group_fwd_mask, | ||
183 | store_group_fwd_mask); | ||
184 | |||
168 | BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPIN_MODE); | 185 | BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPIN_MODE); |
169 | BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD); | 186 | BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD); |
170 | BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK); | 187 | BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK); |
@@ -223,6 +240,7 @@ static const struct brport_attribute *brport_attrs[] = { | |||
223 | &brport_attr_proxyarp_wifi, | 240 | &brport_attr_proxyarp_wifi, |
224 | &brport_attr_multicast_flood, | 241 | &brport_attr_multicast_flood, |
225 | &brport_attr_broadcast_flood, | 242 | &brport_attr_broadcast_flood, |
243 | &brport_attr_group_fwd_mask, | ||
226 | NULL | 244 | NULL |
227 | }; | 245 | }; |
228 | 246 | ||