diff options
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 | ||