blob: 32ccb2b8893374d138d26c55906f1a2efef14bad [file] [log] [blame]
Leon Romanovsky6c80b412017-06-20 09:14:15 +03001/*
2 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the names of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * Alternatively, this software may be distributed under the terms of the
17 * GNU General Public License ("GPL") version 2 as published by the Free
18 * Software Foundation.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
Leon Romanovskyb4c598a2017-06-20 09:59:14 +030033#include <net/netlink.h>
Leon Romanovsky6c80b412017-06-20 09:14:15 +030034#include <rdma/rdma_netlink.h>
35
36#include "core_priv.h"
37
Leon Romanovskyb4c598a2017-06-20 09:59:14 +030038static const struct nla_policy nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
39 [RDMA_NLDEV_ATTR_DEV_INDEX] = { .type = NLA_U32 },
40 [RDMA_NLDEV_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING,
41 .len = IB_DEVICE_NAME_MAX - 1},
42 [RDMA_NLDEV_ATTR_PORT_INDEX] = { .type = NLA_U32 },
Leon Romanovsky8621a7e2017-06-27 16:58:59 +030043 [RDMA_NLDEV_ATTR_FW_VERSION] = { .type = NLA_NUL_STRING,
44 .len = IB_FW_VERSION_NAME_MAX - 1},
Leon Romanovsky1aaff892017-06-28 14:01:37 +030045 [RDMA_NLDEV_ATTR_NODE_GUID] = { .type = NLA_U64 },
46 [RDMA_NLDEV_ATTR_SYS_IMAGE_GUID] = { .type = NLA_U64 },
Leon Romanovsky12026fb2017-06-28 15:05:14 +030047 [RDMA_NLDEV_ATTR_SUBNET_PREFIX] = { .type = NLA_U64 },
Leon Romanovsky80a06dd2017-06-28 15:38:36 +030048 [RDMA_NLDEV_ATTR_LID] = { .type = NLA_U32 },
49 [RDMA_NLDEV_ATTR_SM_LID] = { .type = NLA_U32 },
Leon Romanovsky34840fe2017-06-28 15:49:30 +030050 [RDMA_NLDEV_ATTR_LMC] = { .type = NLA_U8 },
Leon Romanovsky5654e492017-06-29 13:12:45 +030051 [RDMA_NLDEV_ATTR_PORT_STATE] = { .type = NLA_U8 },
52 [RDMA_NLDEV_ATTR_PORT_PHYS_STATE] = { .type = NLA_U8 },
Leon Romanovskyb4c598a2017-06-20 09:59:14 +030053};
54
55static int fill_dev_info(struct sk_buff *msg, struct ib_device *device)
56{
Leon Romanovsky8621a7e2017-06-27 16:58:59 +030057 char fw[IB_FW_VERSION_NAME_MAX];
58
Leon Romanovskyb4c598a2017-06-20 09:59:14 +030059 if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DEV_INDEX, device->index))
60 return -EMSGSIZE;
61 if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, device->name))
62 return -EMSGSIZE;
63 if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, rdma_end_port(device)))
64 return -EMSGSIZE;
Leon Romanovskyac505252017-06-20 14:47:08 +030065
66 BUILD_BUG_ON(sizeof(device->attrs.device_cap_flags) != sizeof(u64));
67 if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CAP_FLAGS,
68 device->attrs.device_cap_flags, 0))
69 return -EMSGSIZE;
70
Leon Romanovsky8621a7e2017-06-27 16:58:59 +030071 ib_get_device_fw_str(device, fw);
72 /* Device without FW has strlen(fw) */
73 if (strlen(fw) && nla_put_string(msg, RDMA_NLDEV_ATTR_FW_VERSION, fw))
74 return -EMSGSIZE;
75
Leon Romanovsky1aaff892017-06-28 14:01:37 +030076 if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_NODE_GUID,
77 be64_to_cpu(device->node_guid), 0))
78 return -EMSGSIZE;
79 if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_SYS_IMAGE_GUID,
80 be64_to_cpu(device->attrs.sys_image_guid), 0))
81 return -EMSGSIZE;
Leon Romanovskyb4c598a2017-06-20 09:59:14 +030082 return 0;
83}
84
Leon Romanovsky7d02f602017-06-20 11:30:33 +030085static int fill_port_info(struct sk_buff *msg,
86 struct ib_device *device, u32 port)
87{
Leon Romanovskyac505252017-06-20 14:47:08 +030088 struct ib_port_attr attr;
89 int ret;
90
Leon Romanovsky7d02f602017-06-20 11:30:33 +030091 if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DEV_INDEX, device->index))
92 return -EMSGSIZE;
93 if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, device->name))
94 return -EMSGSIZE;
95 if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port))
96 return -EMSGSIZE;
Leon Romanovskyac505252017-06-20 14:47:08 +030097
98 ret = ib_query_port(device, port, &attr);
99 if (ret)
100 return ret;
101
102 BUILD_BUG_ON(sizeof(attr.port_cap_flags) > sizeof(u64));
103 if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CAP_FLAGS,
104 (u64)attr.port_cap_flags, 0))
105 return -EMSGSIZE;
Leon Romanovsky12026fb2017-06-28 15:05:14 +0300106 if (rdma_protocol_ib(device, port) &&
107 nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_SUBNET_PREFIX,
108 attr.subnet_prefix, 0))
109 return -EMSGSIZE;
Leon Romanovsky80a06dd2017-06-28 15:38:36 +0300110 if (rdma_protocol_ib(device, port)) {
111 if (nla_put_u32(msg, RDMA_NLDEV_ATTR_LID, attr.lid))
112 return -EMSGSIZE;
113 if (nla_put_u32(msg, RDMA_NLDEV_ATTR_SM_LID, attr.sm_lid))
114 return -EMSGSIZE;
Leon Romanovsky34840fe2017-06-28 15:49:30 +0300115 if (nla_put_u8(msg, RDMA_NLDEV_ATTR_LMC, attr.lmc))
116 return -EMSGSIZE;
Leon Romanovsky80a06dd2017-06-28 15:38:36 +0300117 }
Leon Romanovsky5654e492017-06-29 13:12:45 +0300118 if (nla_put_u8(msg, RDMA_NLDEV_ATTR_PORT_STATE, attr.state))
119 return -EMSGSIZE;
120 if (nla_put_u8(msg, RDMA_NLDEV_ATTR_PORT_PHYS_STATE, attr.phys_state))
121 return -EMSGSIZE;
Leon Romanovsky7d02f602017-06-20 11:30:33 +0300122 return 0;
123}
124
Leon Romanovskye5c94692017-06-15 20:33:08 +0300125static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
126 struct netlink_ext_ack *extack)
127{
128 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
129 struct ib_device *device;
130 struct sk_buff *msg;
131 u32 index;
132 int err;
133
134 err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
135 nldev_policy, extack);
136 if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
137 return -EINVAL;
138
139 index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
140
141 device = __ib_device_get_by_index(index);
142 if (!device)
143 return -EINVAL;
144
145 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
146 if (!msg)
147 return -ENOMEM;
148
149 nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
150 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
151 0, 0);
152
153 err = fill_dev_info(msg, device);
154 if (err) {
155 nlmsg_free(msg);
156 return err;
157 }
158
159 nlmsg_end(msg, nlh);
160
161 return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
162}
163
Leon Romanovskyb4c598a2017-06-20 09:59:14 +0300164static int _nldev_get_dumpit(struct ib_device *device,
165 struct sk_buff *skb,
166 struct netlink_callback *cb,
167 unsigned int idx)
168{
169 int start = cb->args[0];
170 struct nlmsghdr *nlh;
171
172 if (idx < start)
173 return 0;
174
175 nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
176 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
177 0, NLM_F_MULTI);
178
179 if (fill_dev_info(skb, device)) {
180 nlmsg_cancel(skb, nlh);
181 goto out;
182 }
183
184 nlmsg_end(skb, nlh);
185
186 idx++;
187
188out: cb->args[0] = idx;
189 return skb->len;
190}
191
192static int nldev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
193{
194 /*
195 * There is no need to take lock, because
196 * we are relying on ib_core's lists_rwsem
197 */
198 return ib_enum_all_devs(_nldev_get_dumpit, skb, cb);
199}
200
Leon Romanovskyc3f66f72017-06-22 16:10:38 +0300201static int nldev_port_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
202 struct netlink_ext_ack *extack)
203{
204 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
205 struct ib_device *device;
206 struct sk_buff *msg;
207 u32 index;
208 u32 port;
209 int err;
210
211 err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
212 nldev_policy, extack);
213 if (err || !tb[RDMA_NLDEV_ATTR_PORT_INDEX])
214 return -EINVAL;
215
216 index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
217 device = __ib_device_get_by_index(index);
218 if (!device)
219 return -EINVAL;
220
221 port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
222 if (!rdma_is_port_valid(device, port))
223 return -EINVAL;
224
225 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
226 if (!msg)
227 return -ENOMEM;
228
229 nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
230 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
231 0, 0);
232
233 err = fill_port_info(msg, device, port);
234 if (err) {
235 nlmsg_free(msg);
236 return err;
237 }
238
239 nlmsg_end(msg, nlh);
240
241 return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
242}
243
Leon Romanovsky7d02f602017-06-20 11:30:33 +0300244static int nldev_port_get_dumpit(struct sk_buff *skb,
245 struct netlink_callback *cb)
246{
247 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
248 struct ib_device *device;
249 int start = cb->args[0];
250 struct nlmsghdr *nlh;
251 u32 idx = 0;
252 u32 ifindex;
253 int err;
254 u32 p;
255
256 err = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
257 nldev_policy, NULL);
258 if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
259 return -EINVAL;
260
261 ifindex = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
262 device = __ib_device_get_by_index(ifindex);
263 if (!device)
264 return -EINVAL;
265
266 for (p = rdma_start_port(device); p <= rdma_end_port(device); ++p) {
267 /*
268 * The dumpit function returns all information from specific
269 * index. This specific index is taken from the netlink
270 * messages request sent by user and it is available
271 * in cb->args[0].
272 *
273 * Usually, the user doesn't fill this field and it causes
274 * to return everything.
275 *
276 */
277 if (idx < start) {
278 idx++;
279 continue;
280 }
281
282 nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid,
283 cb->nlh->nlmsg_seq,
284 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
285 RDMA_NLDEV_CMD_PORT_GET),
286 0, NLM_F_MULTI);
287
288 if (fill_port_info(skb, device, p)) {
289 nlmsg_cancel(skb, nlh);
290 goto out;
291 }
292 idx++;
293 nlmsg_end(skb, nlh);
294 }
295
296out: cb->args[0] = idx;
297 return skb->len;
298}
299
Leon Romanovskyb4c598a2017-06-20 09:59:14 +0300300static const struct rdma_nl_cbs nldev_cb_table[] = {
301 [RDMA_NLDEV_CMD_GET] = {
Leon Romanovskye5c94692017-06-15 20:33:08 +0300302 .doit = nldev_get_doit,
Leon Romanovskyb4c598a2017-06-20 09:59:14 +0300303 .dump = nldev_get_dumpit,
304 },
Leon Romanovsky7d02f602017-06-20 11:30:33 +0300305 [RDMA_NLDEV_CMD_PORT_GET] = {
Leon Romanovskyc3f66f72017-06-22 16:10:38 +0300306 .doit = nldev_port_get_doit,
Leon Romanovsky7d02f602017-06-20 11:30:33 +0300307 .dump = nldev_port_get_dumpit,
308 },
Leon Romanovskyb4c598a2017-06-20 09:59:14 +0300309};
310
Leon Romanovsky6c80b412017-06-20 09:14:15 +0300311void __init nldev_init(void)
312{
Leon Romanovskyb4c598a2017-06-20 09:59:14 +0300313 rdma_nl_register(RDMA_NL_NLDEV, nldev_cb_table);
Leon Romanovsky6c80b412017-06-20 09:14:15 +0300314}
315
316void __exit nldev_exit(void)
317{
318 rdma_nl_unregister(RDMA_NL_NLDEV);
319}