From 5d1180fcacc5ceb7da5494acfe9c5e4ebad4f281 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 1 Sep 2014 16:07:26 +0200 Subject: [PATCH 1/4] 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(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index f0493e3b7471..5bbaf74bf457 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])); From 1889b0e7efe8373793069bd3deb7702a51e6f2a5 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 1 Sep 2014 16:07:27 +0200 Subject: [PATCH 2/4] 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(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 5bbaf74bf457..2bd9fb15b987 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); } From 90c325e3bfe14ef360de6650fa2a2e92685e5cee Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 1 Sep 2014 16:07:28 +0200 Subject: [PATCH 3/4] 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(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2bd9fb15b987..7d84db3e0597 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)) { From ba9989069f4e426b1e0ed7018eacc9e1ba607095 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 1 Sep 2014 16:07:29 +0200 Subject: [PATCH 4/4] 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(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 7d84db3e0597..a6882686ca3a 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);