Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Nikolay Aleksandrov and committed by
David S. Miller
92899063 ad88d35a

+45 -38
+1 -1
net/bridge/br.c
··· 112 112 /* Events that may cause spanning tree to refresh */ 113 113 if (event == NETDEV_CHANGEADDR || event == NETDEV_UP || 114 114 event == NETDEV_CHANGE || event == NETDEV_DOWN) 115 - br_ifinfo_notify(RTM_NEWLINK, p); 115 + br_ifinfo_notify(RTM_NEWLINK, NULL, p); 116 116 117 117 return NOTIFY_DONE; 118 118 }
+2 -2
net/bridge/br_if.c
··· 271 271 br_stp_disable_port(p); 272 272 spin_unlock_bh(&br->lock); 273 273 274 - br_ifinfo_notify(RTM_DELLINK, p); 274 + br_ifinfo_notify(RTM_DELLINK, NULL, p); 275 275 276 276 list_del_rcu(&p->list); 277 277 if (netdev_get_fwd_headroom(dev) == br->dev->needed_headroom) ··· 589 589 br_stp_enable_port(p); 590 590 spin_unlock_bh(&br->lock); 591 591 592 - br_ifinfo_notify(RTM_NEWLINK, p); 592 + br_ifinfo_notify(RTM_NEWLINK, NULL, p); 593 593 594 594 if (changed_addr) 595 595 call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
+1 -1
net/bridge/br_ioctl.c
··· 293 293 294 294 if (!ret) { 295 295 if (p) 296 - br_ifinfo_notify(RTM_NEWLINK, p); 296 + br_ifinfo_notify(RTM_NEWLINK, NULL, p); 297 297 else 298 298 netdev_state_change(br->dev); 299 299 }
+32 -26
net/bridge/br_netlink.c
··· 361 361 * Contains port and master info as well as carrier and bridge state. 362 362 */ 363 363 static int br_fill_ifinfo(struct sk_buff *skb, 364 - struct net_bridge_port *port, 364 + const struct net_bridge_port *port, 365 365 u32 pid, u32 seq, int event, unsigned int flags, 366 366 u32 filter_mask, const struct net_device *dev) 367 367 { 368 + u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; 368 369 struct net_bridge *br; 369 370 struct ifinfomsg *hdr; 370 371 struct nlmsghdr *nlh; 371 - u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; 372 372 373 373 if (port) 374 374 br = port->br; ··· 454 454 return -EMSGSIZE; 455 455 } 456 456 457 - /* 458 - * Notify listeners of a change in port information 459 - */ 460 - void br_ifinfo_notify(int event, struct net_bridge_port *port) 457 + /* Notify listeners of a change in bridge or port information */ 458 + void br_ifinfo_notify(int event, const struct net_bridge *br, 459 + const struct net_bridge_port *port) 461 460 { 462 - struct net *net; 461 + u32 filter = RTEXT_FILTER_BRVLAN_COMPRESSED; 462 + struct net_device *dev; 463 463 struct sk_buff *skb; 464 464 int err = -ENOBUFS; 465 - u32 filter = RTEXT_FILTER_BRVLAN_COMPRESSED; 465 + struct net *net; 466 + u16 port_no = 0; 466 467 467 - if (!port) 468 + if (WARN_ON(!port && !br)) 468 469 return; 469 470 470 - net = dev_net(port->dev); 471 - br_debug(port->br, "port %u(%s) event %d\n", 472 - (unsigned int)port->port_no, port->dev->name, event); 471 + if (port) { 472 + dev = port->dev; 473 + br = port->br; 474 + port_no = port->port_no; 475 + } else { 476 + dev = br->dev; 477 + } 473 478 474 - skb = nlmsg_new(br_nlmsg_size(port->dev, filter), GFP_ATOMIC); 479 + net = dev_net(dev); 480 + br_debug(br, "port %u(%s) event %d\n", port_no, dev->name, event); 481 + 482 + skb = nlmsg_new(br_nlmsg_size(dev, filter), GFP_ATOMIC); 475 483 if (skb == NULL) 476 484 goto errout; 477 485 478 - err = br_fill_ifinfo(skb, port, 0, 0, event, 0, filter, port->dev); 486 + err = br_fill_ifinfo(skb, port, 0, 0, event, 0, filter, dev); 479 487 if (err < 0) { 480 488 /* -EMSGSIZE implies BUG in br_nlmsg_size() */ 481 489 WARN_ON(err == -EMSGSIZE); ··· 495 487 errout: 496 488 rtnl_set_sk_err(net, RTNLGRP_LINK, err); 497 489 } 498 - 499 490 500 491 /* 501 492 * Dump information about all ports, in response to GETLINK ··· 816 809 /* Change state and parameters on port. */ 817 810 int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) 818 811 { 812 + struct net_bridge *br = (struct net_bridge *)netdev_priv(dev); 813 + struct nlattr *tb[IFLA_BRPORT_MAX + 1]; 814 + struct net_bridge_port *p; 819 815 struct nlattr *protinfo; 820 816 struct nlattr *afspec; 821 - struct net_bridge_port *p; 822 - struct nlattr *tb[IFLA_BRPORT_MAX + 1]; 823 817 bool changed = false; 824 818 int err = 0; 825 819 ··· 860 852 changed = true; 861 853 } 862 854 863 - if (afspec) { 864 - err = br_afspec((struct net_bridge *)netdev_priv(dev), p, 865 - afspec, RTM_SETLINK, &changed); 866 - } 855 + if (afspec) 856 + err = br_afspec(br, p, afspec, RTM_SETLINK, &changed); 867 857 868 858 if (changed) 869 - br_ifinfo_notify(RTM_NEWLINK, p); 859 + br_ifinfo_notify(RTM_NEWLINK, br, p); 870 860 out: 871 861 return err; 872 862 } ··· 872 866 /* Delete port information */ 873 867 int br_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) 874 868 { 875 - struct nlattr *afspec; 869 + struct net_bridge *br = (struct net_bridge *)netdev_priv(dev); 876 870 struct net_bridge_port *p; 871 + struct nlattr *afspec; 877 872 bool changed = false; 878 873 int err = 0; 879 874 ··· 887 880 if (!p && !(dev->priv_flags & IFF_EBRIDGE)) 888 881 return -EINVAL; 889 882 890 - err = br_afspec((struct net_bridge *)netdev_priv(dev), p, 891 - afspec, RTM_DELLINK, &changed); 883 + err = br_afspec(br, p, afspec, RTM_DELLINK, &changed); 892 884 if (changed) 893 885 /* Send RTM_NEWLINK because userspace 894 886 * expects RTM_NEWLINK for vlan dels 895 887 */ 896 - br_ifinfo_notify(RTM_NEWLINK, p); 888 + br_ifinfo_notify(RTM_NEWLINK, br, p); 897 889 898 890 return err; 899 891 }
+2 -1
net/bridge/br_private.h
··· 1071 1071 extern struct rtnl_link_ops br_link_ops; 1072 1072 int br_netlink_init(void); 1073 1073 void br_netlink_fini(void); 1074 - void br_ifinfo_notify(int event, struct net_bridge_port *port); 1074 + void br_ifinfo_notify(int event, const struct net_bridge *br, 1075 + const struct net_bridge_port *port); 1075 1076 int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags); 1076 1077 int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags); 1077 1078 int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev,
+3 -3
net/bridge/br_stp.c
··· 123 123 (unsigned int) p->port_no, p->dev->name); 124 124 125 125 br_set_state(p, BR_STATE_LISTENING); 126 - br_ifinfo_notify(RTM_NEWLINK, p); 126 + br_ifinfo_notify(RTM_NEWLINK, NULL, p); 127 127 128 128 if (br->forward_delay > 0) 129 129 mod_timer(&p->forward_delay_timer, jiffies + br->forward_delay); ··· 403 403 br_topology_change_detection(p->br); 404 404 405 405 br_set_state(p, BR_STATE_BLOCKING); 406 - br_ifinfo_notify(RTM_NEWLINK, p); 406 + br_ifinfo_notify(RTM_NEWLINK, NULL, p); 407 407 408 408 del_timer(&p->forward_delay_timer); 409 409 } ··· 426 426 else 427 427 br_set_state(p, BR_STATE_LEARNING); 428 428 429 - br_ifinfo_notify(RTM_NEWLINK, p); 429 + br_ifinfo_notify(RTM_NEWLINK, NULL, p); 430 430 431 431 if (br->forward_delay != 0) 432 432 mod_timer(&p->forward_delay_timer, jiffies + br->forward_delay);
+2 -2
net/bridge/br_stp_if.c
··· 96 96 { 97 97 br_init_port(p); 98 98 br_port_state_selection(p->br); 99 - br_ifinfo_notify(RTM_NEWLINK, p); 99 + br_ifinfo_notify(RTM_NEWLINK, NULL, p); 100 100 } 101 101 102 102 /* called under bridge lock */ ··· 111 111 p->topology_change_ack = 0; 112 112 p->config_pending = 0; 113 113 114 - br_ifinfo_notify(RTM_NEWLINK, p); 114 + br_ifinfo_notify(RTM_NEWLINK, NULL, p); 115 115 116 116 del_timer(&p->message_age_timer); 117 117 del_timer(&p->forward_delay_timer);
+1 -1
net/bridge/br_stp_timer.c
··· 99 99 netif_carrier_on(br->dev); 100 100 } 101 101 rcu_read_lock(); 102 - br_ifinfo_notify(RTM_NEWLINK, p); 102 + br_ifinfo_notify(RTM_NEWLINK, NULL, p); 103 103 rcu_read_unlock(); 104 104 spin_unlock(&br->lock); 105 105 }
+1 -1
net/bridge/br_sysfs_if.c
··· 280 280 ret = brport_attr->store(p, val); 281 281 spin_unlock_bh(&p->br->lock); 282 282 if (!ret) { 283 - br_ifinfo_notify(RTM_NEWLINK, p); 283 + br_ifinfo_notify(RTM_NEWLINK, NULL, p); 284 284 ret = count; 285 285 } 286 286 }