ethtool: add FEATURES_NTF notification

Send ETHTOOL_MSG_FEATURES_NTF notification whenever network device features
are modified using ETHTOOL_MSG_FEATURES_SET netlink message, ethtool ioctl
request or any other way resulting in call to netdev_update_features() or
netdev_change_features()

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: hongrongxuan <hongrongxuan@huawei.com>
This commit is contained in:
Michal Kubecek 2020-03-12 21:08:03 +01:00 committed by Jianping Liu
parent 590baedcf7
commit 62e057b6df
4 changed files with 39 additions and 1 deletions

View File

@ -208,6 +208,7 @@ Kernel to userspace:
``ETHTOOL_MSG_WOL_NTF`` wake-on-lan settings notification ``ETHTOOL_MSG_WOL_NTF`` wake-on-lan settings notification
``ETHTOOL_MSG_FEATURES_GET_REPLY`` device features ``ETHTOOL_MSG_FEATURES_GET_REPLY`` device features
``ETHTOOL_MSG_FEATURES_SET_REPLY`` optional reply to FEATURES_SET ``ETHTOOL_MSG_FEATURES_SET_REPLY`` optional reply to FEATURES_SET
``ETHTOOL_MSG_FEATURES_NTF`` netdev features notification
===================================== ================================= ===================================== =================================
``GET`` requests are sent by userspace applications to retrieve device ``GET`` requests are sent by userspace applications to retrieve device
@ -591,6 +592,11 @@ reports the difference between old and new dev->features: mask consists of
bits which have changed, values are their values in new dev->features (after bits which have changed, values are their values in new dev->features (after
the operation). the operation).
``ETHTOOL_MSG_FEATURES_NTF`` notification is sent not only if device features
are modified using ``ETHTOOL_MSG_FEATURES_SET`` request or on of ethtool ioctl
request but also each time features are modified with netdev_update_features()
or netdev_change_features().
Request translation Request translation
=================== ===================

View File

@ -47,6 +47,7 @@ enum {
ETHTOOL_MSG_WOL_NTF, ETHTOOL_MSG_WOL_NTF,
ETHTOOL_MSG_FEATURES_GET_REPLY, ETHTOOL_MSG_FEATURES_GET_REPLY,
ETHTOOL_MSG_FEATURES_SET_REPLY, ETHTOOL_MSG_FEATURES_SET_REPLY,
ETHTOOL_MSG_FEATURES_NTF,
/* add new constants above here */ /* add new constants above here */
__ETHTOOL_MSG_KERNEL_CNT, __ETHTOOL_MSG_KERNEL_CNT,

View File

@ -230,6 +230,7 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
struct nlattr *tb[ETHTOOL_A_FEATURES_MAX + 1]; struct nlattr *tb[ETHTOOL_A_FEATURES_MAX + 1];
struct ethnl_req_info req_info = {}; struct ethnl_req_info req_info = {};
struct net_device *dev; struct net_device *dev;
bool mod;
int ret; int ret;
ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
@ -272,6 +273,7 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
dev->wanted_features = ethnl_bitmap_to_features(req_wanted); dev->wanted_features = ethnl_bitmap_to_features(req_wanted);
__netdev_update_features(dev); __netdev_update_features(dev);
ethnl_features_to_bitmap(new_active, dev->features); ethnl_features_to_bitmap(new_active, dev->features);
mod = !bitmap_equal(old_active, new_active, NETDEV_FEATURE_COUNT);
ret = 0; ret = 0;
if (!(req_info.flags & ETHTOOL_FLAG_OMIT_REPLY)) { if (!(req_info.flags & ETHTOOL_FLAG_OMIT_REPLY)) {
@ -292,6 +294,8 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
wanted_diff_mask, new_active, wanted_diff_mask, new_active,
active_diff_mask, compact); active_diff_mask, compact);
} }
if (mod)
ethtool_notify(dev, ETHTOOL_MSG_FEATURES_NTF, NULL);
out_rtnl: out_rtnl:
rtnl_unlock(); rtnl_unlock();

View File

@ -530,6 +530,7 @@ ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = {
[ETHTOOL_MSG_LINKMODES_NTF] = &ethnl_linkmodes_request_ops, [ETHTOOL_MSG_LINKMODES_NTF] = &ethnl_linkmodes_request_ops,
[ETHTOOL_MSG_DEBUG_NTF] = &ethnl_debug_request_ops, [ETHTOOL_MSG_DEBUG_NTF] = &ethnl_debug_request_ops,
[ETHTOOL_MSG_WOL_NTF] = &ethnl_wol_request_ops, [ETHTOOL_MSG_WOL_NTF] = &ethnl_wol_request_ops,
[ETHTOOL_MSG_FEATURES_NTF] = &ethnl_features_request_ops,
}; };
/* default notification handler */ /* default notification handler */
@ -615,6 +616,7 @@ static const ethnl_notify_handler_t ethnl_notify_handlers[] = {
[ETHTOOL_MSG_LINKMODES_NTF] = ethnl_default_notify, [ETHTOOL_MSG_LINKMODES_NTF] = ethnl_default_notify,
[ETHTOOL_MSG_DEBUG_NTF] = ethnl_default_notify, [ETHTOOL_MSG_DEBUG_NTF] = ethnl_default_notify,
[ETHTOOL_MSG_WOL_NTF] = ethnl_default_notify, [ETHTOOL_MSG_WOL_NTF] = ethnl_default_notify,
[ETHTOOL_MSG_FEATURES_NTF] = ethnl_default_notify,
}; };
void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data) void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data)
@ -632,6 +634,29 @@ void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data)
} }
EXPORT_SYMBOL(ethtool_notify); EXPORT_SYMBOL(ethtool_notify);
static void ethnl_notify_features(struct netdev_notifier_info *info)
{
struct net_device *dev = netdev_notifier_info_to_dev(info);
ethtool_notify(dev, ETHTOOL_MSG_FEATURES_NTF, NULL);
}
static int ethnl_netdev_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
switch (event) {
case NETDEV_FEAT_CHANGE:
ethnl_notify_features(ptr);
break;
}
return NOTIFY_DONE;
}
static struct notifier_block ethnl_netdev_notifier = {
.notifier_call = ethnl_netdev_event,
};
/* genetlink setup */ /* genetlink setup */
static const struct genl_ops ethtool_genl_ops[] = { static const struct genl_ops ethtool_genl_ops[] = {
@ -738,7 +763,9 @@ static int __init ethnl_init(void)
return ret; return ret;
ethnl_ok = true; ethnl_ok = true;
return 0; ret = register_netdevice_notifier(&ethnl_netdev_notifier);
WARN(ret < 0, "ethtool: net device notifier registration failed");
return ret;
} }
subsys_initcall(ethnl_init); subsys_initcall(ethnl_init);