diff options
author | Fischer, Anna <anna.fischer@hp.com> | 2009-08-13 02:55:16 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-13 19:26:11 -0400 |
commit | 3982d3d28b02bed5312015762fe2112ccbaf9051 (patch) | |
tree | 783332d9c3983924dfc102b8a2f8147ad5bd078c /net/bridge | |
parent | 8dd07086a1f8048428d33a1917b6209978750cb1 (diff) |
net/bridge: Add 'hairpin' port forwarding mode
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>
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br_forward.c | 3 | ||||
-rw-r--r-- | net/bridge/br_if.c | 1 | ||||
-rw-r--r-- | net/bridge/br_private.h | 3 | ||||
-rw-r--r-- | net/bridge/br_sysfs_if.c | 17 |
4 files changed, 23 insertions, 1 deletions
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index d2c27c808d3b..bc1704ac6cd9 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
@@ -22,7 +22,8 @@ | |||
22 | static inline int should_deliver(const struct net_bridge_port *p, | 22 | static inline int should_deliver(const struct net_bridge_port *p, |
23 | const struct sk_buff *skb) | 23 | const struct sk_buff *skb) |
24 | { | 24 | { |
25 | return (skb->dev != p->dev && p->state == BR_STATE_FORWARDING); | 25 | return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) && |
26 | p->state == BR_STATE_FORWARDING); | ||
26 | } | 27 | } |
27 | 28 | ||
28 | static inline unsigned packet_length(const struct sk_buff *skb) | 29 | static inline unsigned packet_length(const struct sk_buff *skb) |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index eb404dc3ed6e..e486f1fc3632 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -256,6 +256,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, | |||
256 | p->path_cost = port_cost(dev); | 256 | p->path_cost = port_cost(dev); |
257 | p->priority = 0x8000 >> BR_PORT_BITS; | 257 | p->priority = 0x8000 >> BR_PORT_BITS; |
258 | p->port_no = index; | 258 | p->port_no = index; |
259 | p->flags = 0; | ||
259 | br_init_port(p); | 260 | br_init_port(p); |
260 | p->state = BR_STATE_DISABLED; | 261 | p->state = BR_STATE_DISABLED; |
261 | br_stp_port_timer_init(p); | 262 | br_stp_port_timer_init(p); |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d5b5537272b4..8319247dad5d 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -81,6 +81,9 @@ struct net_bridge_port | |||
81 | struct timer_list message_age_timer; | 81 | struct timer_list message_age_timer; |
82 | struct kobject kobj; | 82 | struct kobject kobj; |
83 | struct rcu_head rcu; | 83 | struct rcu_head rcu; |
84 | |||
85 | unsigned long flags; | ||
86 | #define BR_HAIRPIN_MODE 0x00000001 | ||
84 | }; | 87 | }; |
85 | 88 | ||
86 | struct net_bridge | 89 | struct net_bridge |
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 4a3cdf8f3813..820643a3ba9c 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c | |||
@@ -143,6 +143,22 @@ static ssize_t store_flush(struct net_bridge_port *p, unsigned long v) | |||
143 | } | 143 | } |
144 | static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush); | 144 | static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush); |
145 | 145 | ||
146 | static ssize_t show_hairpin_mode(struct net_bridge_port *p, char *buf) | ||
147 | { | ||
148 | int hairpin_mode = (p->flags & BR_HAIRPIN_MODE) ? 1 : 0; | ||
149 | return sprintf(buf, "%d\n", hairpin_mode); | ||
150 | } | ||
151 | static ssize_t store_hairpin_mode(struct net_bridge_port *p, unsigned long v) | ||
152 | { | ||
153 | if (v) | ||
154 | p->flags |= BR_HAIRPIN_MODE; | ||
155 | else | ||
156 | p->flags &= ~BR_HAIRPIN_MODE; | ||
157 | return 0; | ||
158 | } | ||
159 | static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR, | ||
160 | show_hairpin_mode, store_hairpin_mode); | ||
161 | |||
146 | static struct brport_attribute *brport_attrs[] = { | 162 | static struct brport_attribute *brport_attrs[] = { |
147 | &brport_attr_path_cost, | 163 | &brport_attr_path_cost, |
148 | &brport_attr_priority, | 164 | &brport_attr_priority, |
@@ -159,6 +175,7 @@ static struct brport_attribute *brport_attrs[] = { | |||
159 | &brport_attr_forward_delay_timer, | 175 | &brport_attr_forward_delay_timer, |
160 | &brport_attr_hold_timer, | 176 | &brport_attr_hold_timer, |
161 | &brport_attr_flush, | 177 | &brport_attr_flush, |
178 | &brport_attr_hairpin_mode, | ||
162 | NULL | 179 | NULL |
163 | }; | 180 | }; |
164 | 181 | ||