Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit faa1cd82 authored by Nikolay Aleksandrov's avatar Nikolay Aleksandrov Committed by David S. Miller
Browse files

net: bridge: avoid duplicate notification on up/down/change netdev events



While handling netdevice events, br_device_event() sometimes uses
br_stp_(disable|enable)_port which unconditionally send a notification,
but then a second notification for the same event is sent at the end of
the br_device_event() function. To avoid sending duplicate notifications
in such cases, check if one has already been sent (i.e.
br_stp_enable/disable_port have been called).
The patch is based on a change by Satish Ashok.

Signed-off-by: default avatarNikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2e518551
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
	struct net_bridge_port *p;
	struct net_bridge *br;
	bool notified = false;
	bool changed_addr;
	int err;

@@ -67,7 +68,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
		break;

	case NETDEV_CHANGE:
		br_port_carrier_check(p);
		br_port_carrier_check(p, &notified);
		break;

	case NETDEV_FEAT_CHANGE:
@@ -76,8 +77,10 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v

	case NETDEV_DOWN:
		spin_lock_bh(&br->lock);
		if (br->dev->flags & IFF_UP)
		if (br->dev->flags & IFF_UP) {
			br_stp_disable_port(p);
			notified = true;
		}
		spin_unlock_bh(&br->lock);
		break;

@@ -85,6 +88,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
		if (netif_running(br->dev) && netif_oper_up(dev)) {
			spin_lock_bh(&br->lock);
			br_stp_enable_port(p);
			notified = true;
			spin_unlock_bh(&br->lock);
		}
		break;
@@ -110,8 +114,8 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
	}

	/* Events that may cause spanning tree to refresh */
	if (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||
	    event == NETDEV_CHANGE || event == NETDEV_DOWN)
	if (!notified && (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||
			  event == NETDEV_CHANGE || event == NETDEV_DOWN))
		br_ifinfo_notify(RTM_NEWLINK, NULL, p);

	return NOTIFY_DONE;
+8 −3
Original line number Diff line number Diff line
@@ -64,7 +64,7 @@ static int port_cost(struct net_device *dev)


/* Check for port carrier transitions. */
void br_port_carrier_check(struct net_bridge_port *p)
void br_port_carrier_check(struct net_bridge_port *p, bool *notified)
{
	struct net_device *dev = p->dev;
	struct net_bridge *br = p->br;
@@ -73,16 +73,21 @@ void br_port_carrier_check(struct net_bridge_port *p)
	    netif_running(dev) && netif_oper_up(dev))
		p->path_cost = port_cost(dev);

	*notified = false;
	if (!netif_running(br->dev))
		return;

	spin_lock_bh(&br->lock);
	if (netif_running(dev) && netif_oper_up(dev)) {
		if (p->state == BR_STATE_DISABLED)
		if (p->state == BR_STATE_DISABLED) {
			br_stp_enable_port(p);
			*notified = true;
		}
	} else {
		if (p->state != BR_STATE_DISABLED)
		if (p->state != BR_STATE_DISABLED) {
			br_stp_disable_port(p);
			*notified = true;
		}
	}
	spin_unlock_bh(&br->lock);
}
+1 −1
Original line number Diff line number Diff line
@@ -573,7 +573,7 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb,
	      enum br_pkt_type pkt_type, bool local_rcv, bool local_orig);

/* br_if.c */
void br_port_carrier_check(struct net_bridge_port *p);
void br_port_carrier_check(struct net_bridge_port *p, bool *notified);
int br_add_bridge(struct net *net, const char *name);
int br_del_bridge(struct net *net, const char *name);
int br_add_if(struct net_bridge *br, struct net_device *dev,