diff options
author | Leon Romanovsky <leonro@mellanox.com> | 2018-01-28 04:17:24 -0500 |
---|---|---|
committer | Jason Gunthorpe <jgg@mellanox.com> | 2018-01-29 22:21:40 -0500 |
commit | bf3c5a93c52368410a521af34ed3bff91a99df44 (patch) | |
tree | e8a43619c4c4682f45a93616806d8af01847ae9e | |
parent | 9d5f8c209b3f29259e6aa9595ea2dc2dfa27549a (diff) |
RDMA/nldev: Provide global resource utilization
Expose through the netlink interface the global per-device utilization of
the supported object types.
Provide both dumpit and doit callbacks.
As an example of possible output from rdmatool for system with 5
mlx5 cards:
$ rdma res
1: mlx5_0: qp 4 cq 5 pd 3
2: mlx5_1: qp 4 cq 5 pd 3
3: mlx5_2: qp 4 cq 5 pd 3
4: mlx5_3: qp 2 cq 3 pd 2
5: mlx5_4: qp 4 cq 5 pd 3
Reviewed-by: Mark Bloch <markb@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Reviewed-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
-rw-r--r-- | drivers/infiniband/core/nldev.c | 147 | ||||
-rw-r--r-- | include/uapi/rdma/rdma_netlink.h | 7 |
2 files changed, 154 insertions, 0 deletions
diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c index 5d790c507c7e..c37bb041f647 100644 --- a/drivers/infiniband/core/nldev.c +++ b/drivers/infiniband/core/nldev.c | |||
@@ -31,6 +31,8 @@ | |||
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/pid.h> | ||
35 | #include <linux/pid_namespace.h> | ||
34 | #include <net/netlink.h> | 36 | #include <net/netlink.h> |
35 | #include <rdma/rdma_netlink.h> | 37 | #include <rdma/rdma_netlink.h> |
36 | 38 | ||
@@ -52,6 +54,11 @@ static const struct nla_policy nldev_policy[RDMA_NLDEV_ATTR_MAX] = { | |||
52 | [RDMA_NLDEV_ATTR_PORT_STATE] = { .type = NLA_U8 }, | 54 | [RDMA_NLDEV_ATTR_PORT_STATE] = { .type = NLA_U8 }, |
53 | [RDMA_NLDEV_ATTR_PORT_PHYS_STATE] = { .type = NLA_U8 }, | 55 | [RDMA_NLDEV_ATTR_PORT_PHYS_STATE] = { .type = NLA_U8 }, |
54 | [RDMA_NLDEV_ATTR_DEV_NODE_TYPE] = { .type = NLA_U8 }, | 56 | [RDMA_NLDEV_ATTR_DEV_NODE_TYPE] = { .type = NLA_U8 }, |
57 | [RDMA_NLDEV_ATTR_RES_SUMMARY] = { .type = NLA_NESTED }, | ||
58 | [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY] = { .type = NLA_NESTED }, | ||
59 | [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME] = { .type = NLA_NUL_STRING, | ||
60 | .len = 16 }, | ||
61 | [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR] = { .type = NLA_U64 }, | ||
55 | }; | 62 | }; |
56 | 63 | ||
57 | static int fill_nldev_handle(struct sk_buff *msg, struct ib_device *device) | 64 | static int fill_nldev_handle(struct sk_buff *msg, struct ib_device *device) |
@@ -134,6 +141,65 @@ static int fill_port_info(struct sk_buff *msg, | |||
134 | return 0; | 141 | return 0; |
135 | } | 142 | } |
136 | 143 | ||
144 | static int fill_res_info_entry(struct sk_buff *msg, | ||
145 | const char *name, u64 curr) | ||
146 | { | ||
147 | struct nlattr *entry_attr; | ||
148 | |||
149 | entry_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY); | ||
150 | if (!entry_attr) | ||
151 | return -EMSGSIZE; | ||
152 | |||
153 | if (nla_put_string(msg, RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME, name)) | ||
154 | goto err; | ||
155 | if (nla_put_u64_64bit(msg, | ||
156 | RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR, curr, 0)) | ||
157 | goto err; | ||
158 | |||
159 | nla_nest_end(msg, entry_attr); | ||
160 | return 0; | ||
161 | |||
162 | err: | ||
163 | nla_nest_cancel(msg, entry_attr); | ||
164 | return -EMSGSIZE; | ||
165 | } | ||
166 | |||
167 | static int fill_res_info(struct sk_buff *msg, struct ib_device *device) | ||
168 | { | ||
169 | static const char * const names[RDMA_RESTRACK_MAX] = { | ||
170 | [RDMA_RESTRACK_PD] = "pd", | ||
171 | [RDMA_RESTRACK_CQ] = "cq", | ||
172 | [RDMA_RESTRACK_QP] = "qp", | ||
173 | }; | ||
174 | |||
175 | struct rdma_restrack_root *res = &device->res; | ||
176 | struct nlattr *table_attr; | ||
177 | int ret, i, curr; | ||
178 | |||
179 | if (fill_nldev_handle(msg, device)) | ||
180 | return -EMSGSIZE; | ||
181 | |||
182 | table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_SUMMARY); | ||
183 | if (!table_attr) | ||
184 | return -EMSGSIZE; | ||
185 | |||
186 | for (i = 0; i < RDMA_RESTRACK_MAX; i++) { | ||
187 | if (!names[i]) | ||
188 | continue; | ||
189 | curr = rdma_restrack_count(res, i, task_active_pid_ns(current)); | ||
190 | ret = fill_res_info_entry(msg, names[i], curr); | ||
191 | if (ret) | ||
192 | goto err; | ||
193 | } | ||
194 | |||
195 | nla_nest_end(msg, table_attr); | ||
196 | return 0; | ||
197 | |||
198 | err: | ||
199 | nla_nest_cancel(msg, table_attr); | ||
200 | return ret; | ||
201 | } | ||
202 | |||
137 | static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh, | 203 | static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh, |
138 | struct netlink_ext_ack *extack) | 204 | struct netlink_ext_ack *extack) |
139 | { | 205 | { |
@@ -329,6 +395,83 @@ out: | |||
329 | return skb->len; | 395 | return skb->len; |
330 | } | 396 | } |
331 | 397 | ||
398 | static int nldev_res_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh, | ||
399 | struct netlink_ext_ack *extack) | ||
400 | { | ||
401 | struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; | ||
402 | struct ib_device *device; | ||
403 | struct sk_buff *msg; | ||
404 | u32 index; | ||
405 | int ret; | ||
406 | |||
407 | ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, | ||
408 | nldev_policy, extack); | ||
409 | if (ret || !tb[RDMA_NLDEV_ATTR_DEV_INDEX]) | ||
410 | return -EINVAL; | ||
411 | |||
412 | index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); | ||
413 | device = ib_device_get_by_index(index); | ||
414 | if (!device) | ||
415 | return -EINVAL; | ||
416 | |||
417 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
418 | if (!msg) | ||
419 | goto err; | ||
420 | |||
421 | nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, | ||
422 | RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_RES_GET), | ||
423 | 0, 0); | ||
424 | |||
425 | ret = fill_res_info(msg, device); | ||
426 | if (ret) | ||
427 | goto err_free; | ||
428 | |||
429 | nlmsg_end(msg, nlh); | ||
430 | put_device(&device->dev); | ||
431 | return rdma_nl_unicast(msg, NETLINK_CB(skb).portid); | ||
432 | |||
433 | err_free: | ||
434 | nlmsg_free(msg); | ||
435 | err: | ||
436 | put_device(&device->dev); | ||
437 | return ret; | ||
438 | } | ||
439 | |||
440 | static int _nldev_res_get_dumpit(struct ib_device *device, | ||
441 | struct sk_buff *skb, | ||
442 | struct netlink_callback *cb, | ||
443 | unsigned int idx) | ||
444 | { | ||
445 | int start = cb->args[0]; | ||
446 | struct nlmsghdr *nlh; | ||
447 | |||
448 | if (idx < start) | ||
449 | return 0; | ||
450 | |||
451 | nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, | ||
452 | RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_RES_GET), | ||
453 | 0, NLM_F_MULTI); | ||
454 | |||
455 | if (fill_res_info(skb, device)) { | ||
456 | nlmsg_cancel(skb, nlh); | ||
457 | goto out; | ||
458 | } | ||
459 | |||
460 | nlmsg_end(skb, nlh); | ||
461 | |||
462 | idx++; | ||
463 | |||
464 | out: | ||
465 | cb->args[0] = idx; | ||
466 | return skb->len; | ||
467 | } | ||
468 | |||
469 | static int nldev_res_get_dumpit(struct sk_buff *skb, | ||
470 | struct netlink_callback *cb) | ||
471 | { | ||
472 | return ib_enum_all_devs(_nldev_res_get_dumpit, skb, cb); | ||
473 | } | ||
474 | |||
332 | static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = { | 475 | static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = { |
333 | [RDMA_NLDEV_CMD_GET] = { | 476 | [RDMA_NLDEV_CMD_GET] = { |
334 | .doit = nldev_get_doit, | 477 | .doit = nldev_get_doit, |
@@ -338,6 +481,10 @@ static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = { | |||
338 | .doit = nldev_port_get_doit, | 481 | .doit = nldev_port_get_doit, |
339 | .dump = nldev_port_get_dumpit, | 482 | .dump = nldev_port_get_dumpit, |
340 | }, | 483 | }, |
484 | [RDMA_NLDEV_CMD_RES_GET] = { | ||
485 | .doit = nldev_res_get_doit, | ||
486 | .dump = nldev_res_get_dumpit, | ||
487 | }, | ||
341 | }; | 488 | }; |
342 | 489 | ||
343 | void __init nldev_init(void) | 490 | void __init nldev_init(void) |
diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h index cc002e316d09..22c39532c411 100644 --- a/include/uapi/rdma/rdma_netlink.h +++ b/include/uapi/rdma/rdma_netlink.h | |||
@@ -236,6 +236,8 @@ enum rdma_nldev_command { | |||
236 | RDMA_NLDEV_CMD_PORT_NEW, | 236 | RDMA_NLDEV_CMD_PORT_NEW, |
237 | RDMA_NLDEV_CMD_PORT_DEL, | 237 | RDMA_NLDEV_CMD_PORT_DEL, |
238 | 238 | ||
239 | RDMA_NLDEV_CMD_RES_GET, /* can dump */ | ||
240 | |||
239 | RDMA_NLDEV_NUM_OPS | 241 | RDMA_NLDEV_NUM_OPS |
240 | }; | 242 | }; |
241 | 243 | ||
@@ -303,6 +305,11 @@ enum rdma_nldev_attr { | |||
303 | 305 | ||
304 | RDMA_NLDEV_ATTR_DEV_NODE_TYPE, /* u8 */ | 306 | RDMA_NLDEV_ATTR_DEV_NODE_TYPE, /* u8 */ |
305 | 307 | ||
308 | RDMA_NLDEV_ATTR_RES_SUMMARY, /* nested table */ | ||
309 | RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY, /* nested table */ | ||
310 | RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME, /* string */ | ||
311 | RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR, /* u64 */ | ||
312 | |||
306 | RDMA_NLDEV_ATTR_MAX | 313 | RDMA_NLDEV_ATTR_MAX |
307 | }; | 314 | }; |
308 | #endif /* _UAPI_RDMA_NETLINK_H */ | 315 | #endif /* _UAPI_RDMA_NETLINK_H */ |