Skip to content

Commit 13b127d

Browse files
Jiri PirkoPaolo Abeni
Jiri Pirko
authored and
Paolo Abeni
committed
devlink: add a command to set notification filter and use it for multicasts
Currently the user listening on a socket for devlink notifications gets always all messages for all existing instances, 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. Introduce a new devlink NOTIFY_FILTER_SET which the user passes the select attributes. Store these per-socket and use them for filtering messages during multicast send. Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent 971b4ad commit 13b127d

File tree

6 files changed

+169
-4
lines changed

6 files changed

+169
-4
lines changed

Documentation/netlink/specs/devlink.yaml

+10
Original file line numberDiff line numberDiff line change
@@ -2254,3 +2254,13 @@ 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

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/devl_internal.h

+32-2
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,41 @@ static inline bool devlink_nl_notify_need(struct devlink *devlink)
191191
DEVLINK_MCGRP_CONFIG);
192192
}
193193

194+
struct devlink_obj_desc {
195+
struct rcu_head rcu;
196+
const char *bus_name;
197+
const char *dev_name;
198+
long data[];
199+
};
200+
201+
static inline void devlink_nl_obj_desc_init(struct devlink_obj_desc *desc,
202+
struct devlink *devlink)
203+
{
204+
memset(desc, 0, sizeof(*desc));
205+
desc->bus_name = devlink->dev->bus->name;
206+
desc->dev_name = dev_name(devlink->dev);
207+
}
208+
209+
int devlink_nl_notify_filter(struct sock *dsk, struct sk_buff *skb, void *data);
210+
211+
static inline void devlink_nl_notify_send_desc(struct devlink *devlink,
212+
struct sk_buff *msg,
213+
struct devlink_obj_desc *desc)
214+
{
215+
genlmsg_multicast_netns_filtered(&devlink_nl_family,
216+
devlink_net(devlink),
217+
msg, 0, DEVLINK_MCGRP_CONFIG,
218+
GFP_KERNEL,
219+
devlink_nl_notify_filter, desc);
220+
}
221+
194222
static inline void devlink_nl_notify_send(struct devlink *devlink,
195223
struct sk_buff *msg)
196224
{
197-
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
198-
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
225+
struct devlink_obj_desc desc;
226+
227+
devlink_nl_obj_desc_init(&desc, devlink);
228+
devlink_nl_notify_send_desc(devlink, msg, &desc);
199229
}
200230

201231
/* Notify */

net/devlink/netlink.c

