Commit 92899063 authored by Nikolay Aleksandrov's avatar Nikolay Aleksandrov Committed by David S. Miller

net: bridge: add notifications for the bridge dev on vlan change

Currently the bridge device doesn't generate any notifications upon vlan
modifications on itself because it doesn't use the generic bridge
notifications.
With the recent changes we know if anything was modified in the vlan config
thus we can generate a notification when necessary for the bridge device
so add support to br_ifinfo_notify() similar to how other combined
functions are done - if port is present it takes precedence, otherwise
notify about the bridge. I've explicitly marked the locations where the
notification should be always for the port by setting bridge to NULL.
I've also taken the liberty to rearrange each modified function's local
variables in reverse xmas tree as well.
Signed-off-by: default avatarNikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ad88d35a
...@@ -112,7 +112,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v ...@@ -112,7 +112,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
/* Events that may cause spanning tree to refresh */ /* Events that may cause spanning tree to refresh */
if (event == NETDEV_CHANGEADDR || event == NETDEV_UP || if (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||
event == NETDEV_CHANGE || event == NETDEV_DOWN) event == NETDEV_CHANGE || event == NETDEV_DOWN)
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, NULL, p);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
......
...@@ -271,7 +271,7 @@ static void del_nbp(struct net_bridge_port *p) ...@@ -271,7 +271,7 @@ static void del_nbp(struct net_bridge_port *p)
br_stp_disable_port(p); br_stp_disable_port(p);
spin_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
br_ifinfo_notify(RTM_DELLINK, p); br_ifinfo_notify(RTM_DELLINK, NULL, p);
list_del_rcu(&p->list); list_del_rcu(&p->list);
if (netdev_get_fwd_headroom(dev) == br->dev->needed_headroom) if (netdev_get_fwd_headroom(dev) == br->dev->needed_headroom)
...@@ -589,7 +589,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, ...@@ -589,7 +589,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
br_stp_enable_port(p); br_stp_enable_port(p);
spin_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, NULL, p);
if (changed_addr) if (changed_addr)
call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
......
...@@ -293,7 +293,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -293,7 +293,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!ret) { if (!ret) {
if (p) if (p)
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, NULL, p);
else else
netdev_state_change(br->dev); netdev_state_change(br->dev);
} }
......
...@@ -361,14 +361,14 @@ static int br_fill_ifvlaninfo(struct sk_buff *skb, ...@@ -361,14 +361,14 @@ static int br_fill_ifvlaninfo(struct sk_buff *skb,
* Contains port and master info as well as carrier and bridge state. * Contains port and master info as well as carrier and bridge state.
*/ */
static int br_fill_ifinfo(struct sk_buff *skb, static int br_fill_ifinfo(struct sk_buff *skb,
struct net_bridge_port *port, const struct net_bridge_port *port,
u32 pid, u32 seq, int event, unsigned int flags, u32 pid, u32 seq, int event, unsigned int flags,
u32 filter_mask, const struct net_device *dev) u32 filter_mask, const struct net_device *dev)
{ {
u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
struct net_bridge *br; struct net_bridge *br;
struct ifinfomsg *hdr; struct ifinfomsg *hdr;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
if (port) if (port)
br = port->br; br = port->br;
...@@ -454,28 +454,36 @@ static int br_fill_ifinfo(struct sk_buff *skb, ...@@ -454,28 +454,36 @@ static int br_fill_ifinfo(struct sk_buff *skb,
return -EMSGSIZE; return -EMSGSIZE;
} }
/* /* Notify listeners of a change in bridge or port information */
* Notify listeners of a change in port information void br_ifinfo_notify(int event, const struct net_bridge *br,
*/ const struct net_bridge_port *port)
void br_ifinfo_notify(int event, struct net_bridge_port *port)
{ {
struct net *net; u32 filter = RTEXT_FILTER_BRVLAN_COMPRESSED;
struct net_device *dev;
struct sk_buff *skb; struct sk_buff *skb;
int err = -ENOBUFS; int err = -ENOBUFS;
u32 filter = RTEXT_FILTER_BRVLAN_COMPRESSED; struct net *net;
u16 port_no = 0;
if (!port) if (WARN_ON(!port && !br))
return; return;
net = dev_net(port->dev); if (port) {
br_debug(port->br, "port %u(%s) event %d\n", dev = port->dev;
(unsigned int)port->port_no, port->dev->name, event); br = port->br;
port_no = port->port_no;
} else {
dev = br->dev;
}
net = dev_net(dev);
br_debug(br, "port %u(%s) event %d\n", port_no, dev->name, event);
skb = nlmsg_new(br_nlmsg_size(port->dev, filter), GFP_ATOMIC); skb = nlmsg_new(br_nlmsg_size(dev, filter), GFP_ATOMIC);
if (skb == NULL) if (skb == NULL)
goto errout; goto errout;
err = br_fill_ifinfo(skb, port, 0, 0, event, 0, filter, port->dev); err = br_fill_ifinfo(skb, port, 0, 0, event, 0, filter, dev);
if (err < 0) { if (err < 0) {
/* -EMSGSIZE implies BUG in br_nlmsg_size() */ /* -EMSGSIZE implies BUG in br_nlmsg_size() */
WARN_ON(err == -EMSGSIZE); WARN_ON(err == -EMSGSIZE);
...@@ -488,7 +496,6 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port) ...@@ -488,7 +496,6 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
rtnl_set_sk_err(net, RTNLGRP_LINK, err); rtnl_set_sk_err(net, RTNLGRP_LINK, err);
} }
/* /*
* Dump information about all ports, in response to GETLINK * Dump information about all ports, in response to GETLINK
*/ */
...@@ -809,10 +816,11 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) ...@@ -809,10 +816,11 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
/* Change state and parameters on port. */ /* Change state and parameters on port. */
int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags)
{ {
struct net_bridge *br = (struct net_bridge *)netdev_priv(dev);
struct nlattr *tb[IFLA_BRPORT_MAX + 1];
struct net_bridge_port *p;
struct nlattr *protinfo; struct nlattr *protinfo;
struct nlattr *afspec; struct nlattr *afspec;
struct net_bridge_port *p;
struct nlattr *tb[IFLA_BRPORT_MAX + 1];
bool changed = false; bool changed = false;
int err = 0; int err = 0;
...@@ -852,13 +860,11 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) ...@@ -852,13 +860,11 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags)
changed = true; changed = true;
} }
if (afspec) { if (afspec)
err = br_afspec((struct net_bridge *)netdev_priv(dev), p, err = br_afspec(br, p, afspec, RTM_SETLINK, &changed);
afspec, RTM_SETLINK, &changed);
}
if (changed) if (changed)
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, br, p);
out: out:
return err; return err;
} }
...@@ -866,8 +872,9 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) ...@@ -866,8 +872,9 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags)
/* Delete port information */ /* Delete port information */
int br_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) int br_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags)
{ {
struct nlattr *afspec; struct net_bridge *br = (struct net_bridge *)netdev_priv(dev);
struct net_bridge_port *p; struct net_bridge_port *p;
struct nlattr *afspec;
bool changed = false; bool changed = false;
int err = 0; int err = 0;
...@@ -880,13 +887,12 @@ int br_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) ...@@ -880,13 +887,12 @@ int br_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags)
if (!p && !(dev->priv_flags & IFF_EBRIDGE)) if (!p && !(dev->priv_flags & IFF_EBRIDGE))
return -EINVAL; return -EINVAL;
err = br_afspec((struct net_bridge *)netdev_priv(dev), p, err = br_afspec(br, p, afspec, RTM_DELLINK, &changed);
afspec, RTM_DELLINK, &changed);
if (changed) if (changed)
/* Send RTM_NEWLINK because userspace /* Send RTM_NEWLINK because userspace
* expects RTM_NEWLINK for vlan dels * expects RTM_NEWLINK for vlan dels
*/ */
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, br, p);
return err; return err;
} }
......
...@@ -1071,7 +1071,8 @@ extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr) ...@@ -1071,7 +1071,8 @@ extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr)
extern struct rtnl_link_ops br_link_ops; extern struct rtnl_link_ops br_link_ops;
int br_netlink_init(void); int br_netlink_init(void);
void br_netlink_fini(void); void br_netlink_fini(void);
void br_ifinfo_notify(int event, struct net_bridge_port *port); void br_ifinfo_notify(int event, const struct net_bridge *br,
const struct net_bridge_port *port);
int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags); int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags);
int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags); int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags);
int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev,
......
...@@ -123,7 +123,7 @@ static void br_root_port_block(const struct net_bridge *br, ...@@ -123,7 +123,7 @@ static void br_root_port_block(const struct net_bridge *br,
(unsigned int) p->port_no, p->dev->name); (unsigned int) p->port_no, p->dev->name);
br_set_state(p, BR_STATE_LISTENING); br_set_state(p, BR_STATE_LISTENING);
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, NULL, p);
if (br->forward_delay > 0) if (br->forward_delay > 0)
mod_timer(&p->forward_delay_timer, jiffies + br->forward_delay); mod_timer(&p->forward_delay_timer, jiffies + br->forward_delay);
...@@ -403,7 +403,7 @@ static void br_make_blocking(struct net_bridge_port *p) ...@@ -403,7 +403,7 @@ static void br_make_blocking(struct net_bridge_port *p)
br_topology_change_detection(p->br); br_topology_change_detection(p->br);
br_set_state(p, BR_STATE_BLOCKING); br_set_state(p, BR_STATE_BLOCKING);
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, NULL, p);
del_timer(&p->forward_delay_timer); del_timer(&p->forward_delay_timer);
} }
...@@ -426,7 +426,7 @@ static void br_make_forwarding(struct net_bridge_port *p) ...@@ -426,7 +426,7 @@ static void br_make_forwarding(struct net_bridge_port *p)
else else
br_set_state(p, BR_STATE_LEARNING); br_set_state(p, BR_STATE_LEARNING);
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, NULL, p);
if (br->forward_delay != 0) if (br->forward_delay != 0)
mod_timer(&p->forward_delay_timer, jiffies + br->forward_delay); mod_timer(&p->forward_delay_timer, jiffies + br->forward_delay);
......
...@@ -96,7 +96,7 @@ void br_stp_enable_port(struct net_bridge_port *p) ...@@ -96,7 +96,7 @@ void br_stp_enable_port(struct net_bridge_port *p)
{ {
br_init_port(p); br_init_port(p);
br_port_state_selection(p->br); br_port_state_selection(p->br);
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, NULL, p);
} }
/* called under bridge lock */ /* called under bridge lock */
...@@ -111,7 +111,7 @@ void br_stp_disable_port(struct net_bridge_port *p) ...@@ -111,7 +111,7 @@ void br_stp_disable_port(struct net_bridge_port *p)
p->topology_change_ack = 0; p->topology_change_ack = 0;
p->config_pending = 0; p->config_pending = 0;
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, NULL, p);
del_timer(&p->message_age_timer); del_timer(&p->message_age_timer);
del_timer(&p->forward_delay_timer); del_timer(&p->forward_delay_timer);
......
...@@ -99,7 +99,7 @@ static void br_forward_delay_timer_expired(unsigned long arg) ...@@ -99,7 +99,7 @@ static void br_forward_delay_timer_expired(unsigned long arg)
netif_carrier_on(br->dev); netif_carrier_on(br->dev);
} }
rcu_read_lock(); rcu_read_lock();
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, NULL, p);
rcu_read_unlock(); rcu_read_unlock();
spin_unlock(&br->lock); spin_unlock(&br->lock);
} }
......
...@@ -280,7 +280,7 @@ static ssize_t brport_store(struct kobject *kobj, ...@@ -280,7 +280,7 @@ static ssize_t brport_store(struct kobject *kobj,
ret = brport_attr->store(p, val); ret = brport_attr->store(p, val);
spin_unlock_bh(&p->br->lock); spin_unlock_bh(&p->br->lock);
if (!ret) { if (!ret) {
br_ifinfo_notify(RTM_NEWLINK, p); br_ifinfo_notify(RTM_NEWLINK, NULL, p);
ret = count; ret = count;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment