[Bridge] RFC: Simple Private VLAN impl.

Joakim Tjernlund joakim.tjernlund at transmode.se
Wed Jun 10 06:32:06 PDT 2009


Even though some folks on this list thinks ebtables should be used
to deploy Private VLAN I find using ebtables a bit clumsy.

So here a first simple(RFC only) Private VLAN impl. for only Promiscuous and Isolated
mode for the linux bridge. Not tested yet.

 Jocke


diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index d2c27c8..c10362c 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -18,11 +18,30 @@
 #include <linux/netfilter_bridge.h>
 #include "br_private.h"

-/* Don't forward packets to originating port or forwarding diasabled */
-static inline int should_deliver(const struct net_bridge_port *p,
+/* Don't forward packets to originating port or forwarding disabled.
+ * Don't froward packets between private VLAN's in ISOLATED mode.
+ */
+static inline int should_deliver(const struct net_bridge_port *to,
 				 const struct sk_buff *skb)
 {
-	return (skb->dev != p->dev && p->state == BR_STATE_FORWARDING);
+	struct net_bridge_port *from = rcu_dereference(skb->dev->br_port);
+
+	if (skb->dev == to->dev || to->state != BR_STATE_FORWARDING)
+		return 0;
+	if (to->priv_vlan == PVLAN_ISOLATED &&
+	    from->priv_vlan == PVLAN_ISOLATED)
+		return 0;
+	return 1;
+}
+
+int br_set_private_vlan(struct net_bridge_port *p,
+			unsigned long v)
+{
+	if (!(v == PVLAN_ISOLATED ||
+	      v == PVLAN_PROMISC))
+		return 1;
+	p->priv_vlan = v;
+	return 0;
 }

 static inline unsigned packet_length(const struct sk_buff *skb)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index b6c3b71..6f63b7f 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -30,6 +30,10 @@
 /* Path to usermode spanning tree program */
 #define BR_STP_PROG	"/sbin/bridge-stp"

+/* Private VLAN defs */
+#define PVLAN_PROMISC 0
+#define PVLAN_ISOLATED 1
+
 typedef struct bridge_id bridge_id;
 typedef struct mac_addr mac_addr;
 typedef __u16 port_id;
@@ -67,6 +71,7 @@ struct net_bridge_port
 	/* STP */
 	u8				priority;
 	u8				state;
+	u8				priv_vlan;
 	u16				port_no;
 	unsigned char			topology_change_ack;
 	unsigned char			config_pending;
@@ -175,6 +180,7 @@ extern void br_forward(const struct net_bridge_port *to,
 extern int br_forward_finish(struct sk_buff *skb);
 extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb);
 extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb);
+extern int br_set_private_vlan(struct net_bridge_port *p, unsigned long v);

 /* br_if.c */
 extern void br_port_carrier_check(struct net_bridge_port *p);
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 02b2d50..aaaa085 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -143,6 +143,18 @@ static ssize_t store_flush(struct net_bridge_port *p, unsigned long v)
 }
 static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush);

+static ssize_t show_private_vlan(struct net_bridge_port *p, char *buf)
+{
+	return sprintf(buf, "%d\n", p->priv_vlan);
+}
+static ssize_t store_private_vlan(struct net_bridge_port *p, unsigned long v)
+{
+	return br_set_private_vlan(p, v);
+}
+static BRPORT_ATTR(private_vlan, S_IRUGO | S_IWUSR,
+		   show_private_vlan, store_private_vlan);
+
+
 static struct brport_attribute *brport_attrs[] = {
 	&brport_attr_path_cost,
 	&brport_attr_priority,
@@ -159,6 +171,7 @@ static struct brport_attribute *brport_attrs[] = {
 	&brport_attr_forward_delay_timer,
 	&brport_attr_hold_timer,
 	&brport_attr_flush,
+	&brport_attr_private_vlan,
 	NULL
 };




More information about the Bridge mailing list