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 };
On Wed, 10 Jun 2009 15:32:06 +0200 Joakim Tjernlund <joakim.tjernlund at transmode.se> wrote:> > Even though some folks on this list thinks ebtables should be used > to deploy Private VLAN I find using ebtables a bit clumsy. >I prefer ebtables be used to "patch" bridge to do these kind of special case things. Remember any code that is put in mainline adds additional API's and long term support burden.
Joakim Tjernlund/Transmode wrote on 10/06/2009 19:09:09:> > Ross Vandegrift <ross at kallisti.us> wrote on 10/06/2009 18:27:52: > > > > On Wed, Jun 10, 2009 at 05:32:06PM +0200, Joakim Tjernlund wrote: > > > I am not sure this is so special anymore. I know that this > > > adds "support burden" but so does a lot of stuff in the kernel. > > > > Private VLANs are additional restrictions on a bridge's filtering > > database. No kernel support is required because Linux (via ebtables) > > has a much more generic way to affect the filtering of frames. > > hmm, yes I am starting to get a grip on this now. > > > > > Have anybody managed to do Private VLAN with several switches by > > > just using ebtables? Seems like most people here thinks that > > > ebtables is the right tool but none has provided any examples > > > on how to do it so I am starting to think that noone is so the > > > claim to just use ebtables might be false. > > > > I don't have a Linux machine with enough interfaces to build a > > meaningful private VLAN config, but I can step you though a simple > > conceptual explanation. > > > > One very common installation I can think of - a single router > > provides service to many clients in the same VLAN which must be > > isolated. Say the router is using eth0 and the clients are on > > eth1-ethX. > > > > Then what you want to do looks something like the following: > > > > 0) Deny all frames not explicitly permitted: > > ebtables -P FORWARD DENY > > > > 1) Permit any frames with ingress eth0: > > ebtables -A FORWARD -i eth0 -j ACCEPT > > > > 2) Permit any frames with egress interface eth0. > > ebtables -A FORWARD -o eth0 -j ACCEPT > > > > > > Think about ebtables as a low-level way to specify policy for the > > handling of frames, much in the same way that iptables is a low-level > > way to specify policy for IP packets. > > I have managed to convince myself that I can do Private VLAN with ebtables, > even between bridges :) > I do need some help to figure out how to setup the ebtable rules in an simple > manner that allows me to add/remove ports and also flip between Isolated and > Promiscuous port mode. > > Check out http://www.rfc-editor.org/internet-drafts/draft-sanjib-private-vlan-10.txt , > Table 1 and ignore community ports for now: > --------------------------------------------------------------- > | | isolat-| promis-| commu-| commu-| interswitch | > | | ted | cuous | nity1 | nity2 | link port | > --------------------------------------------------------------- > | isolated | deny | permit | deny | deny | permit | > --------------------------------------------------------------- > | promiscuous | permit | permit | permit| permit| permit | > --------------------------------------------------------------- > | community1 | deny | permit | permit| deny | permit | > --------------------------------------------------------------- > | community2 | deny | permit | deny | permit| permit | > --------------------------------------------------------------- > | interswitch | | | | | | > | link port | deny(*)| permit | permit| permit| permit | > --------------------------------------------------------------- > > (*) Please note that this asymmetric behavior is for traffic > traversing inter-switch link ports over an isolated VLAN only. > Traffic from an inter-switch link port to an isolated port will be > denied if it is in the isolated VLAN. Traffic from an inter-switch > link port to an isolated port will be permitted if it is in the > primary VLAN (see below for the different VLAN characteristics). > > N.B.: An interswitch link port is simply a regular port that > connects two switches (and that happens to carry two or more VLANs).These are the rules i come up with when I have a bridge with four interfaces. Promisc, Isolated, Community and a Interswitch port. The Interswitch port is modelled with 3 VLANs 4042, 4043 and 4044 #Static rules #.4042 = Promisc/primary VLAN #.4043 = Isolated VLAN #.4042 = Community VLAN #These VLANs represent the interswitch port #Do not leak pkgs between the above VLANs ./ebtables -A FORWARD -i eth0.4042 -o eth0.4043 -j DROP ./ebtables -A FORWARD -i eth0.4042 -o eth0.4044 -j DROP ./ebtables -A FORWARD -i eth0.4043 -o eth0.4042 -j DROP ./ebtables -A FORWARD -i eth0.4043 -o eth0.4044 -j DROP ./ebtables -A FORWARD -i eth0.4044 -o eth0.4042 -j DROP ./ebtables -A FORWARD -i eth0.4044 -o eth0.4043 -j DROP #Port rules #Promisc Port, eth1.1 ./ebtables -A FORWARD -i eth1.1 -o eth0.4043 -j DROP ./ebtables -A FORWARD -i eth1.1 -o eth0.4044 -j DROP #Isolated Port, eth1.2 ./ebtables -A FORWARD -i eth1.2 -o eth0.4043 -j ACCEPT ./ebtables -A FORWARD -i eth1.2 -o eth1.1 -j ACCEPT ./ebtables -A FORWARD -i eth1.2 -j DROP ./ebtables -A FORWARD -o eth1.2 -i eth0.4042 -j ACCEPT ./ebtables -A FORWARD -o eth1.2 -i eth1.1 -j ACCEPT ./ebtables -A FORWARD -o eth1.2 -j DROP #Community Port, eth1.3 ./ebtables -A FORWARD -i eth1.3 -o eth0.4042 -j ACCEPT ./ebtables -A FORWARD -i eth1.3 -o eth0.4044 -j ACCEPT ./ebtables -A FORWARD -i eth1.3 -j DROP ./ebtables -A FORWARD -o eth1.3 -i eth0.4042 -j ACCEPT ./ebtables -A FORWARD -o eth1.3 -i eth0.4044 -j ACCEPT ./ebtables -A FORWARD -o eth1.3 -i eth1.1 -j ACCEPT ./ebtables -A FORWARD -o eth1.3 -j DROP This is getting out of control. I was hoping there would be a simpler way to express the above. Adding ports or changing roles won't be funny. Anyone? Jocke