|
|
@@ -0,0 +1,103 @@
|
|
|
+--- a/net/bridge/br_private.h
|
|
|
++++ b/net/bridge/br_private.h
|
|
|
+@@ -132,6 +132,7 @@ struct net_bridge_port
|
|
|
+
|
|
|
+ unsigned long flags;
|
|
|
+ #define BR_HAIRPIN_MODE 0x00000001
|
|
|
++#define BR_ISOLATE_MODE 0x00000002
|
|
|
+
|
|
|
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
|
|
+ u32 multicast_startup_queries_sent;
|
|
|
+--- a/net/bridge/br_sysfs_if.c
|
|
|
++++ b/net/bridge/br_sysfs_if.c
|
|
|
+@@ -159,6 +159,22 @@ static ssize_t store_hairpin_mode(struct
|
|
|
+ static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR,
|
|
|
+ show_hairpin_mode, store_hairpin_mode);
|
|
|
+
|
|
|
++static ssize_t show_isolate_mode(struct net_bridge_port *p, char *buf)
|
|
|
++{
|
|
|
++ int isolate_mode = (p->flags & BR_ISOLATE_MODE) ? 1 : 0;
|
|
|
++ return sprintf(buf, "%d\n", isolate_mode);
|
|
|
++}
|
|
|
++static ssize_t store_isolate_mode(struct net_bridge_port *p, unsigned long v)
|
|
|
++{
|
|
|
++ if (v)
|
|
|
++ p->flags |= BR_ISOLATE_MODE;
|
|
|
++ else
|
|
|
++ p->flags &= ~BR_ISOLATE_MODE;
|
|
|
++ return 0;
|
|
|
++}
|
|
|
++static BRPORT_ATTR(isolate_mode, S_IRUGO | S_IWUSR,
|
|
|
++ show_isolate_mode, store_isolate_mode);
|
|
|
++
|
|
|
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
|
|
+ static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
|
|
|
+ {
|
|
|
+@@ -191,6 +207,7 @@ static struct brport_attribute *brport_a
|
|
|
+ &brport_attr_hold_timer,
|
|
|
+ &brport_attr_flush,
|
|
|
+ &brport_attr_hairpin_mode,
|
|
|
++ &brport_attr_isolate_mode,
|
|
|
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
|
|
+ &brport_attr_multicast_router,
|
|
|
+ #endif
|
|
|
+--- a/net/bridge/br_input.c
|
|
|
++++ b/net/bridge/br_input.c
|
|
|
+@@ -91,7 +91,8 @@ int br_handle_frame_finish(struct sk_buf
|
|
|
+ skb2 = skb;
|
|
|
+
|
|
|
+ br->dev->stats.multicast++;
|
|
|
+- } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
|
|
|
++ } else if ((p->flags & BR_ISOLATE_MODE) ||
|
|
|
++ ((dst = __br_fdb_get(br, dest)) && dst->is_local)) {
|
|
|
+ skb2 = skb;
|
|
|
+ /* Do not forward the packet since it's local. */
|
|
|
+ skb = NULL;
|
|
|
+--- a/net/bridge/br_forward.c
|
|
|
++++ b/net/bridge/br_forward.c
|
|
|
+@@ -113,7 +113,7 @@ void br_deliver(const struct net_bridge_
|
|
|
+ /* called with rcu_read_lock */
|
|
|
+ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
|
|
|
+ {
|
|
|
+- if (should_deliver(to, skb)) {
|
|
|
++ if (should_deliver(to, skb) && !(to->flags & BR_ISOLATE_MODE)) {
|
|
|
+ if (skb0)
|
|
|
+ deliver_clone(to, skb, __br_forward);
|
|
|
+ else
|
|
|
+@@ -168,7 +168,8 @@ out:
|
|
|
+ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
|
|
|
+ struct sk_buff *skb0,
|
|
|
+ void (*__packet_hook)(const struct net_bridge_port *p,
|
|
|
+- struct sk_buff *skb))
|
|
|
++ struct sk_buff *skb),
|
|
|
++ bool forward)
|
|
|
+ {
|
|
|
+ struct net_bridge_port *p;
|
|
|
+ struct net_bridge_port *prev;
|
|
|
+@@ -176,6 +177,9 @@ static void br_flood(struct net_bridge *
|
|
|
+ prev = NULL;
|
|
|
+
|
|
|
+ list_for_each_entry_rcu(p, &br->port_list, list) {
|
|
|
++ if (forward && (p->flags & BR_ISOLATE_MODE))
|
|
|
++ continue;
|
|
|
++
|
|
|
+ prev = maybe_deliver(prev, p, skb, __packet_hook);
|
|
|
+ if (IS_ERR(prev))
|
|
|
+ goto out;
|
|
|
+@@ -199,14 +203,14 @@ out:
|
|
|
+ /* called with rcu_read_lock */
|
|
|
+ void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
|
|
|
+ {
|
|
|
+- br_flood(br, skb, NULL, __br_deliver);
|
|
|
++ br_flood(br, skb, NULL, __br_deliver, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* called under bridge lock */
|
|
|
+ void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
|
|
|
+ struct sk_buff *skb2)
|
|
|
+ {
|
|
|
+- br_flood(br, skb, skb2, __br_forward);
|
|
|
++ br_flood(br, skb, skb2, __br_forward, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|