Skip to content

Commit 62ed78f

Browse files
author
Paolo Abeni
committed
Merge branch 'devlink-introduce-notifications-filtering'
Jiri Pirko says: ==================== devlink: introduce notifications filtering From: Jiri Pirko <[email protected]> Currently the user listening on a socket for devlink notifications gets always all messages for all existing devlink instances and objects, even if he is interested only in one of those. That may cause unnecessary overhead on setups with thousands of instances present. User is currently able to narrow down the devlink objects replies to dump commands by specifying select attributes. Allow similar approach for notifications providing user a new notify-filter-set command to select attributes with values the notification message has to match. In that case, it is delivered to the socket. Note that the filtering is done per-socket, so multiple users may specify different selection of attributes with values. This patchset initially introduces support for following attributes: DEVLINK_ATTR_BUS_NAME DEVLINK_ATTR_DEV_NAME DEVLINK_ATTR_PORT_INDEX Patches #1 - #4 are preparations in devlink code, patch #3 is an optimization done on the way. Patches #5 - #7 are preparations in netlink and generic netlink code. Patch #8 is the main one in this set implementing of the notify-filter-set command and the actual per-socket filtering. Patch #9 extends the infrastructure allowing to filter according to a port index. Example: $ devlink mon port pci/0000:08:00.0/32768 [port,new] pci/0000:08:00.0/32768: type notset flavour pcisf controller 0 pfnum 0 sfnum 107 splittable false function: hw_addr 00:00:00:00:00:00 state inactive opstate detached roce enable [port,new] pci/0000:08:00.0/32768: type eth flavour pcisf controller 0 pfnum 0 sfnum 107 splittable false function: hw_addr 00:00:00:00:00:00 state inactive opstate detached roce enable [port,new] pci/0000:08:00.0/32768: type eth netdev eth3 flavour pcisf controller 0 pfnum 0 sfnum 107 splittable false function: hw_addr 00:00:00:00:00:00 state inactive opstate detached roce enable [port,new] pci/0000:08:00.0/32768: type eth netdev eth3 flavour pcisf controller 0 pfnum 0 sfnum 107 splittable false function: hw_addr 00:00:00:00:00:00 state inactive opstate detached roce enable [port,new] pci/0000:08:00.0/32768: type eth flavour pcisf controller 0 pfnum 0 sfnum 107 splittable false function: hw_addr 00:00:00:00:00:00 state inactive opstate detached roce enable [port,new] pci/0000:08:00.0/32768: type notset flavour pcisf controller 0 pfnum 0 sfnum 107 splittable false function: hw_addr 00:00:00:00:00:00 state inactive opstate detached roce enable [port,del] pci/0000:08:00.0/32768: type notset flavour pcisf controller 0 pfnum 0 sfnum 107 splittable false function: hw_addr 00:00:00:00:00:00 state inactive opstate detached roce enable ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents f7dd48e + ded6f77 commit 62ed78f

File tree

21 files changed

+463
-53
lines changed

21 files changed

+463
-53
lines changed

Documentation/netlink/specs/devlink.yaml

+11
Original file line numberDiff line numberDiff line change
@@ -2254,3 +2254,14 @@ operations:
22542254
- bus-name
22552255
- dev-name
22562256
- selftests
2257+
2258+
-
2259+
name: notify-filter-set
2260+
doc: Set notification messages socket filter.
2261+
attribute-set: devlink
2262+
do:
2263+
request:
2264+
attributes:
2265+
- bus-name
2266+
- dev-name
2267+
- port-index

drivers/connector/connector.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,8 @@ static int cn_already_initialized;
5959
* both, or if both are zero then the group is looked up and sent there.
6060
*/
6161
int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid, u32 __group,
62-
gfp_t gfp_mask,
63-
int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data),
64-
void *filter_data)
62+
gfp_t gfp_mask, netlink_filter_fn filter,
63+
void *filter_data)
6564
{
6665
struct cn_callback_entry *__cbq;
6766
unsigned int size;

include/linux/connector.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ void cn_del_callback(const struct cb_id *id);
100100
*/
101101
int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid,
102102
u32 group, gfp_t gfp_mask,
103-
int (*filter)(struct sock *dsk, struct sk_buff *skb,
104-
void *data),
103+
netlink_filter_fn filter,
105104
void *filter_data);
106105