+108
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,111 @@ static const struct genl_multicast_group devlink_nl_mcgrps[] = {
1717
[DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
1818
};
1919

20+
struct devlink_nl_sock_priv {
21+
struct devlink_obj_desc __rcu *flt;
22+
spinlock_t flt_lock; /* Protects flt. */
23+
};
24+
25+
static void devlink_nl_sock_priv_init(void *priv)
26+
{
27+
struct devlink_nl_sock_priv *sk_priv = priv;
28+
29+
spin_lock_init(&sk_priv->flt_lock);
30+
}
31+
32+
static void devlink_nl_sock_priv_destroy(void *priv)
33+
{
34+
struct devlink_nl_sock_priv *sk_priv = priv;
35+
struct devlink_obj_desc *flt;
36+
37+
flt = rcu_dereference_protected(sk_priv->flt, true);
38+
kfree_rcu(flt, rcu);
39+
}
40+
41+
int devlink_nl_notify_filter_set_doit(struct sk_buff *skb,
42+
struct genl_info *info)
43+
{
44+
struct devlink_nl_sock_priv *sk_priv;
45+
struct nlattr **attrs = info->attrs;
46+
struct devlink_obj_desc *flt;
47+
size_t data_offset = 0;
48+
size_t data_size = 0;
49+
char *pos;
50+
51+
if (attrs[DEVLINK_ATTR_BUS_NAME])
52+
data_size = size_add(data_size,
53+
nla_len(attrs[DEVLINK_ATTR_BUS_NAME]) + 1);
54+
if (attrs[DEVLINK_ATTR_DEV_NAME])
55+
data_size = size_add(data_size,
56+
nla_len(attrs[DEVLINK_ATTR_DEV_NAME]) + 1);
57+
58+
flt = kzalloc(size_add(sizeof(*flt), data_size), GFP_KERNEL);
59+
if (!flt)
60+
return -ENOMEM;
61+
62+
pos = (char *) flt->data;
63+
if (attrs[DEVLINK_ATTR_BUS_NAME]) {
64+
data_offset += nla_strscpy(pos,
65+
attrs[DEVLINK_ATTR_BUS_NAME],
66+
data_size) + 1;
67+
flt->bus_name = pos;
68+
pos += data_offset;
69+
}
70+
if (attrs[DEVLINK_ATTR_DEV_NAME]) {
71+
nla_strscpy(pos, attrs[DEVLINK_ATTR_DEV_NAME],
72+
data_size - data_offset);
73+
flt->dev_name = pos;
74+
}
75+
76+
/* Don't attach empty filter. */
77+
if (!flt->bus_name && !flt->dev_name) {
78+
kfree(flt);
79+
flt = NULL;
80+
}
81+
82+
sk_priv = genl_sk_priv_get(&devlink_nl_family, NETLINK_CB(skb).sk);
83+
if (IS_ERR(sk_priv)) {
84+
kfree(flt);
85+
return PTR_ERR(sk_priv);
86+
}
87+
spin_lock(&sk_priv->flt_lock);
88+
flt = rcu_replace_pointer(sk_priv->flt, flt,
89+
lockdep_is_held(&sk_priv->flt_lock));
90+
spin_unlock(&sk_priv->flt_lock);
91+
kfree_rcu(flt, rcu);
92+
return 0;
93+
}
94+
95+
static bool devlink_obj_desc_match(const struct devlink_obj_desc *desc,
96+
const struct devlink_obj_desc *flt)
97+
{
98+
if (desc->bus_name && flt->bus_name &&
99+
strcmp(desc->bus_name, flt->bus_name))
100+
return false;
101+
if (desc->dev_name && flt->dev_name &&
102+
strcmp(desc->dev_name, flt->dev_name))
103+
return false;
104+
return true;
105+
}
106+
107+
int devlink_nl_notify_filter(struct sock *dsk, struct sk_buff *skb, void *data)
108+
{
109+
struct devlink_obj_desc *desc = data;
110+
struct devlink_nl_sock_priv *sk_priv;
111+
struct devlink_obj_desc *flt;
112+
int ret = 0;
113+
114+
rcu_read_lock();
115+
sk_priv = __genl_sk_priv_get(&devlink_nl_family, dsk);
116+
if (!IS_ERR_OR_NULL(sk_priv)) {
117+
flt = rcu_dereference(sk_priv->flt);
118+
if (flt)
119+
ret = !devlink_obj_desc_match(desc, flt);
120+
}
121+
rcu_read_unlock();
122+
return ret;
123+
}
124+
20125
int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
21126
struct devlink *devlink, int attrtype)
22127
{
@@ -256,4 +361,7 @@ struct genl_family devlink_nl_family __ro_after_init = {
256361
.resv_start_op = DEVLINK_CMD_SELFTESTS_RUN + 1,
257362
.mcgrps = devlink_nl_mcgrps,
258363
.n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
364+
.sock_priv_size = sizeof(struct devlink_nl_sock_priv),
365+
.sock_priv_init = devlink_nl_sock_priv_init,
366+
.sock_priv_destroy = devlink_nl_sock_priv_destroy,
259367
};

net/devlink/netlink_gen.c

+14-1
Original file line numberDiff line numberDiff line change
@@ -560,8 +560,14 @@ static const struct nla_policy devlink_selftests_run_nl_policy[DEVLINK_ATTR_SELF
560560
[DEVLINK_ATTR_SELFTESTS] = NLA_POLICY_NESTED(devlink_dl_selftest_id_nl_policy),
561561
};
562562

563+
/* DEVLINK_CMD_NOTIFY_FILTER_SET - do */
564+
static const struct nla_policy devlink_notify_filter_set_nl_policy[DEVLINK_ATTR_DEV_NAME + 1] = {
565+
[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
566+
[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
567+
};
568+
563569
/* Ops table for devlink */
564-
const struct genl_split_ops devlink_nl_ops[73] = {
570+
const struct genl_split_ops devlink_nl_ops[74] = {
565571
{
566572
.cmd = DEVLINK_CMD_GET,
567573
.validate = GENL_DONT_VALIDATE_STRICT,
@@ -1233,4 +1239,11 @@ const struct genl_split_ops devlink_nl_ops[73] = {
12331239
.maxattr = DEVLINK_ATTR_SELFTESTS,
12341240
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
12351241
},
1242+
{
1243+
.cmd = DEVLINK_CMD_NOTIFY_FILTER_SET,
1244+
.doit = devlink_nl_notify_filter_set_doit,
1245+
.policy = devlink_notify_filter_set_nl_policy,
1246+
.maxattr = DEVLINK_ATTR_DEV_NAME,
1247+
.flags = GENL_CMD_CAP_DO,
1248+
},
12361249
};

net/devlink/netlink_gen.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ extern const struct nla_policy devlink_dl_port_function_nl_policy[DEVLINK_PORT_F
1616
extern const struct nla_policy devlink_dl_selftest_id_nl_policy[DEVLINK_ATTR_SELFTEST_ID_FLASH + 1];
1717

1818
/* Ops table for devlink */
19-
extern const struct genl_split_ops devlink_nl_ops[73];
19+
extern const struct genl_split_ops devlink_nl_ops[74];
2020

2121
int devlink_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
2222
struct genl_info *info);
@@ -142,5 +142,7 @@ int devlink_nl_selftests_get_doit(struct sk_buff *skb, struct genl_info *info);
142142
int devlink_nl_selftests_get_dumpit(struct sk_buff *skb,
143143
struct netlink_callback *cb);
144144
int devlink_nl_selftests_run_doit(struct sk_buff *skb, struct genl_info *info);
145+
int devlink_nl_notify_filter_set_doit(struct sk_buff *skb,
146+
struct genl_info *info);
145147

146148
#endif /* _LINUX_DEVLINK_GEN_H */

0 commit comments

Comments
 (0)