|
@@ -85,6 +85,82 @@ void br_port_carrier_check(struct net_bridge_port *p)
|
|
|
spin_unlock_bh(&br->lock);
|
|
|
}
|
|
|
|
|
|
+static void br_port_set_promisc(struct net_bridge_port *p)
|
|
|
+{
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+ if (br_promisc_port(p))
|
|
|
+ return;
|
|
|
+
|
|
|
+ err = dev_set_promiscuity(p->dev, 1);
|
|
|
+ if (err)
|
|
|
+ return;
|
|
|
+
|
|
|
+ br_fdb_unsync_static(p->br, p);
|
|
|
+ p->flags |= BR_PROMISC;
|
|
|
+}
|
|
|
+
|
|
|
+static void br_port_clear_promisc(struct net_bridge_port *p)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ /* Check if the port is already non-promisc or if it doesn't
|
|
|
+ * support UNICAST filtering. Without unicast filtering support
|
|
|
+ * we'll end up re-enabling promisc mode anyway, so just check for
|
|
|
+ * it here.
|
|
|
+ */
|
|
|
+ if (!br_promisc_port(p) || !(p->dev->priv_flags & IFF_UNICAST_FLT))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Since we'll be clearing the promisc mode, program the port
|
|
|
+ * first so that we don't have interruption in traffic.
|
|
|
+ */
|
|
|
+ err = br_fdb_sync_static(p->br, p);
|
|
|
+ if (err)
|
|
|
+ return;
|
|
|
+
|
|
|
+ dev_set_promiscuity(p->dev, -1);
|
|
|
+ p->flags &= ~BR_PROMISC;
|
|
|
+}
|
|
|
+
|
|
|
+/* When a port is added or removed or when certain port flags
|
|
|
+ * change, this function is called to automatically manage
|
|
|
+ * promiscuity setting of all the bridge ports. We are always called
|
|
|
+ * under RTNL so can skip using rcu primitives.
|
|
|
+ */
|
|
|
+void br_manage_promisc(struct net_bridge *br)
|
|
|
+{
|
|
|
+ struct net_bridge_port *p;
|
|
|
+ bool set_all = false;
|
|
|
+
|
|
|
+ /* If vlan filtering is disabled or bridge interface is placed
|
|
|
+ * into promiscuous mode, place all ports in promiscuous mode.
|
|
|
+ */
|
|
|
+ if ((br->dev->flags & IFF_PROMISC) || !br_vlan_enabled(br))
|
|
|
+ set_all = true;
|
|
|
+
|
|
|
+ list_for_each_entry(p, &br->port_list, list) {
|
|
|
+ if (set_all) {
|
|
|
+ br_port_set_promisc(p);
|
|
|
+ } else {
|
|
|
+ /* If the number of auto-ports is <= 1, then all other
|
|
|
+ * ports will have their output configuration
|
|
|
+ * statically specified through fdbs. Since ingress
|
|
|
+ * on the auto-port becomes forwarding/egress to other
|
|
|
+ * ports and egress configuration is statically known,
|
|
|
+ * we can say that ingress configuration of the
|
|
|
+ * auto-port is also statically known.
|
|
|
+ * This lets us disable promiscuous mode and write
|
|
|
+ * this config to hw.
|
|
|
+ */
|
|
|
+ if (br->auto_cnt <= br_auto_port(p))
|
|
|
+ br_port_clear_promisc(p);
|
|
|
+ else
|
|
|
+ br_port_set_promisc(p);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void nbp_update_port_count(struct net_bridge *br)
|
|
|
{
|
|
|
struct net_bridge_port *p;
|
|
@@ -94,7 +170,23 @@ static void nbp_update_port_count(struct net_bridge *br)
|
|
|
if (br_auto_port(p))
|
|
|
cnt++;
|
|
|
}
|
|
|
- br->auto_cnt = cnt;
|
|
|
+ if (br->auto_cnt != cnt) {
|
|
|
+ br->auto_cnt = cnt;
|
|
|
+ br_manage_promisc(br);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void nbp_delete_promisc(struct net_bridge_port *p)
|
|
|
+{
|
|
|
+ /* If port is currently promiscous, unset promiscuity.
|
|
|
+ * Otherwise, it is a static port so remove all addresses
|
|
|
+ * from it.
|
|
|
+ */
|
|
|
+ dev_set_allmulti(p->dev, -1);
|
|
|
+ if (br_promisc_port(p))
|
|
|
+ dev_set_promiscuity(p->dev, -1);
|
|
|
+ else
|
|
|
+ br_fdb_unsync_static(p->br, p);
|
|
|
}
|
|
|
|
|
|
static void release_nbp(struct kobject *kobj)
|
|
@@ -145,7 +237,7 @@ static void del_nbp(struct net_bridge_port *p)
|
|
|
|
|
|
sysfs_remove_link(br->ifobj, p->dev->name);
|
|
|
|
|
|
- dev_set_promiscuity(dev, -1);
|
|
|
+ nbp_delete_promisc(p);
|
|
|
|
|
|
spin_lock_bh(&br->lock);
|
|
|
br_stp_disable_port(p);
|
|
@@ -153,11 +245,10 @@ static void del_nbp(struct net_bridge_port *p)
|
|
|
|
|
|
br_ifinfo_notify(RTM_DELLINK, p);
|
|
|
|
|
|
- nbp_vlan_flush(p);
|
|
|
- br_fdb_delete_by_port(br, p, 1);
|
|
|
-
|
|
|
list_del_rcu(&p->list);
|
|
|
|
|
|
+ nbp_vlan_flush(p);
|
|
|
+ br_fdb_delete_by_port(br, p, 1);
|
|
|
nbp_update_port_count(br);
|
|
|
|
|
|
dev->priv_flags &= ~IFF_BRIDGE_PORT;
|
|
@@ -238,7 +329,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 = BR_LEARNING | BR_FLOOD | BR_PROMISC;
|
|
|
+ p->flags = BR_LEARNING | BR_FLOOD;
|
|
|
br_init_port(p);
|
|
|
p->state = BR_STATE_DISABLED;
|
|
|
br_stp_port_timer_init(p);
|
|
@@ -367,7 +458,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
|
|
|
|
|
|
call_netdevice_notifiers(NETDEV_JOIN, dev);
|
|
|
|
|
|
- err = dev_set_promiscuity(dev, 1);
|
|
|
+ err = dev_set_allmulti(dev, 1);
|
|
|
if (err)
|
|
|
goto put_back;
|
|
|
|