Message ID | 20120411151002.GA17739@kvack.org |
---|---|
State | Not Applicable, archived |
Delegated to: | David Miller |
Headers | show |
On Wed, 11 Apr 2012 11:10:02 -0400 Benjamin LaHaise <bcrl@kvack.org> wrote: > Hello folks, > > Attached is the first stab at a patch to make it possible to filter packets > received from other bridge ports based on the port number. This can be used > to emulate port based VLANs that some switches support. > > The justification for this is a bit interesting. Initially, I had been > filtering packets using firewall rules. Unfortunately, the number of > filter rules becomes impossible to manage when trying to filter traffic > between 100 different ports. CPU overhead of the filters is also a major > problem. > > The particular use-case I'm dealing with is simulating wireless networks > on a system using LXC containers. Each guest has a veth device that is a > member of the bridge, but the topology of which nodes can "hear" each other > changes at runtime. > > Comments/thoughts? > Nak. If firewall doesn't work then implement a better netfilter module. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Apr 11, 2012 at 08:30:52AM -0700, Stephen Hemminger wrote: > On Wed, 11 Apr 2012 11:10:02 -0400 > Benjamin LaHaise <bcrl@kvack.org> wrote: > > > Hello folks, > > > > Attached is the first stab at a patch to make it possible to filter packets > > received from other bridge ports based on the port number. This can be used > > to emulate port based VLANs that some switches support. > > > > The justification for this is a bit interesting. Initially, I had been > > filtering packets using firewall rules. Unfortunately, the number of > > filter rules becomes impossible to manage when trying to filter traffic > > between 100 different ports. CPU overhead of the filters is also a major > > problem. > > > > The particular use-case I'm dealing with is simulating wireless networks > > on a system using LXC containers. Each guest has a veth device that is a > > member of the bridge, but the topology of which nodes can "hear" each other > > changes at runtime. > > > > Comments/thoughts? > > > > Nak. If firewall doesn't work then implement a better netfilter > module. That still results in the CPU overhead of packet duplication for each and every bridge port regardless of the port receiving the packet or not. Hmmmm, would a NF_HOOK in should_deliver be okay? -ben
On Wed, 11 Apr 2012 11:36:29 -0400 Benjamin LaHaise <bcrl@kvack.org> wrote: > On Wed, Apr 11, 2012 at 08:30:52AM -0700, Stephen Hemminger wrote: > > On Wed, 11 Apr 2012 11:10:02 -0400 > > Benjamin LaHaise <bcrl@kvack.org> wrote: > > > > > Hello folks, > > > > > > Attached is the first stab at a patch to make it possible to filter packets > > > received from other bridge ports based on the port number. This can be used > > > to emulate port based VLANs that some switches support. > > > > > > The justification for this is a bit interesting. Initially, I had been > > > filtering packets using firewall rules. Unfortunately, the number of > > > filter rules becomes impossible to manage when trying to filter traffic > > > between 100 different ports. CPU overhead of the filters is also a major > > > problem. > > > > > > The particular use-case I'm dealing with is simulating wireless networks > > > on a system using LXC containers. Each guest has a veth device that is a > > > member of the bridge, but the topology of which nodes can "hear" each other > > > changes at runtime. > > > > > > Comments/thoughts? > > > > > > > Nak. If firewall doesn't work then implement a better netfilter > > module. > > That still results in the CPU overhead of packet duplication for each and > every bridge port regardless of the port receiving the packet or not. > Hmmmm, would a NF_HOOK in should_deliver be okay? Sure. Having better way to do policy would be great. Just don't want to have implementations of specific policies in generic code. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index ee64287..9b106f8 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -30,6 +30,9 @@ static int deliver_clone(const struct net_bridge_port *prev, static inline int should_deliver(const struct net_bridge_port *p, const struct sk_buff *skb) { + struct net_bridge_port *from = br_port_get_rcu(skb->dev); + if (from && test_bit(from->port_no, p->filter_ports)) + return 0; return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) && p->state == BR_STATE_FORWARDING); } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f603e5b..2f2e595 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -183,8 +183,7 @@ static int find_portno(struct net_bridge *br) struct net_bridge_port *p; unsigned long *inuse; - inuse = kcalloc(BITS_TO_LONGS(BR_MAX_PORTS), sizeof(unsigned long), - GFP_KERNEL); + inuse = kcalloc(BR_PORT_LONGS, sizeof(unsigned long), GFP_KERNEL); if (!inuse) return -ENOMEM; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d7d6fb0..c6fbab0 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -17,6 +17,7 @@ #include <linux/if_bridge.h> #include <linux/netpoll.h> #include <linux/u64_stats_sync.h> +#include <linux/bitops.h> #include <net/route.h> #define BR_HASH_BITS 8 @@ -26,6 +27,7 @@ #define BR_PORT_BITS 10 #define BR_MAX_PORTS (1<<BR_PORT_BITS) +#define BR_PORT_LONGS BITS_TO_LONGS(BR_MAX_PORTS) #define BR_VERSION "2.3" @@ -156,6 +158,8 @@ struct net_bridge_port #ifdef CONFIG_NET_POLL_CONTROLLER struct netpoll *np; #endif + + unsigned long filter_ports[BR_PORT_LONGS]; }; #define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT) diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 6229b62..9d95f6a 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -164,6 +164,24 @@ static BRPORT_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router, store_multicast_router); #endif +static int store_add_filter_port(struct net_bridge_port *p, unsigned long v) +{ + if (v >= BR_MAX_PORTS) + return -EINVAL; + set_bit(v, p->filter_ports); + return 0; +} +static BRPORT_ATTR(add_filter_port, S_IWUSR, NULL, store_add_filter_port); + +static int store_remove_filter_port(struct net_bridge_port *p, unsigned long v) +{ + if (v >= BR_MAX_PORTS) + return -EINVAL; + clear_bit(v, p->filter_ports); + return 0; +} +static BRPORT_ATTR(remove_filter_port, S_IWUSR, NULL, store_remove_filter_port); + static struct brport_attribute *brport_attrs[] = { &brport_attr_path_cost, &brport_attr_priority, @@ -184,6 +202,8 @@ static struct brport_attribute *brport_attrs[] = { #ifdef CONFIG_BRIDGE_IGMP_SNOOPING &brport_attr_multicast_router, #endif + &brport_attr_add_filter_port, + &brport_attr_remove_filter_port, NULL };