From 945a36761fd7877660f630bbdeb4ff9ff80d1935 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Fri, 8 Aug 2014 16:44:32 +0200 Subject: rtnetlink: fix VF info size Commit 1d8faf48c74b8 ("net/core: Add VF link state control") added new attribute to IFLA_VF_INFO group in rtnl_fill_ifinfo but did not adjust size of the allocated memory in if_nlmsg_size/rtnl_vfinfo_size. As the result, we may trigger warnings in rtnl_getlink and similar functions when many VF links are enabled, as the information does not fit into the allocated skb. Fixes: 1d8faf48c74b8 ("net/core: Add VF link state control") Reported-by: Yulong Pei Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/core/rtnetlink.c') diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 8d39071f32d..f0493e3b747 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -804,7 +804,8 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev, (nla_total_size(sizeof(struct ifla_vf_mac)) + nla_total_size(sizeof(struct ifla_vf_vlan)) + nla_total_size(sizeof(struct ifla_vf_spoofchk)) + - nla_total_size(sizeof(struct ifla_vf_rate))); + nla_total_size(sizeof(struct ifla_vf_rate)) + + nla_total_size(sizeof(struct ifla_vf_link_state))); return size; } else return 0; -- cgit v1.2.3-70-g09d2 From 5d1180fcacc5ceb7da5494acfe9c5e4ebad4f281 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 1 Sep 2014 16:07:26 +0200 Subject: rtnl/do_setlink(): set modified when IFLA_TXQLEN is updated The only effect of this patch is to print a warning if IFLA_TXQLEN is updated and a following change fails. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net/core/rtnetlink.c') diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index f0493e3b747..5bbaf74bf45 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1611,8 +1611,14 @@ static int do_setlink(const struct sk_buff *skb, modified = 1; } - if (tb[IFLA_TXQLEN]) - dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); + if (tb[IFLA_TXQLEN]) { + unsigned long value = nla_get_u32(tb[IFLA_TXQLEN]); + + if (dev->tx_queue_len ^ value) + modified = 1; + + dev->tx_queue_len = value; + } if (tb[IFLA_OPERSTATE]) set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); -- cgit v1.2.3-70-g09d2 From 1889b0e7efe8373793069bd3deb7702a51e6f2a5 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 1 Sep 2014 16:07:27 +0200 Subject: rtnl/do_setlink(): set modified when IFLA_LINKMODE is updated The only effect of this patch is to print a warning if IFLA_LINKMODE is updated and a following change fails. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net/core/rtnetlink.c') diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 5bbaf74bf45..2bd9fb15b98 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1624,8 +1624,12 @@ static int do_setlink(const struct sk_buff *skb, set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); if (tb[IFLA_LINKMODE]) { + unsigned char value = nla_get_u8(tb[IFLA_LINKMODE]); + write_lock_bh(&dev_base_lock); - dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); + if (dev->link_mode ^ value) + modified = 1; + dev->link_mode = value; write_unlock_bh(&dev_base_lock); } -- cgit v1.2.3-70-g09d2 From 90c325e3bfe14ef360de6650fa2a2e92685e5cee Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 1 Sep 2014 16:07:28 +0200 Subject: rtnl/do_setlink(): last arg is now a set of flags There is no functional changes with this commit, it only prepares the next one. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'net/core/rtnetlink.c') diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2bd9fb15b98..7d84db3e059 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1481,9 +1481,10 @@ static int do_set_master(struct net_device *dev, int ifindex) return 0; } +#define DO_SETLINK_MODIFIED 0x01 static int do_setlink(const struct sk_buff *skb, struct net_device *dev, struct ifinfomsg *ifm, - struct nlattr **tb, char *ifname, int modified) + struct nlattr **tb, char *ifname, int status) { const struct net_device_ops *ops = dev->netdev_ops; int err; @@ -1502,7 +1503,7 @@ static int do_setlink(const struct sk_buff *skb, put_net(net); if (err) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } if (tb[IFLA_MAP]) { @@ -1531,7 +1532,7 @@ static int do_setlink(const struct sk_buff *skb, if (err < 0) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } if (tb[IFLA_ADDRESS]) { @@ -1551,19 +1552,19 @@ static int do_setlink(const struct sk_buff *skb, kfree(sa); if (err) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } if (tb[IFLA_MTU]) { err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU])); if (err < 0) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } if (tb[IFLA_GROUP]) { dev_set_group(dev, nla_get_u32(tb[IFLA_GROUP])); - modified = 1; + status |= DO_SETLINK_MODIFIED; } /* @@ -1575,7 +1576,7 @@ static int do_setlink(const struct sk_buff *skb, err = dev_change_name(dev, ifname); if (err < 0) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } if (tb[IFLA_IFALIAS]) { @@ -1583,7 +1584,7 @@ static int do_setlink(const struct sk_buff *skb, nla_len(tb[IFLA_IFALIAS])); if (err < 0) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } if (tb[IFLA_BROADCAST]) { @@ -1601,21 +1602,21 @@ static int do_setlink(const struct sk_buff *skb, err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER])); if (err) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } if (tb[IFLA_CARRIER]) { err = dev_change_carrier(dev, nla_get_u8(tb[IFLA_CARRIER])); if (err) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } if (tb[IFLA_TXQLEN]) { unsigned long value = nla_get_u32(tb[IFLA_TXQLEN]); if (dev->tx_queue_len ^ value) - modified = 1; + status |= DO_SETLINK_MODIFIED; dev->tx_queue_len = value; } @@ -1628,7 +1629,7 @@ static int do_setlink(const struct sk_buff *skb, write_lock_bh(&dev_base_lock); if (dev->link_mode ^ value) - modified = 1; + status |= DO_SETLINK_MODIFIED; dev->link_mode = value; write_unlock_bh(&dev_base_lock); } @@ -1644,7 +1645,7 @@ static int do_setlink(const struct sk_buff *skb, err = do_setvfinfo(dev, attr); if (err < 0) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } } err = 0; @@ -1674,7 +1675,7 @@ static int do_setlink(const struct sk_buff *skb, err = ops->ndo_set_vf_port(dev, vf, port); if (err < 0) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } } err = 0; @@ -1692,7 +1693,7 @@ static int do_setlink(const struct sk_buff *skb, err = ops->ndo_set_vf_port(dev, PORT_SELF_VF, port); if (err < 0) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } if (tb[IFLA_AF_SPEC]) { @@ -1709,13 +1710,13 @@ static int do_setlink(const struct sk_buff *skb, if (err < 0) goto errout; - modified = 1; + status |= DO_SETLINK_MODIFIED; } } err = 0; errout: - if (err < 0 && modified) + if (err < 0 && status & DO_SETLINK_MODIFIED) net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n", dev->name); @@ -1999,7 +2000,7 @@ replay: } if (dev) { - int modified = 0; + int status = 0; if (nlh->nlmsg_flags & NLM_F_EXCL) return -EEXIST; @@ -2014,7 +2015,7 @@ replay: err = ops->changelink(dev, tb, data); if (err < 0) return err; - modified = 1; + status |= DO_SETLINK_MODIFIED; } if (linkinfo[IFLA_INFO_SLAVE_DATA]) { @@ -2025,10 +2026,10 @@ replay: tb, slave_data); if (err < 0) return err; - modified = 1; + status |= DO_SETLINK_MODIFIED; } - return do_setlink(skb, dev, ifm, tb, ifname, modified); + return do_setlink(skb, dev, ifm, tb, ifname, status); } if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { -- cgit v1.2.3-70-g09d2 From ba9989069f4e426b1e0ed7018eacc9e1ba607095 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 1 Sep 2014 16:07:29 +0200 Subject: rtnl/do_setlink(): notify when a netdev is modified Depending on which parameters were updated, the changes were not propagated via the notifier chain and netlink. The new flag has been set only when the change did not cause a call to the notifier chain and/or to the netlink notification functions. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'net/core/rtnetlink.c') diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 7d84db3e059..a6882686ca3 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1482,6 +1482,8 @@ static int do_set_master(struct net_device *dev, int ifindex) } #define DO_SETLINK_MODIFIED 0x01 +/* notify flag means notify + modified. */ +#define DO_SETLINK_NOTIFY 0x03 static int do_setlink(const struct sk_buff *skb, struct net_device *dev, struct ifinfomsg *ifm, struct nlattr **tb, char *ifname, int status) @@ -1532,7 +1534,7 @@ static int do_setlink(const struct sk_buff *skb, if (err < 0) goto errout; - status |= DO_SETLINK_MODIFIED; + status |= DO_SETLINK_NOTIFY; } if (tb[IFLA_ADDRESS]) { @@ -1564,7 +1566,7 @@ static int do_setlink(const struct sk_buff *skb, if (tb[IFLA_GROUP]) { dev_set_group(dev, nla_get_u32(tb[IFLA_GROUP])); - status |= DO_SETLINK_MODIFIED; + status |= DO_SETLINK_NOTIFY; } /* @@ -1584,7 +1586,7 @@ static int do_setlink(const struct sk_buff *skb, nla_len(tb[IFLA_IFALIAS])); if (err < 0) goto errout; - status |= DO_SETLINK_MODIFIED; + status |= DO_SETLINK_NOTIFY; } if (tb[IFLA_BROADCAST]) { @@ -1616,7 +1618,7 @@ static int do_setlink(const struct sk_buff *skb, unsigned long value = nla_get_u32(tb[IFLA_TXQLEN]); if (dev->tx_queue_len ^ value) - status |= DO_SETLINK_MODIFIED; + status |= DO_SETLINK_NOTIFY; dev->tx_queue_len = value; } @@ -1629,7 +1631,7 @@ static int do_setlink(const struct sk_buff *skb, write_lock_bh(&dev_base_lock); if (dev->link_mode ^ value) - status |= DO_SETLINK_MODIFIED; + status |= DO_SETLINK_NOTIFY; dev->link_mode = value; write_unlock_bh(&dev_base_lock); } @@ -1645,7 +1647,7 @@ static int do_setlink(const struct sk_buff *skb, err = do_setvfinfo(dev, attr); if (err < 0) goto errout; - status |= DO_SETLINK_MODIFIED; + status |= DO_SETLINK_NOTIFY; } } err = 0; @@ -1675,7 +1677,7 @@ static int do_setlink(const struct sk_buff *skb, err = ops->ndo_set_vf_port(dev, vf, port); if (err < 0) goto errout; - status |= DO_SETLINK_MODIFIED; + status |= DO_SETLINK_NOTIFY; } } err = 0; @@ -1693,7 +1695,7 @@ static int do_setlink(const struct sk_buff *skb, err = ops->ndo_set_vf_port(dev, PORT_SELF_VF, port); if (err < 0) goto errout; - status |= DO_SETLINK_MODIFIED; + status |= DO_SETLINK_NOTIFY; } if (tb[IFLA_AF_SPEC]) { @@ -1710,15 +1712,20 @@ static int do_setlink(const struct sk_buff *skb, if (err < 0) goto errout; - status |= DO_SETLINK_MODIFIED; + status |= DO_SETLINK_NOTIFY; } } err = 0; errout: - if (err < 0 && status & DO_SETLINK_MODIFIED) - net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n", - dev->name); + if (status & DO_SETLINK_MODIFIED) { + if (status & DO_SETLINK_NOTIFY) + netdev_state_change(dev); + + if (err < 0) + net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n", + dev->name); + } return err; } @@ -2015,7 +2022,7 @@ replay: err = ops->changelink(dev, tb, data); if (err < 0) return err; - status |= DO_SETLINK_MODIFIED; + status |= DO_SETLINK_NOTIFY; } if (linkinfo[IFLA_INFO_SLAVE_DATA]) { @@ -2026,7 +2033,7 @@ replay: tb, slave_data); if (err < 0) return err; - status |= DO_SETLINK_MODIFIED; + status |= DO_SETLINK_NOTIFY; } return do_setlink(skb, dev, ifm, tb, ifname, status); -- cgit v1.2.3-70-g09d2