107106
/**

include/linux/netlink.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,12 @@ bool netlink_strict_get_check(struct sk_buff *skb);
228228
int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock);
229229
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid,
230230
__u32 group, gfp_t allocation);
231+
232+
typedef int (*netlink_filter_fn)(struct sock *dsk, struct sk_buff *skb, void *data);
233+
231234
int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb,
232235
__u32 portid, __u32 group, gfp_t allocation,
233-
int (*filter)(struct sock *dsk,
234-
struct sk_buff *skb, void *data),
236+
netlink_filter_fn filter,
235237
void *filter_data);
236238
int netlink_set_err(struct sock *ssk, __u32 portid, __u32 group, int code);
237239
int netlink_register_notifier(struct notifier_block *nb);

include/net/genetlink.h

+42-4
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ struct genl_info;
5151
* @split_ops: the split do/dump form of operation definition
5252
* @n_split_ops: number of entries in @split_ops, not that with split do/dump
5353
* ops the number of entries is not the same as number of commands
54+
* @sock_priv_size: the size of per-socket private memory
55+
* @sock_priv_init: the per-socket private memory initializer
56+
* @sock_priv_destroy: the per-socket private memory destructor
5457
*
5558
* Attribute policies (the combination of @policy and @maxattr fields)
5659
* can be attached at the family level or at the operation level.
@@ -84,11 +87,17 @@ struct genl_family {
8487
const struct genl_multicast_group *mcgrps;
8588
struct module *module;
8689

90+
size_t sock_priv_size;
91+
void (*sock_priv_init)(void *priv);
92+
void (*sock_priv_destroy)(void *priv);
93+
8794
/* private: internal use only */
8895
/* protocol family identifier */
8996
int id;
9097
/* starting number of multicast group IDs in this family */
9198
unsigned int mcgrp_offset;
99+
/* list of per-socket privs */
100+
struct xarray *sock_privs;
92101
};
93102

94103
/**
@@ -298,6 +307,8 @@ static inline bool genl_info_is_ntf(const struct genl_info *info)
298307
return !info->nlhdr;
299308
}
300309

310+
void *__genl_sk_priv_get(struct genl_family *family, struct sock *sk);
311+
void *genl_sk_priv_get(struct genl_family *family, struct sock *sk);
301312
int genl_register_family(struct genl_family *family);
302313
int genl_unregister_family(const struct genl_family *family);
303314
void genl_notify(const struct genl_family *family, struct sk_buff *skb,
@@ -437,6 +448,35 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
437448
nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN);
438449
}
439450

451+
/**
452+
* genlmsg_multicast_netns_filtered - multicast a netlink message
453+
* to a specific netns with filter
454+
* function
455+
* @family: the generic netlink family
456+
* @net: the net namespace
457+
* @skb: netlink message as socket buffer
458+
* @portid: own netlink portid to avoid sending to yourself
459+
* @group: offset of multicast group in groups array
460+
* @flags: allocation flags
461+
* @filter: filter function
462+
* @filter_data: filter function private data
463+
*
464+
* Return: 0 on success, negative error code for failure.
465+
*/
466+
static inline int
467+
genlmsg_multicast_netns_filtered(const struct genl_family *family,
468+
struct net *net, struct sk_buff *skb,
469+
u32 portid, unsigned int group, gfp_t flags,
470+
netlink_filter_fn filter,
471+
void *filter_data)
472+
{
473+
if (WARN_ON_ONCE(group >= family->n_mcgrps))
474+
return -EINVAL;
475+
group = family->mcgrp_offset + group;
476+
return nlmsg_multicast_filtered(net->genl_sock, skb, portid, group,
477+
flags, filter, filter_data);
478+
}
479+
440480
/**
441481
* genlmsg_multicast_netns - multicast a netlink message to a specific netns
442482
* @family: the generic netlink family
@@ -450,10 +490,8 @@ static inline int genlmsg_multicast_netns(const struct genl_family *family,
450490
struct net *net, struct sk_buff *skb,
451491
u32 portid, unsigned int group, gfp_t flags)
452492
{
453-
if (WARN_ON_ONCE(group >= family->n_mcgrps))
454-
return -EINVAL;
455-
group = family->mcgrp_offset + group;
456-
return nlmsg_multicast(net->genl_sock, skb, portid, group, flags);
493+
return genlmsg_multicast_netns_filtered(family, net, skb, portid,
494+
group, flags, NULL, NULL);
457495
}
458496

459497
/**

include/net/netlink.h

+27-4
Original file line numberDiff line numberDiff line change
@@ -1087,27 +1087,50 @@ static inline void nlmsg_free(struct sk_buff *skb)
10871087
}
10881088

10891089
/**
1090-
* nlmsg_multicast - multicast a netlink message
1090+
* nlmsg_multicast_filtered - multicast a netlink message with filter function
10911091
* @sk: netlink socket to spread messages to
10921092
* @skb: netlink message as socket buffer
10931093
* @portid: own netlink portid to avoid sending to yourself
10941094
* @group: multicast group id
10951095
* @flags: allocation flags
1096+
* @filter: filter function
1097+
* @filter_data: filter function private data
1098+
*
1099+
* Return: 0 on success, negative error code for failure.
10961100
*/
1097-
static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb,
1098-
u32 portid, unsigned int group, gfp_t flags)
1101+
static inline int nlmsg_multicast_filtered(struct sock *sk, struct sk_buff *skb,
1102+
u32 portid, unsigned int group,
1103+
gfp_t flags,
1104+
netlink_filter_fn filter,
1105+
void *filter_data)
10991106
{
11001107
int err;
11011108

11021109
NETLINK_CB(skb).dst_group = group;
11031110

1104-
err = netlink_broadcast(sk, skb, portid, group, flags);
1111+
err = netlink_broadcast_filtered(sk, skb, portid, group, flags,
1112+
filter, filter_data);
11051113
if (err > 0)
11061114
err = 0;
11071115

11081116
return err;
11091117
}
11101118

