diff mbox series

[1/3] netlink: Add notifier when changing netlink socket membership

Message ID 20240131120535.933424-2-stanislaw.gruszka@linux.intel.com (mailing list archive)
State Changes Requested, archived
Headers show
Series thermal/netlink/intel_hfi: Enable HFI feature only when required | expand

Commit Message

Stanislaw Gruszka Jan. 31, 2024, 12:05 p.m. UTC
Add notification when adding/removing multicast group to/from
client socket via setsockopt() syscall.

It can be used with conjunction with netlink_has_listeners() to check
if consumers of netlink multicast messages emerge or disappear.

A client can call netlink_register_notifier() to register a callback.
In the callback check for state NETLINK_CHANGE and NETLINK_URELEASE to
get notification for change in the netlink socket membership.

Thus, a client can now send events only when there are active consumers,
preventing unnecessary work when none exist.

Signed-off-by: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
---
 include/linux/notifier.h | 1 +
 net/netlink/af_netlink.c | 6 ++++++
 2 files changed, 7 insertions(+)

Comments

Jakub Kicinski Feb. 1, 2024, 1:40 a.m. UTC | #1
On Wed, 31 Jan 2024 13:05:33 +0100 Stanislaw Gruszka wrote:
> Add notification when adding/removing multicast group to/from
> client socket via setsockopt() syscall.
> 
> It can be used with conjunction with netlink_has_listeners() to check
> if consumers of netlink multicast messages emerge or disappear.
> 
> A client can call netlink_register_notifier() to register a callback.
> In the callback check for state NETLINK_CHANGE and NETLINK_URELEASE to
> get notification for change in the netlink socket membership.
> 
> Thus, a client can now send events only when there are active consumers,
> preventing unnecessary work when none exist.

Can we plumb thru the existing netlink_bind / netlink_unbind callbacks?
Add similar callbacks to the genl family struct to plumb it thru to
thermal. Then thermal can do what it wants with it (also add driver
callbacks or notifiers).

Having a driver listen to a core AF_NETLINK notifier to learn about
changes to a genl family it registers with skips too many layers to
easily reason about. At least for my taste.

When you repost please CC Florian W, Johannes B and Jiri P, off the top
of my head. Folks who most often work on netlink internals..
Stanislaw Gruszka Feb. 1, 2024, 1:10 p.m. UTC | #2
On Wed, Jan 31, 2024 at 05:40:56PM -0800, Jakub Kicinski wrote:
> On Wed, 31 Jan 2024 13:05:33 +0100 Stanislaw Gruszka wrote:
> > Add notification when adding/removing multicast group to/from
> > client socket via setsockopt() syscall.
> > 
> > It can be used with conjunction with netlink_has_listeners() to check
> > if consumers of netlink multicast messages emerge or disappear.
> > 
> > A client can call netlink_register_notifier() to register a callback.
> > In the callback check for state NETLINK_CHANGE and NETLINK_URELEASE to
> > get notification for change in the netlink socket membership.
> > 
> > Thus, a client can now send events only when there are active consumers,
> > preventing unnecessary work when none exist.
> 
> Can we plumb thru the existing netlink_bind / netlink_unbind callbacks?
>
> Add similar callbacks to the genl family struct to plumb it thru to
> thermal. Then thermal can do what it wants with it (also add driver
> callbacks or notifiers).

Yes, sure, can be done this way and make sense. Going to do this.

> Having a driver listen to a core AF_NETLINK notifier to learn about
> changes to a genl family it registers with skips too many layers to
> easily reason about. At least for my taste.
> 
> When you repost please CC Florian W, Johannes B and Jiri P, off the top
> of my head. Folks who most often work on netlink internals..

Ok.

Regards
Stanislaw
>
diff mbox series

Patch

diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 45702bdcbceb..8f5a5eed1e0e 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -227,6 +227,7 @@  static inline int notifier_to_errno(int ret)
 /* Virtual Terminal events are defined in include/linux/vt.h. */
 
 #define NETLINK_URELEASE	0x0001	/* Unicast netlink socket released */
+#define NETLINK_CHANGE		0x0002  /* Changed membership of netlink socket */
 
 /* Console keyboard events.
  * Note: KBD_KEYCODE is always sent before KBD_UNBOUND_KEYCODE, KBD_UNICODE and
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index eb086b06d60d..674af2cb0f12 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1680,6 +1680,11 @@  static int netlink_setsockopt(struct socket *sock, int level, int optname,
 	case NETLINK_ADD_MEMBERSHIP:
 	case NETLINK_DROP_MEMBERSHIP: {
 		int err;
+		struct netlink_notify n = {
+			.net = sock_net(sk),
+			.protocol = sk->sk_protocol,
+			.portid = nlk->portid,
+		};
 
 		if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
 			return -EPERM;
@@ -1700,6 +1705,7 @@  static int netlink_setsockopt(struct socket *sock, int level, int optname,
 		if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind)
 			nlk->netlink_unbind(sock_net(sk), val);
 
+		blocking_notifier_call_chain(&netlink_chain, NETLINK_CHANGE, &n);
 		break;
 	}
 	case NETLINK_BROADCAST_ERROR: