linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Michal Kubecek <mkubecek@suse.cz>
To: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Jiri Pirko <jiri@resnulli.us>,
	David Miller <davem@davemloft.net>,
	Florian Fainelli <f.fainelli@gmail.com>,
	Roopa Prabhu <roopa@cumulusnetworks.com>,
	Jakub Kicinski <kubakici@wp.pl>,
	"John W. Linville" <linville@tuxdriver.com>
Subject: [RFC PATCH net-next v2 06/17] ethtool: support for netlink notifications
Date: Mon, 30 Jul 2018 14:53:12 +0200 (CEST)	[thread overview]
Message-ID: <e0e0433fd250dc331caa23aa739d7841e9602e0f.1532953989.git.mkubecek@suse.cz> (raw)
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Add infrastructure for ethtool netlink notifications. There is only one
multicast group, "monitor" which userspace can use to get notifications.
Notifications are supposed to be broadcasted on every configuration change,
whether it is done using the netlink interface or legacy ioctl one.

To trigger a notification, netlink code calls ethtool_notify(), external
code (ioctl interface) uses NETDEV_ETHTOOL event, preferrably by the means
of netdev_ethtool_info_change() helper. For both, the caller must hold
RTNL (and, obviously, allow sleeping).

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 include/linux/ethtool_netlink.h      |  5 ++
 include/linux/netdevice.h            | 23 ++++++++
 include/uapi/linux/ethtool_netlink.h |  2 +
 net/core/dev.c                       | 24 +++++++-
 net/ethtool/netlink.c                | 82 +++++++++++++++++++++++++++-
 net/ethtool/netlink.h                |  5 ++
 6 files changed, 139 insertions(+), 2 deletions(-)

diff --git a/include/linux/ethtool_netlink.h b/include/linux/ethtool_netlink.h
index 0412adb4f42f..2a15e64a16f3 100644
--- a/include/linux/ethtool_netlink.h
+++ b/include/linux/ethtool_netlink.h
@@ -5,5 +5,10 @@
 
 #include <uapi/linux/ethtool_netlink.h>
 #include <linux/ethtool.h>
+#include <linux/netdevice.h>
+
+enum ethtool_multicast_groups {
+	ETHNL_MCGRP_MONITOR,
+};
 
 #endif /* _LINUX_ETHTOOL_NETLINK_H_ */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c1295c7a452e..c4b0c575d57e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2444,6 +2444,7 @@ enum netdev_cmd {
 	NETDEV_CVLAN_FILTER_DROP_INFO,
 	NETDEV_SVLAN_FILTER_PUSH_INFO,
 	NETDEV_SVLAN_FILTER_DROP_INFO,
+	NETDEV_ETHTOOL,
 };
 const char *netdev_cmd_to_name(enum netdev_cmd cmd);
 
@@ -4221,6 +4222,28 @@ struct netdev_notifier_bonding_info {
 void netdev_bonding_info_change(struct net_device *dev,
 				struct netdev_bonding_info *bonding_info);
 
+struct netdev_ethtool_info {
+	unsigned int cmd;
+	u32 req_mask;
+};
+
+struct netdev_notifier_ethtool_info {
+	struct netdev_notifier_info info; /* must be first */
+	struct netdev_ethtool_info ethtool_info;
+};
+
+#if IS_ENABLED(CONFIG_ETHTOOL_NETLINK)
+int netdev_ethtool_info_change(struct net_device *dev,
+			       struct netlink_ext_ack *extack,
+			       unsigned int cmd, u32 req_mask);
+#else
+static inline void netdev_ethtool_info_change(struct net_device *dev,
+					      struct netlink_ext_ack *extack,
+					      unsigned int cmd, u32 req_mask)
+{
+}
+#endif
+
 static inline
 struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features)
 {
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 98d6fae315f3..444a668e4a08 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -58,4 +58,6 @@ enum {
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
 
+#define ETHTOOL_MCGRP_MONITOR_NAME "monitor"
+
 #endif /* _UAPI_LINUX_ETHTOOL_NETLINK_H_ */
diff --git a/net/core/dev.c b/net/core/dev.c
index 87c42c8249ae..8a0773a52dd7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1585,7 +1585,7 @@ const char *netdev_cmd_to_name(enum netdev_cmd cmd)
 	N(PRECHANGEUPPER) N(CHANGELOWERSTATE) N(UDP_TUNNEL_PUSH_INFO)
 	N(UDP_TUNNEL_DROP_INFO) N(CHANGE_TX_QUEUE_LEN)
 	N(CVLAN_FILTER_PUSH_INFO) N(CVLAN_FILTER_DROP_INFO)
-	N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO)
+	N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO) N(ETHTOOL)
 	}
 #undef N
 	return "UNKNOWN_NETDEV_EVENT";
