Signed-off-by: Felix Fietkau <nbd@nbd.name>
(backported from 21ee8ce9b5)
(rebased patches)
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
		
	
			
		
			
				
	
	
		
			146 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
 | 
						|
Date: Thu, 24 May 2018 11:56:48 +0300
 | 
						|
Subject: [PATCH] net: bridge: add support for port isolation
 | 
						|
 | 
						|
This patch adds support for a new port flag - BR_ISOLATED. If it is set
 | 
						|
then isolated ports cannot communicate between each other, but they can
 | 
						|
still communicate with non-isolated ports. The same can be achieved via
 | 
						|
ACLs but they can't scale with large number of ports and also the
 | 
						|
complexity of the rules grows. This feature can be used to achieve
 | 
						|
isolated vlan functionality (similar to pvlan) as well, though currently
 | 
						|
it will be port-wide (for all vlans on the port). The new test in
 | 
						|
should_deliver uses data that is already cache hot and the new boolean
 | 
						|
is used to avoid an additional source port test in should_deliver.
 | 
						|
 | 
						|
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
 | 
						|
Reviewed-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
 | 
						|
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
						|
---
 | 
						|
 | 
						|
--- a/include/uapi/linux/if_link.h
 | 
						|
+++ b/include/uapi/linux/if_link.h
 | 
						|
@@ -326,6 +326,8 @@ enum {
 | 
						|
 	IFLA_BRPORT_MCAST_TO_UCAST,
 | 
						|
 	IFLA_BRPORT_VLAN_TUNNEL,
 | 
						|
 	IFLA_BRPORT_BCAST_FLOOD,
 | 
						|
+	IFLA_BRPORT_NEIGH_SUPPRESS,
 | 
						|
+	IFLA_BRPORT_ISOLATED,
 | 
						|
 	__IFLA_BRPORT_MAX
 | 
						|
 };
 | 
						|
 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
 | 
						|
--- a/net/bridge/br_forward.c
 | 
						|
+++ b/net/bridge/br_forward.c
 | 
						|
@@ -30,7 +30,8 @@ static inline int should_deliver(const s
 | 
						|
 	vg = nbp_vlan_group_rcu(p);
 | 
						|
 	return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
 | 
						|
 		br_allowed_egress(vg, skb) && p->state == BR_STATE_FORWARDING &&
 | 
						|
-		nbp_switchdev_allowed_egress(p, skb);
 | 
						|
+		nbp_switchdev_allowed_egress(p, skb) &&
 | 
						|
+		!br_skb_isolated(p, skb);
 | 
						|
 }
 | 
						|
 
 | 
						|
 int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
 | 
						|
--- a/net/bridge/br_input.c
 | 
						|
+++ b/net/bridge/br_input.c
 | 
						|
@@ -170,6 +170,7 @@ int br_handle_frame_finish(struct net *n
 | 
						|
 		goto drop;
 | 
						|
 
 | 
						|
 	BR_INPUT_SKB_CB(skb)->brdev = br->dev;
 | 
						|
+	BR_INPUT_SKB_CB(skb)->src_port_isolated = !!(p->flags & BR_ISOLATED);
 | 
						|
 
 | 
						|
 	if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP))
 | 
						|
 		br_do_proxy_arp(skb, br, vid, p);
 | 
						|
--- a/net/bridge/br_netlink.c
 | 
						|
+++ b/net/bridge/br_netlink.c
 | 
						|
@@ -138,6 +138,7 @@ static inline size_t br_port_info_size(v
 | 
						|
 		+ nla_total_size(1)	/* IFLA_BRPORT_PROXYARP */
 | 
						|
 		+ nla_total_size(1)	/* IFLA_BRPORT_PROXYARP_WIFI */
 | 
						|
 		+ nla_total_size(1)	/* IFLA_BRPORT_VLAN_TUNNEL */
 | 
						|
+		+ nla_total_size(1)	/* IFLA_BRPORT_ISOLATED */
 | 
						|
 		+ nla_total_size(sizeof(struct ifla_bridge_id))	/* IFLA_BRPORT_ROOT_ID */
 | 
						|
 		+ nla_total_size(sizeof(struct ifla_bridge_id))	/* IFLA_BRPORT_BRIDGE_ID */
 | 
						|
 		+ nla_total_size(sizeof(u16))	/* IFLA_BRPORT_DESIGNATED_PORT */
 | 
						|
@@ -208,7 +209,8 @@ static int br_port_fill_attrs(struct sk_
 | 
						|
 		       p->topology_change_ack) ||
 | 
						|
 	    nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending) ||
 | 
						|
 	    nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(p->flags &
 | 
						|
-							BR_VLAN_TUNNEL)))
 | 
						|
