net/bridge: Add 'hairpin' port forwarding mode
authorFischer, Anna <anna.fischer@hp.com>
Thu, 13 Aug 2009 06:55:16 +0000 (06:55 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 13 Aug 2009 23:26:11 +0000 (16:26 -0700)
This patch adds a 'hairpin' (also called 'reflective relay') mode
port configuration to the Linux Ethernet bridge kernel module.
A bridge supporting hairpin forwarding mode can send frames back
out through the port the frame was received on.

Hairpin mode is required to support basic VEPA (Virtual
Ethernet Port Aggregator) capabilities.

You can find additional information on VEPA here:
http://tech.groups.yahoo.com/group/evb/
http://www.ieee802.org/1/files/public/docs2009/new-hudson-vepa_seminar-20090514d.pdf
http://www.internet2.edu/presentations/jt2009jul/20090719-congdon.pdf

An additional patch 'bridge-utils: Add 'hairpin' port forwarding mode'
is provided to allow configuring hairpin mode from userspace tools.

Signed-off-by: Paul Congdon <paul.congdon@hp.com>
Signed-off-by: Anna Fischer <anna.fischer@hp.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/bridge/br_forward.c
net/bridge/br_if.c
net/bridge/br_private.h
net/bridge/br_sysfs_if.c

index d2c27c808d3bad3cb7b782f731c39345098c7df6..bc1704ac6cd9f68f2b73e36443a3c8162b5f5fe1 100644 (file)
@@ -22,7 +22,8 @@
 static inline int should_deliver(const struct net_bridge_port *p,
                                 const struct sk_buff *skb)
 {
-       return (skb->dev != p->dev && p->state == BR_STATE_FORWARDING);
+       return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
+               p->state == BR_STATE_FORWARDING);
 }
 
 static inline unsigned packet_length(const struct sk_buff *skb)
index eb404dc3ed6e213e4148ba1f7b13bb1d0570a4e1..e486f1fc36324e74868d348eb9e09af2d6419fac 100644 (file)
@@ -256,6 +256,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
        p->path_cost = port_cost(dev);
        p->priority = 0x8000 >> BR_PORT_BITS;
        p->port_no = index;
+       p->flags = 0;
        br_init_port(p);
        p->state = BR_STATE_DISABLED;
        br_stp_port_timer_init(p);
index d5b5537272b47af9c1e8abdcc7a693ac6a7e63cd..8319247dad5db6c555911b7a5f9f5ad75bfe216a 100644 (file)
@@ -81,6 +81,9 @@ struct net_bridge_port
        struct timer_list               message_age_timer;
        struct kobject                  kobj;
        struct rcu_head                 rcu;
+
+       unsigned long                   flags;
+#define BR_HAIRPIN_MODE                0x00000001
 };
 
 struct net_bridge
index 4a3cdf8f38131e6b19adf330a0e697a307a39e16..820643a3ba9c35e98d1b679e50bfbac22e987aa3 100644 (file)
@@ -143,6 +143,22 @@ 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_hairpin_mode(struct net_bridge_port *p, char *buf)
+{
+       int hairpin_mode = (p->flags & BR_HAIRPIN_MODE) ? 1 : 0;
+       return sprintf(buf, "%d\n", hairpin_mode);
+}
+static ssize_t store_hairpin_mode(struct net_bridge_port *p, unsigned long v)
+{
+       if (v)
+               p->flags |= BR_HAIRPIN_MODE;
+       else
+               p->flags &= ~BR_HAIRPIN_MODE;
+       return 0;
+}
+static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR,
+                  show_hairpin_mode, store_hairpin_mode);
+
 static struct brport_attribute *brport_attrs[] = {
        &brport_attr_path_cost,
        &brport_attr_priority,
@@ -159,6 +175,7 @@ static struct brport_attribute *brport_attrs[] = {
        &brport_attr_forward_delay_timer,
        &brport_attr_hold_timer,
        &brport_attr_flush,
+       &brport_attr_hairpin_mode,
        NULL
 };