| 1 | --- a/net/bridge/br_private.h |
| 2 | +++ b/net/bridge/br_private.h |
| 3 | @@ -135,6 +135,7 @@ struct net_bridge_port |
| 4 | |
| 5 | unsigned long flags; |
| 6 | #define BR_HAIRPIN_MODE 0x00000001 |
| 7 | +#define BR_ISOLATE_MODE 0x00000002 |
| 8 | |
| 9 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING |
| 10 | u32 multicast_startup_queries_sent; |
| 11 | --- a/net/bridge/br_sysfs_if.c |
| 12 | +++ b/net/bridge/br_sysfs_if.c |
| 13 | @@ -149,6 +149,22 @@ static int store_hairpin_mode(struct net |
| 14 | static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR, |
| 15 | show_hairpin_mode, store_hairpin_mode); |
| 16 | |
| 17 | +static ssize_t show_isolate_mode(struct net_bridge_port *p, char *buf) |
| 18 | +{ |
| 19 | + int isolate_mode = (p->flags & BR_ISOLATE_MODE) ? 1 : 0; |
| 20 | + return sprintf(buf, "%d\n", isolate_mode); |
| 21 | +} |
| 22 | +static ssize_t store_isolate_mode(struct net_bridge_port *p, unsigned long v) |
| 23 | +{ |
| 24 | + if (v) |
| 25 | + p->flags |= BR_ISOLATE_MODE; |
| 26 | + else |
| 27 | + p->flags &= ~BR_ISOLATE_MODE; |
| 28 | + return 0; |
| 29 | +} |
| 30 | +static BRPORT_ATTR(isolate_mode, S_IRUGO | S_IWUSR, |
| 31 | + show_isolate_mode, store_isolate_mode); |
| 32 | + |
| 33 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING |
| 34 | static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) |
| 35 | { |
| 36 | @@ -181,6 +197,7 @@ static struct brport_attribute *brport_a |
| 37 | &brport_attr_hold_timer, |
| 38 | &brport_attr_flush, |
| 39 | &brport_attr_hairpin_mode, |
| 40 | + &brport_attr_isolate_mode, |
| 41 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING |
| 42 | &brport_attr_multicast_router, |
| 43 | #endif |
| 44 | --- a/net/bridge/br_input.c |
| 45 | +++ b/net/bridge/br_input.c |
| 46 | @@ -98,7 +98,8 @@ int br_handle_frame_finish(struct sk_buf |
| 47 | skb2 = skb; |
| 48 | |
| 49 | br->dev->stats.multicast++; |
| 50 | - } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) { |
| 51 | + } else if ((p->flags & BR_ISOLATE_MODE) || |
| 52 | + ((dst = __br_fdb_get(br, dest)) && dst->is_local)) { |
| 53 | skb2 = skb; |
| 54 | /* Do not forward the packet since it's local. */ |
| 55 | skb = NULL; |
| 56 | --- a/net/bridge/br_forward.c |
| 57 | +++ b/net/bridge/br_forward.c |
| 58 | @@ -109,7 +109,7 @@ void br_deliver(const struct net_bridge_ |
| 59 | /* called with rcu_read_lock */ |
| 60 | void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0) |
| 61 | { |
| 62 | - if (should_deliver(to, skb)) { |
| 63 | + if (should_deliver(to, skb) && !(to->flags & BR_ISOLATE_MODE)) { |
| 64 | if (skb0) |
| 65 | deliver_clone(to, skb, __br_forward); |
| 66 | else |
| 67 | @@ -164,7 +164,8 @@ out: |
| 68 | static void br_flood(struct net_bridge *br, struct sk_buff *skb, |
| 69 | struct sk_buff *skb0, |
| 70 | void (*__packet_hook)(const struct net_bridge_port *p, |
| 71 | - struct sk_buff *skb)) |
| 72 | + struct sk_buff *skb), |
| 73 | + bool forward) |
| 74 | { |
| 75 | struct net_bridge_port *p; |
| 76 | struct net_bridge_port *prev; |
| 77 | @@ -172,6 +173,9 @@ static void br_flood(struct net_bridge * |
| 78 | prev = NULL; |
| 79 | |
| 80 | list_for_each_entry_rcu(p, &br->port_list, list) { |
| 81 | + if (forward && (p->flags & BR_ISOLATE_MODE)) |
| 82 | + continue; |
| 83 | + |
| 84 | prev = maybe_deliver(prev, p, skb, __packet_hook); |
| 85 | if (IS_ERR(prev)) |
| 86 | goto out; |
| 87 | @@ -195,14 +199,14 @@ out: |
| 88 | /* called with rcu_read_lock */ |
| 89 | void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb) |
| 90 | { |
| 91 | - br_flood(br, skb, NULL, __br_deliver); |
| 92 | + br_flood(br, skb, NULL, __br_deliver, false); |
| 93 | } |
| 94 | |
| 95 | /* called under bridge lock */ |
| 96 | void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, |
| 97 | struct sk_buff *skb2) |
| 98 | { |
| 99 | - br_flood(br, skb, skb2, __br_forward); |
| 100 | + br_flood(br, skb, skb2, __br_forward, true); |
| 101 | } |
| 102 | |
| 103 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING |
| 104 | |