xref: /openbmc/linux/drivers/infiniband/core/nldev.c (revision 287683d0)
16c80b41aSLeon Romanovsky /*
26c80b41aSLeon Romanovsky  * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
36c80b41aSLeon Romanovsky  *
46c80b41aSLeon Romanovsky  * Redistribution and use in source and binary forms, with or without
56c80b41aSLeon Romanovsky  * modification, are permitted provided that the following conditions are met:
66c80b41aSLeon Romanovsky  *
76c80b41aSLeon Romanovsky  * 1. Redistributions of source code must retain the above copyright
86c80b41aSLeon Romanovsky  *    notice, this list of conditions and the following disclaimer.
96c80b41aSLeon Romanovsky  * 2. Redistributions in binary form must reproduce the above copyright
106c80b41aSLeon Romanovsky  *    notice, this list of conditions and the following disclaimer in the
116c80b41aSLeon Romanovsky  *    documentation and/or other materials provided with the distribution.
126c80b41aSLeon Romanovsky  * 3. Neither the names of the copyright holders nor the names of its
136c80b41aSLeon Romanovsky  *    contributors may be used to endorse or promote products derived from
146c80b41aSLeon Romanovsky  *    this software without specific prior written permission.
156c80b41aSLeon Romanovsky  *
166c80b41aSLeon Romanovsky  * Alternatively, this software may be distributed under the terms of the
176c80b41aSLeon Romanovsky  * GNU General Public License ("GPL") version 2 as published by the Free
186c80b41aSLeon Romanovsky  * Software Foundation.
196c80b41aSLeon Romanovsky  *
206c80b41aSLeon Romanovsky  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
216c80b41aSLeon Romanovsky  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226c80b41aSLeon Romanovsky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236c80b41aSLeon Romanovsky  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
246c80b41aSLeon Romanovsky  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
256c80b41aSLeon Romanovsky  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
266c80b41aSLeon Romanovsky  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
276c80b41aSLeon Romanovsky  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
286c80b41aSLeon Romanovsky  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
296c80b41aSLeon Romanovsky  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
306c80b41aSLeon Romanovsky  * POSSIBILITY OF SUCH DAMAGE.
316c80b41aSLeon Romanovsky  */
326c80b41aSLeon Romanovsky 
33e3bf14bdSJason Gunthorpe #include <linux/module.h>
34b4c598a6SLeon Romanovsky #include <net/netlink.h>
356c80b41aSLeon Romanovsky #include <rdma/rdma_netlink.h>
366c80b41aSLeon Romanovsky 
376c80b41aSLeon Romanovsky #include "core_priv.h"
386c80b41aSLeon Romanovsky 
39b4c598a6SLeon Romanovsky static const struct nla_policy nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
40b4c598a6SLeon Romanovsky 	[RDMA_NLDEV_ATTR_DEV_INDEX]     = { .type = NLA_U32 },
41b4c598a6SLeon Romanovsky 	[RDMA_NLDEV_ATTR_DEV_NAME]	= { .type = NLA_NUL_STRING,
42b4c598a6SLeon Romanovsky 					    .len = IB_DEVICE_NAME_MAX - 1},
43b4c598a6SLeon Romanovsky 	[RDMA_NLDEV_ATTR_PORT_INDEX]	= { .type = NLA_U32 },
448621a7e3SLeon Romanovsky 	[RDMA_NLDEV_ATTR_FW_VERSION]	= { .type = NLA_NUL_STRING,
458621a7e3SLeon Romanovsky 					    .len = IB_FW_VERSION_NAME_MAX - 1},
461aaff896SLeon Romanovsky 	[RDMA_NLDEV_ATTR_NODE_GUID]	= { .type = NLA_U64 },
471aaff896SLeon Romanovsky 	[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID] = { .type = NLA_U64 },
4812026fbbSLeon Romanovsky 	[RDMA_NLDEV_ATTR_SUBNET_PREFIX]	= { .type = NLA_U64 },
4980a06dd3SLeon Romanovsky 	[RDMA_NLDEV_ATTR_LID]		= { .type = NLA_U32 },
5080a06dd3SLeon Romanovsky 	[RDMA_NLDEV_ATTR_SM_LID]	= { .type = NLA_U32 },
5134840feaSLeon Romanovsky 	[RDMA_NLDEV_ATTR_LMC]		= { .type = NLA_U8 },
525654e49dSLeon Romanovsky 	[RDMA_NLDEV_ATTR_PORT_STATE]	= { .type = NLA_U8 },
535654e49dSLeon Romanovsky 	[RDMA_NLDEV_ATTR_PORT_PHYS_STATE] = { .type = NLA_U8 },
541bb77b8cSLeon Romanovsky 	[RDMA_NLDEV_ATTR_DEV_NODE_TYPE] = { .type = NLA_U8 },
55b4c598a6SLeon Romanovsky };
56b4c598a6SLeon Romanovsky 
57b4c598a6SLeon Romanovsky static int fill_dev_info(struct sk_buff *msg, struct ib_device *device)
58b4c598a6SLeon Romanovsky {
598621a7e3SLeon Romanovsky 	char fw[IB_FW_VERSION_NAME_MAX];
608621a7e3SLeon Romanovsky 
61b4c598a6SLeon Romanovsky 	if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DEV_INDEX, device->index))
62b4c598a6SLeon Romanovsky 		return -EMSGSIZE;
63b4c598a6SLeon Romanovsky 	if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, device->name))
64b4c598a6SLeon Romanovsky 		return -EMSGSIZE;
65b4c598a6SLeon Romanovsky 	if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, rdma_end_port(device)))
66b4c598a6SLeon Romanovsky 		return -EMSGSIZE;
67ac505253SLeon Romanovsky 
68ac505253SLeon Romanovsky 	BUILD_BUG_ON(sizeof(device->attrs.device_cap_flags) != sizeof(u64));
69ac505253SLeon Romanovsky 	if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CAP_FLAGS,
70ac505253SLeon Romanovsky 			      device->attrs.device_cap_flags, 0))
71ac505253SLeon Romanovsky 		return -EMSGSIZE;
72ac505253SLeon Romanovsky 
738621a7e3SLeon Romanovsky 	ib_get_device_fw_str(device, fw);
748621a7e3SLeon Romanovsky 	/* Device without FW has strlen(fw) */
758621a7e3SLeon Romanovsky 	if (strlen(fw) && nla_put_string(msg, RDMA_NLDEV_ATTR_FW_VERSION, fw))
768621a7e3SLeon Romanovsky 		return -EMSGSIZE;
778621a7e3SLeon Romanovsky 
781aaff896SLeon Romanovsky 	if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_NODE_GUID,
791aaff896SLeon Romanovsky 			      be64_to_cpu(device->node_guid), 0))
801aaff896SLeon Romanovsky 		return -EMSGSIZE;
811aaff896SLeon Romanovsky 	if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_SYS_IMAGE_GUID,
821aaff896SLeon Romanovsky 			      be64_to_cpu(device->attrs.sys_image_guid), 0))
831aaff896SLeon Romanovsky 		return -EMSGSIZE;
841bb77b8cSLeon Romanovsky 	if (nla_put_u8(msg, RDMA_NLDEV_ATTR_DEV_NODE_TYPE, device->node_type))
851bb77b8cSLeon Romanovsky 		return -EMSGSIZE;
86b4c598a6SLeon Romanovsky 	return 0;
87b4c598a6SLeon Romanovsky }
88b4c598a6SLeon Romanovsky 
897d02f605SLeon Romanovsky static int fill_port_info(struct sk_buff *msg,
907d02f605SLeon Romanovsky 			  struct ib_device *device, u32 port)
917d02f605SLeon Romanovsky {
92ac505253SLeon Romanovsky 	struct ib_port_attr attr;
93ac505253SLeon Romanovsky 	int ret;
94ac505253SLeon Romanovsky 
957d02f605SLeon Romanovsky 	if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DEV_INDEX, device->index))
967d02f605SLeon Romanovsky 		return -EMSGSIZE;
977d02f605SLeon Romanovsky 	if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, device->name))
987d02f605SLeon Romanovsky 		return -EMSGSIZE;
997d02f605SLeon Romanovsky 	if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port))
1007d02f605SLeon Romanovsky 		return -EMSGSIZE;
101ac505253SLeon Romanovsky 
102ac505253SLeon Romanovsky 	ret = ib_query_port(device, port, &attr);
103ac505253SLeon Romanovsky 	if (ret)
104ac505253SLeon Romanovsky 		return ret;
105ac505253SLeon Romanovsky 
106ac505253SLeon Romanovsky 	BUILD_BUG_ON(sizeof(attr.port_cap_flags) > sizeof(u64));
107ac505253SLeon Romanovsky 	if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CAP_FLAGS,
108ac505253SLeon Romanovsky 			      (u64)attr.port_cap_flags, 0))
109ac505253SLeon Romanovsky 		return -EMSGSIZE;
11012026fbbSLeon Romanovsky 	if (rdma_protocol_ib(device, port) &&
11112026fbbSLeon Romanovsky 	    nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_SUBNET_PREFIX,
11212026fbbSLeon Romanovsky 			      attr.subnet_prefix, 0))
11312026fbbSLeon Romanovsky 		return -EMSGSIZE;
11480a06dd3SLeon Romanovsky 	if (rdma_protocol_ib(device, port)) {
11580a06dd3SLeon Romanovsky 		if (nla_put_u32(msg, RDMA_NLDEV_ATTR_LID, attr.lid))
11680a06dd3SLeon Romanovsky 			return -EMSGSIZE;
11780a06dd3SLeon Romanovsky 		if (nla_put_u32(msg, RDMA_NLDEV_ATTR_SM_LID, attr.sm_lid))
11880a06dd3SLeon Romanovsky 			return -EMSGSIZE;
11934840feaSLeon Romanovsky 		if (nla_put_u8(msg, RDMA_NLDEV_ATTR_LMC, attr.lmc))
12034840feaSLeon Romanovsky 			return -EMSGSIZE;
12180a06dd3SLeon Romanovsky 	}
1225654e49dSLeon Romanovsky 	if (nla_put_u8(msg, RDMA_NLDEV_ATTR_PORT_STATE, attr.state))
1235654e49dSLeon Romanovsky 		return -EMSGSIZE;
1245654e49dSLeon Romanovsky 	if (nla_put_u8(msg, RDMA_NLDEV_ATTR_PORT_PHYS_STATE, attr.phys_state))
1255654e49dSLeon Romanovsky 		return -EMSGSIZE;
1267d02f605SLeon Romanovsky 	return 0;
1277d02f605SLeon Romanovsky }
1287d02f605SLeon Romanovsky 
129e5c9469eSLeon Romanovsky static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
130e5c9469eSLeon Romanovsky 			  struct netlink_ext_ack *extack)
131e5c9469eSLeon Romanovsky {
132e5c9469eSLeon Romanovsky 	struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
133e5c9469eSLeon Romanovsky 	struct ib_device *device;
134e5c9469eSLeon Romanovsky 	struct sk_buff *msg;
135e5c9469eSLeon Romanovsky 	u32 index;
136e5c9469eSLeon Romanovsky 	int err;
137e5c9469eSLeon Romanovsky 
138e5c9469eSLeon Romanovsky 	err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
139e5c9469eSLeon Romanovsky 			  nldev_policy, extack);
140e5c9469eSLeon Romanovsky 	if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
141e5c9469eSLeon Romanovsky 		return -EINVAL;
142e5c9469eSLeon Romanovsky 
143e5c9469eSLeon Romanovsky 	index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
144e5c9469eSLeon Romanovsky 
145e5c9469eSLeon Romanovsky 	device = __ib_device_get_by_index(index);
146e5c9469eSLeon Romanovsky 	if (!device)
147e5c9469eSLeon Romanovsky 		return -EINVAL;
148e5c9469eSLeon Romanovsky 
149e5c9469eSLeon Romanovsky 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
150e5c9469eSLeon Romanovsky 	if (!msg)
151e5c9469eSLeon Romanovsky 		return -ENOMEM;
152e5c9469eSLeon Romanovsky 
153e5c9469eSLeon Romanovsky 	nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
154e5c9469eSLeon Romanovsky 			RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
155e5c9469eSLeon Romanovsky 			0, 0);
156e5c9469eSLeon Romanovsky 
157e5c9469eSLeon Romanovsky 	err = fill_dev_info(msg, device);
158e5c9469eSLeon Romanovsky 	if (err) {
159e5c9469eSLeon Romanovsky 		nlmsg_free(msg);
160e5c9469eSLeon Romanovsky 		return err;
161e5c9469eSLeon Romanovsky 	}
162e5c9469eSLeon Romanovsky 
163e5c9469eSLeon Romanovsky 	nlmsg_end(msg, nlh);
164e5c9469eSLeon Romanovsky 
165e5c9469eSLeon Romanovsky 	return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
166e5c9469eSLeon Romanovsky }
167e5c9469eSLeon Romanovsky 
168b4c598a6SLeon Romanovsky static int _nldev_get_dumpit(struct ib_device *device,
169b4c598a6SLeon Romanovsky 			     struct sk_buff *skb,
170b4c598a6SLeon Romanovsky 			     struct netlink_callback *cb,
171b4c598a6SLeon Romanovsky 			     unsigned int idx)
172b4c598a6SLeon Romanovsky {
173b4c598a6SLeon Romanovsky 	int start = cb->args[0];
174b4c598a6SLeon Romanovsky 	struct nlmsghdr *nlh;
175b4c598a6SLeon Romanovsky 
176b4c598a6SLeon Romanovsky 	if (idx < start)
177b4c598a6SLeon Romanovsky 		return 0;
178b4c598a6SLeon Romanovsky 
179b4c598a6SLeon Romanovsky 	nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
180b4c598a6SLeon Romanovsky 			RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
181b4c598a6SLeon Romanovsky 			0, NLM_F_MULTI);
182b4c598a6SLeon Romanovsky 
183b4c598a6SLeon Romanovsky 	if (fill_dev_info(skb, device)) {
184b4c598a6SLeon Romanovsky 		nlmsg_cancel(skb, nlh);
185b4c598a6SLeon Romanovsky 		goto out;
186b4c598a6SLeon Romanovsky 	}
187b4c598a6SLeon Romanovsky 
188b4c598a6SLeon Romanovsky 	nlmsg_end(skb, nlh);
189b4c598a6SLeon Romanovsky 
190b4c598a6SLeon Romanovsky 	idx++;
191b4c598a6SLeon Romanovsky 
192b4c598a6SLeon Romanovsky out:	cb->args[0] = idx;
193b4c598a6SLeon Romanovsky 	return skb->len;
194b4c598a6SLeon Romanovsky }
195b4c598a6SLeon Romanovsky 
196b4c598a6SLeon Romanovsky static int nldev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
197b4c598a6SLeon Romanovsky {
198b4c598a6SLeon Romanovsky 	/*
199b4c598a6SLeon Romanovsky 	 * There is no need to take lock, because
200b4c598a6SLeon Romanovsky 	 * we are relying on ib_core's lists_rwsem
201b4c598a6SLeon Romanovsky 	 */
202b4c598a6SLeon Romanovsky 	return ib_enum_all_devs(_nldev_get_dumpit, skb, cb);
203b4c598a6SLeon Romanovsky }
204b4c598a6SLeon Romanovsky 
205c3f66f7bSLeon Romanovsky static int nldev_port_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
206c3f66f7bSLeon Romanovsky 			       struct netlink_ext_ack *extack)
207c3f66f7bSLeon Romanovsky {
208c3f66f7bSLeon Romanovsky 	struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
209c3f66f7bSLeon Romanovsky 	struct ib_device *device;
210c3f66f7bSLeon Romanovsky 	struct sk_buff *msg;
211c3f66f7bSLeon Romanovsky 	u32 index;
212c3f66f7bSLeon Romanovsky 	u32 port;
213c3f66f7bSLeon Romanovsky 	int err;
214c3f66f7bSLeon Romanovsky 
215c3f66f7bSLeon Romanovsky 	err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
216c3f66f7bSLeon Romanovsky 			  nldev_policy, extack);
217287683d0SLeon Romanovsky 	if (err ||
218287683d0SLeon Romanovsky 	    !tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
219287683d0SLeon Romanovsky 	    !tb[RDMA_NLDEV_ATTR_PORT_INDEX])
220c3f66f7bSLeon Romanovsky 		return -EINVAL;
221c3f66f7bSLeon Romanovsky 
222c3f66f7bSLeon Romanovsky 	index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
223c3f66f7bSLeon Romanovsky 	device = __ib_device_get_by_index(index);
224c3f66f7bSLeon Romanovsky 	if (!device)
225c3f66f7bSLeon Romanovsky 		return -EINVAL;
226c3f66f7bSLeon Romanovsky 
227c3f66f7bSLeon Romanovsky 	port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
228c3f66f7bSLeon Romanovsky 	if (!rdma_is_port_valid(device, port))
229c3f66f7bSLeon Romanovsky 		return -EINVAL;
230c3f66f7bSLeon Romanovsky 
231c3f66f7bSLeon Romanovsky 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
232c3f66f7bSLeon Romanovsky 	if (!msg)
233c3f66f7bSLeon Romanovsky 		return -ENOMEM;
234c3f66f7bSLeon Romanovsky 
235c3f66f7bSLeon Romanovsky 	nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
236c3f66f7bSLeon Romanovsky 			RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
237c3f66f7bSLeon Romanovsky 			0, 0);
238c3f66f7bSLeon Romanovsky 
239c3f66f7bSLeon Romanovsky 	err = fill_port_info(msg, device, port);
240c3f66f7bSLeon Romanovsky 	if (err) {
241c3f66f7bSLeon Romanovsky 		nlmsg_free(msg);
242c3f66f7bSLeon Romanovsky 		return err;
243c3f66f7bSLeon Romanovsky 	}
244c3f66f7bSLeon Romanovsky 
245c3f66f7bSLeon Romanovsky 	nlmsg_end(msg, nlh);
246c3f66f7bSLeon Romanovsky 
247c3f66f7bSLeon Romanovsky 	return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
248c3f66f7bSLeon Romanovsky }
249c3f66f7bSLeon Romanovsky 
2507d02f605SLeon Romanovsky static int nldev_port_get_dumpit(struct sk_buff *skb,
2517d02f605SLeon Romanovsky 				 struct netlink_callback *cb)
2527d02f605SLeon Romanovsky {
2537d02f605SLeon Romanovsky 	struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
2547d02f605SLeon Romanovsky 	struct ib_device *device;
2557d02f605SLeon Romanovsky 	int start = cb->args[0];
2567d02f605SLeon Romanovsky 	struct nlmsghdr *nlh;
2577d02f605SLeon Romanovsky 	u32 idx = 0;
2587d02f605SLeon Romanovsky 	u32 ifindex;
2597d02f605SLeon Romanovsky 	int err;
2607d02f605SLeon Romanovsky 	u32 p;
2617d02f605SLeon Romanovsky 
2627d02f605SLeon Romanovsky 	err = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
2637d02f605SLeon Romanovsky 			  nldev_policy, NULL);
2647d02f605SLeon Romanovsky 	if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
2657d02f605SLeon Romanovsky 		return -EINVAL;
2667d02f605SLeon Romanovsky 
2677d02f605SLeon Romanovsky 	ifindex = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
2687d02f605SLeon Romanovsky 	device = __ib_device_get_by_index(ifindex);
2697d02f605SLeon Romanovsky 	if (!device)
2707d02f605SLeon Romanovsky 		return -EINVAL;
2717d02f605SLeon Romanovsky 
2727d02f605SLeon Romanovsky 	for (p = rdma_start_port(device); p <= rdma_end_port(device); ++p) {
2737d02f605SLeon Romanovsky 		/*
2747d02f605SLeon Romanovsky 		 * The dumpit function returns all information from specific
2757d02f605SLeon Romanovsky 		 * index. This specific index is taken from the netlink
2767d02f605SLeon Romanovsky 		 * messages request sent by user and it is available
2777d02f605SLeon Romanovsky 		 * in cb->args[0].
2787d02f605SLeon Romanovsky 		 *
2797d02f605SLeon Romanovsky 		 * Usually, the user doesn't fill this field and it causes
2807d02f605SLeon Romanovsky 		 * to return everything.
2817d02f605SLeon Romanovsky 		 *
2827d02f605SLeon Romanovsky 		 */
2837d02f605SLeon Romanovsky 		if (idx < start) {
2847d02f605SLeon Romanovsky 			idx++;
2857d02f605SLeon Romanovsky 			continue;
2867d02f605SLeon Romanovsky 		}
2877d02f605SLeon Romanovsky 
2887d02f605SLeon Romanovsky 		nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid,
2897d02f605SLeon Romanovsky 				cb->nlh->nlmsg_seq,
2907d02f605SLeon Romanovsky 				RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
2917d02f605SLeon Romanovsky 						 RDMA_NLDEV_CMD_PORT_GET),
2927d02f605SLeon Romanovsky 				0, NLM_F_MULTI);
2937d02f605SLeon Romanovsky 
2947d02f605SLeon Romanovsky 		if (fill_port_info(skb, device, p)) {
2957d02f605SLeon Romanovsky 			nlmsg_cancel(skb, nlh);
2967d02f605SLeon Romanovsky 			goto out;
2977d02f605SLeon Romanovsky 		}
2987d02f605SLeon Romanovsky 		idx++;
2997d02f605SLeon Romanovsky 		nlmsg_end(skb, nlh);
3007d02f605SLeon Romanovsky 	}
3017d02f605SLeon Romanovsky 
3027d02f605SLeon Romanovsky out:	cb->args[0] = idx;
3037d02f605SLeon Romanovsky 	return skb->len;
3047d02f605SLeon Romanovsky }
3057d02f605SLeon Romanovsky 
306b4c598a6SLeon Romanovsky static const struct rdma_nl_cbs nldev_cb_table[] = {
307b4c598a6SLeon Romanovsky 	[RDMA_NLDEV_CMD_GET] = {
308e5c9469eSLeon Romanovsky 		.doit = nldev_get_doit,
309b4c598a6SLeon Romanovsky 		.dump = nldev_get_dumpit,
310b4c598a6SLeon Romanovsky 	},
3117d02f605SLeon Romanovsky 	[RDMA_NLDEV_CMD_PORT_GET] = {
312c3f66f7bSLeon Romanovsky 		.doit = nldev_port_get_doit,
3137d02f605SLeon Romanovsky 		.dump = nldev_port_get_dumpit,
3147d02f605SLeon Romanovsky 	},
315b4c598a6SLeon Romanovsky };
316b4c598a6SLeon Romanovsky 
3176c80b41aSLeon Romanovsky void __init nldev_init(void)
3186c80b41aSLeon Romanovsky {
319b4c598a6SLeon Romanovsky 	rdma_nl_register(RDMA_NL_NLDEV, nldev_cb_table);
3206c80b41aSLeon Romanovsky }
3216c80b41aSLeon Romanovsky 
3226c80b41aSLeon Romanovsky void __exit nldev_exit(void)
3236c80b41aSLeon Romanovsky {
3246c80b41aSLeon Romanovsky 	rdma_nl_unregister(RDMA_NL_NLDEV);
3256c80b41aSLeon Romanovsky }
326e3bf14bdSJason Gunthorpe 
327e3bf14bdSJason Gunthorpe MODULE_ALIAS_RDMA_NETLINK(RDMA_NL_NLDEV, 5);
328