diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index d2c27c808d3..bc1704ac6cd 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -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) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index eb404dc3ed6..e486f1fc363 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, 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); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d5b5537272b..8319247dad5 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -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 diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 4a3cdf8f381..820643a3ba9 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) } 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 };