+							BR_VLAN_TUNNEL)) ||
 | 
						|
+	    nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED)))
 | 
						|
 		return -EMSGSIZE;
 | 
						|
 
 | 
						|
 	timerval = br_timer_value(&p->message_age_timer);
 | 
						|
@@ -637,6 +639,7 @@ static const struct nla_policy br_port_p
 | 
						|
 	[IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NLA_U8 },
 | 
						|
 	[IFLA_BRPORT_MCAST_FLOOD] = { .type = NLA_U8 },
 | 
						|
 	[IFLA_BRPORT_BCAST_FLOOD] = { .type = NLA_U8 },
 | 
						|
+	[IFLA_BRPORT_ISOLATED]	= { .type = NLA_U8 },
 | 
						|
 };
 | 
						|
 
 | 
						|
 /* Change the state of the port and notify spanning tree */
 | 
						|
@@ -773,6 +776,11 @@ static int br_setport(struct net_bridge_
 | 
						|
 			return err;
 | 
						|
 	}
 | 
						|
 #endif
 | 
						|
+
 | 
						|
+	err = br_set_port_flag(p, tb, IFLA_BRPORT_ISOLATED, BR_ISOLATED);
 | 
						|
+	if (err)
 | 
						|
+		return err;
 | 
						|
+
 | 
						|
 	br_port_flags_change(p, old_flags ^ p->flags);
 | 
						|
 	return 0;
 | 
						|
 }
 | 
						|
--- a/net/bridge/br_private.h
 | 
						|
+++ b/net/bridge/br_private.h
 | 
						|
@@ -407,6 +407,7 @@ struct br_input_skb_cb {
 | 
						|
 #endif
 | 
						|
 
 | 
						|
 	bool proxyarp_replied;
 | 
						|
+	bool src_port_isolated;
 | 
						|
 
 | 
						|
 #ifdef CONFIG_BRIDGE_VLAN_FILTERING
 | 
						|
 	bool vlan_filtered;
 | 
						|
@@ -554,6 +555,14 @@ int br_forward_finish(struct net *net, s
 | 
						|
 void br_flood(struct net_bridge *br, struct sk_buff *skb,
 | 
						|
 	      enum br_pkt_type pkt_type, bool local_rcv, bool local_orig);
 | 
						|
 
 | 
						|
+/* return true if both source port and dest port are isolated */
 | 
						|
+static inline bool br_skb_isolated(const struct net_bridge_port *to,
 | 
						|
+				   const struct sk_buff *skb)
 | 
						|
+{
 | 
						|
+	return BR_INPUT_SKB_CB(skb)->src_port_isolated &&
 | 
						|
+	       (to->flags & BR_ISOLATED);
 | 
						|
+}
 | 
						|
+
 | 
						|
 /* br_if.c */
 | 
						|
 void br_port_carrier_check(struct net_bridge_port *p);
 | 
						|
 int br_add_bridge(struct net *net, const char *name);
 | 
						|
--- a/net/bridge/br_sysfs_if.c
 | 
						|
+++ b/net/bridge/br_sysfs_if.c
 | 
						|
@@ -174,6 +174,7 @@ BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP);
 | 
						|
 BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI);
 | 
						|
 BRPORT_ATTR_FLAG(multicast_flood, BR_MCAST_FLOOD);
 | 
						|
 BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD);
 | 
						|
+BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
 | 
						|
 
 | 
						|
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 | 
						|
 static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
 | 
						|
@@ -223,6 +224,7 @@ static const struct brport_attribute *br
 | 
						|
 	&brport_attr_proxyarp_wifi,
 | 
						|
 	&brport_attr_multicast_flood,
 | 
						|
 	&brport_attr_broadcast_flood,
 | 
						|
+	&brport_attr_isolated,
 | 
						|
 	NULL
 | 
						|
 };
 | 
						|
 
 | 
						|
--- a/include/linux/if_bridge.h
 | 
						|
+++ b/include/linux/if_bridge.h
 | 
						|
@@ -49,6 +49,7 @@ struct br_ip_list {
 | 
						|
 #define BR_MULTICAST_TO_UNICAST	BIT(12)
 | 
						|
 #define BR_VLAN_TUNNEL		BIT(13)
 | 
						|
 #define BR_BCAST_FLOOD		BIT(14)
 | 
						|
+#define BR_ISOLATED		BIT(16)
 | 
						|
 
 | 
						|
 #define BR_DEFAULT_AGEING_TIME	(300 * HZ)
 | 
						|
 
 |