aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoopa Prabhu <roopa@cumulusnetworks.com>2015-01-14 23:02:25 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-17 23:49:51 -0500
commit02dba4388d1691a087f40fe8acd2e1ffd577a07f (patch)
treee006a1ff98e4fecb91f9e21d90a777952b4238b3
parent1e7d06ba5f2683f7a9df4fc74dbc7046a9be4c26 (diff)
bridge: fix setlink/dellink notifications
problems with bridge getlink/setlink notifications today: - bridge setlink generates two notifications to userspace - one from the bridge driver - one from rtnetlink.c (rtnl_bridge_notify) - dellink generates one notification from rtnetlink.c. Which means bridge setlink and dellink notifications are not consistent - Looking at the code it appears, If both BRIDGE_FLAGS_MASTER and BRIDGE_FLAGS_SELF were set, the size calculation in rtnl_bridge_notify can be wrong. Example: if you set both BRIDGE_FLAGS_MASTER and BRIDGE_FLAGS_SELF in a setlink request to rocker dev, rtnl_bridge_notify will allocate skb for one set of bridge attributes, but, both the bridge driver and rocker dev will try to add attributes resulting in twice the number of attributes being added to the skb. (rocker dev calls ndo_dflt_bridge_getlink) There are multiple options: 1) Generate one notification including all attributes from master and self: But, I don't think it will work, because both master and self may use the same attributes/policy. Cannot pack the same set of attributes in a single notification from both master and slave (duplicate attributes). 2) Generate one notification from master and the other notification from self (This seems to be ideal): For master: the master driver will send notification (bridge in this example) For self: the self driver will send notification (rocker in the above example. It can use helpers from rtnetlink.c to do so. Like the ndo_dflt_bridge_getlink api). This patch implements 2) (leaving the 'rtnl_bridge_notify' around to be used with 'self'). v1->v2 : - rtnl_bridge_notify is now called only for self, so, remove 'BRIDGE_FLAGS_SELF' check and cleanup a few things - rtnl_bridge_dellink used to always send a RTM_NEWLINK msg earlier. So, I have changed the notification from br_dellink to go as RTM_NEWLINK Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/bridge/br_netlink.c5
-rw-r--r--net/core/rtnetlink.c45
2 files changed, 26 insertions, 24 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 66ece91ee165..163950b10d8c 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -569,6 +569,11 @@ int br_dellink(struct net_device *dev, struct nlmsghdr *nlh)
569 569
570 err = br_afspec((struct net_bridge *)netdev_priv(dev), p, 570 err = br_afspec((struct net_bridge *)netdev_priv(dev), p,
571 afspec, RTM_DELLINK); 571 afspec, RTM_DELLINK);
572 if (err == 0)
573 /* Send RTM_NEWLINK because userspace
574 * expects RTM_NEWLINK for vlan dels
575 */
576 br_ifinfo_notify(RTM_NEWLINK, p);
572 577
573 return err; 578 return err;
574} 579}
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 6a6cdade1676..eadc5c0e2dfa 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2880,32 +2880,24 @@ static inline size_t bridge_nlmsg_size(void)
2880 + nla_total_size(sizeof(u16)); /* IFLA_BRIDGE_MODE */ 2880 + nla_total_size(sizeof(u16)); /* IFLA_BRIDGE_MODE */
2881} 2881}
2882 2882
2883static int rtnl_bridge_notify(struct net_device *dev, u16 flags) 2883static int rtnl_bridge_notify(struct net_device *dev)
2884{ 2884{
2885 struct net *net = dev_net(dev); 2885 struct net *net = dev_net(dev);
2886 struct net_device *br_dev = netdev_master_upper_dev_get(dev);
2887 struct sk_buff *skb; 2886 struct sk_buff *skb;
2888 int err = -EOPNOTSUPP; 2887 int err = -EOPNOTSUPP;
2889 2888
2889 if (!dev->netdev_ops->ndo_bridge_getlink)
2890 return 0;
2891
2890 skb = nlmsg_new(bridge_nlmsg_size(), GFP_ATOMIC); 2892 skb = nlmsg_new(bridge_nlmsg_size(), GFP_ATOMIC);
2891 if (!skb) { 2893 if (!skb) {
2892 err = -ENOMEM; 2894 err = -ENOMEM;
2893 goto errout; 2895 goto errout;
2894 } 2896 }
2895 2897
2896 if ((!flags || (flags & BRIDGE_FLAGS_MASTER)) && 2898 err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0);
2897 br_dev && br_dev->netdev_ops->ndo_bridge_getlink) { 2899 if (err < 0)
2898 err = br_dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0); 2900 goto errout;
2899 if (err < 0)
2900 goto errout;
2901 }
2902
2903 if ((flags & BRIDGE_FLAGS_SELF) &&
2904 dev->netdev_ops->ndo_bridge_getlink) {
2905 err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0);
2906 if (err < 0)
2907 goto errout;
2908 }
2909 2901
2910 rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); 2902 rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
2911 return 0; 2903 return 0;
@@ -2975,16 +2967,18 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh)
2975 err = -EOPNOTSUPP; 2967 err = -EOPNOTSUPP;
2976 else 2968 else
2977 err = dev->netdev_ops->ndo_bridge_setlink(dev, nlh); 2969 err = dev->netdev_ops->ndo_bridge_setlink(dev, nlh);
2978 2970 if (!err) {
2979 if (!err)
2980 flags &= ~BRIDGE_FLAGS_SELF; 2971 flags &= ~BRIDGE_FLAGS_SELF;
2972
2973 /* Generate event to notify upper layer of bridge
2974 * change
2975 */
2976 err = rtnl_bridge_notify(dev);
2977 }
2981 } 2978 }
2982 2979
2983 if (have_flags) 2980 if (have_flags)
2984 memcpy(nla_data(attr), &flags, sizeof(flags)); 2981 memcpy(nla_data(attr), &flags, sizeof(flags));
2985 /* Generate event to notify upper layer of bridge change */
2986 if (!err)
2987 err = rtnl_bridge_notify(dev, oflags);
2988out: 2982out:
2989 return err; 2983 return err;
2990} 2984}
@@ -3049,15 +3043,18 @@ static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh)
3049 else 3043 else
3050 err = dev->netdev_ops->ndo_bridge_dellink(dev, nlh); 3044 err = dev->netdev_ops->ndo_bridge_dellink(dev, nlh);
3051 3045
3052 if (!err) 3046 if (!err) {
3053 flags &= ~BRIDGE_FLAGS_SELF; 3047 flags &= ~BRIDGE_FLAGS_SELF;
3048
3049 /* Generate event to notify upper layer of bridge
3050 * change
3051 */
3052 err = rtnl_bridge_notify(dev);
3053 }
3054 } 3054 }
3055 3055
3056 if (have_flags) 3056 if (have_flags)
3057 memcpy(nla_data(attr), &flags, sizeof(flags)); 3057 memcpy(nla_data(attr), &flags, sizeof(flags));
3058 /* Generate event to notify upper layer of bridge change */
3059 if (!err)
3060 err = rtnl_bridge_notify(dev, oflags);
3061out: 3058out:
3062 return err; 3059 return err;
3063} 3060}