@@ -7058,6 +7058,28 @@ void netdev_bonding_info_change(struct net_device *dev,
 }
 EXPORT_SYMBOL(netdev_bonding_info_change);
 
+#if IS_ENABLED(CONFIG_ETHTOOL_NETLINK)
+int netdev_ethtool_info_change(struct net_device *dev,
+			       struct netlink_ext_ack *extack,
+			       unsigned int cmd, u32 req_mask)
+{
+	struct netdev_notifier_ethtool_info ethtool_info = {
+		.info = {
+			.dev = dev,
+			.extack = extack,
+		},
+		.ethtool_info = {
+			.cmd = cmd,
+			.req_mask = req_mask,
+		},
+	};
+
+	return call_netdevice_notifiers_info(NETDEV_ETHTOOL,
+					     &ethtool_info.info);
+}
+EXPORT_SYMBOL(netdev_ethtool_info_change);
+#endif
+
 static void netdev_adjacent_add_links(struct net_device *dev)
 {
 	struct netdev_adjacent *iter;
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index df065fd3dc80..e4a20bb6c1d4 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -6,6 +6,8 @@
 #include <linux/ethtool_netlink.h>
 #include "netlink.h"
 
+u32 ethnl_bcast_seq;
+
 static const struct nla_policy dev_policy[ETHA_DEV_MAX + 1] = {
 	[ETHA_DEV_UNSPEC]	= { .type = NLA_UNSPEC },
 	[ETHA_DEV_INDEX]	= { .type = NLA_U32 },
@@ -19,6 +21,11 @@ struct net_device *ethnl_dev_get(struct genl_info *info, struct nlattr *nest)
 	struct net_device *dev;
 	int ret;
 
+	if (!nest) {
+		ETHNL_SET_ERRMSG(info,
+				 "mandatory device identification missing");
+		return ERR_PTR(-EINVAL);
+	}
 	ret = nla_parse_nested(tb, ETHA_DEV_MAX, nest, dev_policy,
 			       info->extack);
 	if (ret < 0)
@@ -562,11 +569,69 @@ int ethnl_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
 	return ret;
 }
 
+/* notifications */
+
+typedef void (*ethnl_notify_handler_t)(struct netdev_notifier_ethtool_info *);
+
+ethnl_notify_handler_t ethnl_notify_handlers[] = {
+};
+
+static void __ethnl_notify(struct netdev_notifier_ethtool_info *info)
+{
+	unsigned int cmd = info->ethtool_info.cmd;
+
+	ASSERT_RTNL();
+	if (likely(cmd < ARRAY_SIZE(ethnl_notify_handlers) &&
+		   ethnl_notify_handlers[cmd]))
+		ethnl_notify_handlers[cmd](info);
+	else
+		WARN_ONCE(1, "notification %u not implemented (dev=%s, req_mask=0x%x\n",
+			  cmd, netdev_name(info->info.dev),
+			  info->ethtool_info.req_mask);
+}
+
+void ethnl_notify(struct net_device *dev, struct netlink_ext_ack *extack,
+		  unsigned int cmd, u32 req_mask)
+{
+	struct netdev_notifier_ethtool_info ethtool_info = {
+		.info = {
+			.dev = dev,
+			.extack = extack,
+		},
+		.ethtool_info = {
+			.cmd = cmd,
+			.req_mask = req_mask,
+		},
+	};
+
+	return __ethnl_notify(&ethtool_info);
+}
+
+static int ethnl_netdev_event(struct notifier_block *this, unsigned long event,
+			      void *ptr)
+{
+	switch(event) {
+	case NETDEV_ETHTOOL:
+		__ethnl_notify(ptr);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ethnl_netdev_notifier = {
+	.notifier_call = ethnl_netdev_event,
+};
+
 /* genetlink setup */
 
 static const struct genl_ops ethtool_genl_ops[] = {
 };
 
+static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
+	[ETHNL_MCGRP_MONITOR] = { .name = ETHTOOL_MCGRP_MONITOR_NAME },
+};
+
 struct genl_family ethtool_genl_family = {
 	.hdrsize	= 0,
 	.name		= ETHTOOL_GENL_NAME,
@@ -575,17 +640,32 @@ struct genl_family ethtool_genl_family = {
 	.parallel_ops	= true,
 	.ops		= ethtool_genl_ops,
 	.n_ops		= ARRAY_SIZE(ethtool_genl_ops),
+	.mcgrps		= ethtool_nl_mcgrps,
+	.n_mcgrps	= ARRAY_SIZE(ethtool_nl_mcgrps),
 };
 
 /* module setup */
 
 static int __init ethtool_nl_init(void)
 {
-	return genl_register_family(&ethtool_genl_family);
+	int ret;
+
+	ret = genl_register_family(&ethtool_genl_family);
+	if (ret < 0)
+		return ret;
+	ret = register_netdevice_notifier(&ethnl_netdev_notifier);
+	if (ret < 0)
+		goto err_unregister;
+	return 0;
+
+err_unregister:
+	genl_unregister_family(&ethtool_genl_family);
+	return ret;
 }
 
 static void __exit ethtool_nl_exit(void)
 {
+	unregister_netdevice_notifier(&ethnl_netdev_notifier);
 	genl_unregister_family(&ethtool_genl_family);
 }
 
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 6e9e854eec5d..94c14ec2c3fc 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -11,6 +11,8 @@
 #define ETHNL_SET_ERRMSG(info, msg) \
 	do { if (info) GENL_SET_ERR_MSG(info, msg); } while (0)
 
+extern u32 ethnl_bcast_seq;
+
 extern struct genl_family ethtool_genl_family;
 
 struct net_device *ethnl_dev_get(struct genl_info *info, struct nlattr *nest);
@@ -159,4 +161,7 @@ static inline bool ethnl_is_privileged(struct sk_buff *skb)
 	return netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN);
 }
 
+void ethnl_notify(struct net_device *dev, struct netlink_ext_ack *extack,
+		  unsigned int cmd, u32 req_mask);
+
 #endif /* _NET_ETHTOOL_NETLINK_H */
-- 
2.18.0


  parent reply	other threads:[~2018-07-30 12:55 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-30 12:52 [RFC PATCH net-next v2 00/17] ethtool netlink interface (WiP) Michal Kubecek
2018-07-30 12:52 ` [RFC PATCH net-next v2 01/17] netlink: introduce nla_put_bitfield32() Michal Kubecek
2018-07-30 12:52 ` [RFC PATCH net-next v2 02/17] ethtool: move to its own directory Michal Kubecek
2018-07-30 12:52 ` [RFC PATCH net-next v2 03/17] ethtool: introduce ethtool netlink interface Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 04/17] ethtool: helper functions for " Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 05/17] ethtool: netlink bitset handling Michal Kubecek
2018-07-30 12:53 ` Michal Kubecek [this message]
2018-07-30 13:16   ` [RFC PATCH net-next v2 06/17] ethtool: support for netlink notifications Jiri Pirko
2018-07-30 17:01     ` Michal Kubecek
2018-07-31  6:46       ` Jiri Pirko
2018-07-30 12:53 ` [RFC PATCH net-next v2 07/17] ethtool: implement EVENT notifications Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 08/17] ethtool: implement GET_STRSET message Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 09/17] ethtool: implement GET_DRVINFO message Michal Kubecek
2018-07-30 13:21   ` Jiri Pirko
2018-07-30 14:37     ` Michal Kubecek
2018-07-30 14:28   ` Andrew Lunn
2018-07-30 14:46     ` Michal Kubecek
2018-07-30 15:48       ` Andrew Lunn
2018-07-30 16:47         ` Michal Kubecek
2018-07-31  0:56   ` Jakub Kicinski
2018-07-30 12:53 ` [RFC PATCH net-next v2 10/17] ethtool: implement GET_SETTINGS message Michal Kubecek
2018-07-30 18:54   ` Andrew Lunn
2018-08-21  9:32     ` Michal Kubecek
2018-08-21 14:10       ` Andrew Lunn
2018-08-21 14:52         ` Michal Kubecek
2018-07-30 19:06   ` Andrew Lunn
2018-07-30 19:09   ` Andrew Lunn
2018-07-30 19:42     ` Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 11/17] ethtool: implement GET_SETTINGS request for features Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 12/17] ethtool: implement SET_SETTINGS notification Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 13/17] ethtool: implement SET_SETTINGS message Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 14/17] ethtool: implement SET_SETTINGS request for features Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 15/17] ethtool: implement GET_PARAMS message Michal Kubecek
2018-07-30 12:54 ` [RFC PATCH net-next v2 16/17] ethtool: implement SET_PARAMS notification Michal Kubecek
2018-07-30 12:54 ` [RFC PATCH net-next v2 17/17] ethtool: implement SET_PARAMS message Michal Kubecek
2018-07-30 13:07 ` [RFC PATCH net-next v2 00/17] ethtool netlink interface (WiP) Jiri Pirko
2018-07-31  0:38   ` Jakub Kicinski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e0e0433fd250dc331caa23aa739d7841e9602e0f.1532953989.git.mkubecek@suse.cz \
    --to=mkubecek@suse.cz \
    --cc=davem@davemloft.net \
    --cc=f.fainelli@gmail.com \
    --cc=jiri@resnulli.us \
    --cc=kubakici@wp.pl \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linville@tuxdriver.com \
    --cc=netdev@vger.kernel.org \
    --cc=roopa@cumulusnetworks.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).