1119+
/**
1120+
* nlmsg_multicast - multicast a netlink message
1121+
* @sk: netlink socket to spread messages to
1122+
* @skb: netlink message as socket buffer
1123+
* @portid: own netlink portid to avoid sending to yourself
1124+
* @group: multicast group id
1125+
* @flags: allocation flags
1126+
*/
1127+
static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb,
1128+
u32 portid, unsigned int group, gfp_t flags)
1129+
{
1130+
return nlmsg_multicast_filtered(sk, skb, portid, group, flags,
1131+
NULL, NULL);
1132+
}
1133+
11111134
/**
11121135
* nlmsg_unicast - unicast a netlink message
11131136
* @sk: netlink socket to spread message to

include/uapi/linux/devlink.h

+2
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ enum devlink_command {
139139
DEVLINK_CMD_SELFTESTS_GET, /* can dump */
140140
DEVLINK_CMD_SELFTESTS_RUN,
141141

142+
DEVLINK_CMD_NOTIFY_FILTER_SET,
143+
142144
/* add new commands above here */
143145
__DEVLINK_CMD_MAX,
144146
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1

net/devlink/dev.c

+7-6
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,10 @@ static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
202202
int err;
203203

204204
WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
205-
WARN_ON(!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED));
205+
WARN_ON(!devl_is_registered(devlink));
206+
207+
if (!devlink_nl_notify_need(devlink))
208+
return;
206209

207210
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
208211
if (!msg)
@@ -214,8 +217,7 @@ static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
214217
return;
215218
}
216219

217-
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
218-
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
220+
devlink_nl_notify_send(devlink, msg);
219221
}
220222

221223
int devlink_nl_get_doit(struct sk_buff *skb, struct genl_info *info)
@@ -999,7 +1001,7 @@ static void __devlink_flash_update_notify(struct devlink *devlink,
9991001
cmd != DEVLINK_CMD_FLASH_UPDATE_END &&
10001002
cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS);
10011003

1002-
if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
1004+
if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
10031005
return;
10041006

10051007
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -1010,8 +1012,7 @@ static void __devlink_flash_update_notify(struct devlink *devlink,
10101012
if (err)
10111013
goto out_free_msg;
10121014

1013-
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
1014-
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
1015+
devlink_nl_notify_send(devlink, msg);
10151016
return;
10161017

10171018
out_free_msg:

net/devlink/devl_internal.h

+58-1
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,15 @@ extern struct genl_family devlink_nl_family;
9191

9292
struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp);
9393

