genetlink: introduce helpers to do filtered multicast
authorJiri Pirko <jiri@nvidia.com>
Sat, 16 Dec 2023 12:29:59 +0000 (13:29 +0100)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 19 Dec 2023 14:31:40 +0000 (15:31 +0100)
Currently it is possible for netlink kernel user to pass custom
filter function to broadcast send function netlink_broadcast_filtered().
However, this is not exposed to multicast send and to generic
netlink users.

Extend the api and introduce a netlink helper nlmsg_multicast_filtered()
and a generic netlink helper genlmsg_multicast_netns_filtered()
to allow generic netlink families to specify filter function
while sending multicast messages.

Signed-off-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
include/net/genetlink.h
include/net/netlink.h

index 6bc37f392a9a6926017c354c9dca60426f1e3557..85c63d4f16dd1ba20e0dc690500dd8fdb84846dd 100644 (file)
@@ -448,6 +448,35 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
                nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN);
 }
 
+/**
+ * genlmsg_multicast_netns_filtered - multicast a netlink message
+ *                                   to a specific netns with filter
+ *                                   function
+ * @family: the generic netlink family
+ * @net: the net namespace
+ * @skb: netlink message as socket buffer
+ * @portid: own netlink portid to avoid sending to yourself
+ * @group: offset of multicast group in groups array
+ * @flags: allocation flags
+ * @filter: filter function
+ * @filter_data: filter function private data
+ *
+ * Return: 0 on success, negative error code for failure.
+ */
+static inline int
+genlmsg_multicast_netns_filtered(const struct genl_family *family,
+                                struct net *net, struct sk_buff *skb,
+                                u32 portid, unsigned int group, gfp_t flags,
+                                netlink_filter_fn filter,
+                                void *filter_data)
+{
+       if (WARN_ON_ONCE(group >= family->n_mcgrps))
+               return -EINVAL;
+       group = family->mcgrp_offset + group;
+       return nlmsg_multicast_filtered(net->genl_sock, skb, portid, group,
+                                       flags, filter, filter_data);
+}
+
 /**
  * genlmsg_multicast_netns - multicast a netlink message to a specific netns
  * @family: the generic netlink family
@@ -461,10 +490,8 @@ static inline int genlmsg_multicast_netns(const struct genl_family *family,
                                          struct net *net, struct sk_buff *skb,
                                          u32 portid, unsigned int group, gfp_t flags)
 {
-       if (WARN_ON_ONCE(group >= family->n_mcgrps))
-               return -EINVAL;
-       group = family->mcgrp_offset + group;
-       return nlmsg_multicast(net->genl_sock, skb, portid, group, flags);
+       return genlmsg_multicast_netns_filtered(family, net, skb, portid,
+                                               group, flags, NULL, NULL);
 }
 
 /**
index 28039e57070aa0b129ad240b579838122daf45fa..c19ff921b661adbf7face59f282f7880e2db6293 100644 (file)
@@ -1087,27 +1087,50 @@ static inline void nlmsg_free(struct sk_buff *skb)
 }
 
 /**
- * nlmsg_multicast - multicast a netlink message
+ * nlmsg_multicast_filtered - multicast a netlink message with filter function
  * @sk: netlink socket to spread messages to
  * @skb: netlink message as socket buffer
  * @portid: own netlink portid to avoid sending to yourself
  * @group: multicast group id
  * @flags: allocation flags
+ * @filter: filter function
+ * @filter_data: filter function private data
+ *
+ * Return: 0 on success, negative error code for failure.
  */
-static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb,
-                                 u32 portid, unsigned int group, gfp_t flags)
+static inline int nlmsg_multicast_filtered(struct sock *sk, struct sk_buff *skb,
+                                          u32 portid, unsigned int group,
+                                          gfp_t flags,
+                                          netlink_filter_fn filter,
+                                          void *filter_data)
 {
        int err;
 
        NETLINK_CB(skb).dst_group = group;
 
-       err = netlink_broadcast(sk, skb, portid, group, flags);
+       err = netlink_broadcast_filtered(sk, skb, portid, group, flags,
+                                        filter, filter_data);
        if (err > 0)
                err = 0;
 
        return err;
 }
 
+/**
+ * nlmsg_multicast - multicast a netlink message
+ * @sk: netlink socket to spread messages to
+ * @skb: netlink message as socket buffer
+ * @portid: own netlink portid to avoid sending to yourself
+ * @group: multicast group id
+ * @flags: allocation flags
+ */
+static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb,
+                                 u32 portid, unsigned int group, gfp_t flags)
+{
+       return nlmsg_multicast_filtered(sk, skb, portid, group, flags,
+                                       NULL, NULL);
+}
+
 /**
  * nlmsg_unicast - unicast a netlink message
  * @sk: netlink socket to spread message to