aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_forward.c3
-rw-r--r--net/bridge/br_if.c1
-rw-r--r--net/bridge/br_private.h3
-rw-r--r--net/bridge/br_sysfs_if.c17
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 @@
22static inline int should_deliver(const struct net_bridge_port *p, 22static 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
28static inline unsigned packet_length(const struct sk_buff *skb) 29static 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
86struct net_bridge 89struct 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}
144static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush); 144static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush);
145 145
146static 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}
151static 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}
159static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR,
160 show_hairpin_mode, store_hairpin_mode);
161
146static struct brport_attribute *brport_attrs[] = { 162static 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