94+
static inline bool __devl_is_registered(struct devlink *devlink)
95+
{
96+
return xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
97+
}
98+
9499
static inline bool devl_is_registered(struct devlink *devlink)
95100
{
96101
devl_assert_locked(devlink);
97-
return xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
102+
return __devl_is_registered(devlink);
98103
}
99104

100105
static inline void devl_dev_lock(struct devlink *devlink, bool dev_lock)
@@ -180,6 +185,58 @@ int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
180185
struct devlink *devlink, int attrtype);
181186
int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info);
182187

188+
static inline bool devlink_nl_notify_need(struct devlink *devlink)
189+
{
190+
return genl_has_listeners(&devlink_nl_family, devlink_net(devlink),
191+
DEVLINK_MCGRP_CONFIG);
192+
}
193+
194+
struct devlink_obj_desc {
195+
struct rcu_head rcu;
196+
const char *bus_name;
197+
const char *dev_name;
198+
unsigned int port_index;
199+
bool port_index_valid;
200+
long data[];
201+
};
202+
203+
static inline void devlink_nl_obj_desc_init(struct devlink_obj_desc *desc,
204+
struct devlink *devlink)
205+
{
206+
memset(desc, 0, sizeof(*desc));
207+
desc->bus_name = devlink->dev->bus->name;
208+
desc->dev_name = dev_name(devlink->dev);
209+
}
210+
211+
static inline void devlink_nl_obj_desc_port_set(struct devlink_obj_desc *desc,
212+
struct devlink_port *devlink_port)
213+
{
214+
desc->port_index = devlink_port->index;
215+
desc->port_index_valid = true;
216+
}
217+
218+
int devlink_nl_notify_filter(struct sock *dsk, struct sk_buff *skb, void *data);
219+
220+
static inline void devlink_nl_notify_send_desc(struct devlink *devlink,
221+
struct sk_buff *msg,
222+
struct devlink_obj_desc *desc)
223+
{
224+
genlmsg_multicast_netns_filtered(&devlink_nl_family,
225+
devlink_net(devlink),
226+
msg, 0, DEVLINK_MCGRP_CONFIG,
227+
GFP_KERNEL,
228+
devlink_nl_notify_filter, desc);
229+
}
230+
231+
static inline void devlink_nl_notify_send(struct devlink *devlink,
232+
struct sk_buff *msg)
233+
{
234+
struct devlink_obj_desc desc;
235+
236+
devlink_nl_obj_desc_init(&desc, devlink);
237+
devlink_nl_notify_send_desc(devlink, msg, &desc);
238+
}
239+
183240
/* Notify */
184241
void devlink_notify_register(struct devlink *devlink);
185242
void devlink_notify_unregister(struct devlink *devlink);

net/devlink/health.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -490,12 +490,16 @@ static void devlink_recover_notify(struct devlink_health_reporter *reporter,
490490
enum devlink_command cmd)
491491
{
492492
struct devlink *devlink = reporter->devlink;
493+
struct devlink_obj_desc desc;
493494
struct sk_buff *msg;
494495
int err;
495496

496497
WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
497498
ASSERT_DEVLINK_REGISTERED(devlink);
498499

500+
if (!devlink_nl_notify_need(devlink))
501+
return;
502+
499503
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
500504
if (!msg)
501505
return;
@@ -506,8 +510,10 @@ static void devlink_recover_notify(struct devlink_health_reporter *reporter,
506510
return;
507511
}
508512

509-
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), msg,
510-
0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
513+
devlink_nl_obj_desc_init(&desc, devlink);
514+
if (reporter->devlink_port)
515+
devlink_nl_obj_desc_port_set(&desc, reporter->devlink_port);
516+
devlink_nl_notify_send_desc(devlink, msg, &desc);
511517
}
512518

513519
void

net/devlink/linecard.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ static void devlink_linecard_notify(struct devlink_linecard *linecard,
136136
WARN_ON(cmd != DEVLINK_CMD_LINECARD_NEW &&
137137
cmd != DEVLINK_CMD_LINECARD_DEL);
138138

139-
if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
139+
if (!__devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
140140
return;
141141

142142
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -150,8 +150,7 @@ static void devlink_linecard_notify(struct devlink_linecard *linecard,
150150
return;
151151
}
152152

153-
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
154-
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
153+
devlink_nl_notify_send(devlink, msg);
155154
}
156155

157156
void devlink_linecards_notify_register(struct devlink *devlink)

0 commit comments

Comments
 (0)