blob: cdc970ca5a1b741f2a3e27a667700c1c0da6293f [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 Romanovskyb4c598a2017-06-20 09:59:14 +030045};
46
47static int fill_dev_info(struct sk_buff *msg, struct ib_device *device)
48{
Leon Romanovsky8621a7e2017-06-27 16:58:59 +030049 char fw[IB_FW_VERSION_NAME_MAX];
50
Leon Romanovskyb4c598a2017-06-20 09:59:14 +030051 if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DEV_INDEX, device->index))
52 return -EMSGSIZE;
53 if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, device->name))
54 return -EMSGSIZE;
55 if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, rdma_end_port(device)))
56 return -EMSGSIZE;
Leon Romanovskyac505252017-06-20 14:47:08 +030057
58 BUILD_BUG_ON(sizeof(device->attrs.device_cap_flags) != sizeof(u64));
59 if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CAP_FLAGS,
60 device->attrs.device_cap_flags, 0))
61 return -EMSGSIZE;
62
Leon Romanovsky8621a7e2017-06-27 16:58:59 +030063 ib_get_device_fw_str(device, fw);
64 /* Device without FW has strlen(fw) */
65 if (strlen(fw) && nla_put_string(msg, RDMA_NLDEV_ATTR_FW_VERSION, fw))
66 return -EMSGSIZE;
67
Leon Romanovskyb4c598a2017-06-20 09:59:14 +030068 return 0;
69}
70
Leon Romanovsky7d02f602017-06-20 11:30:33 +030071static int fill_port_info(struct sk_buff *msg,
72 struct ib_device *device, u32 port)
73{
Leon Romanovskyac505252017-06-20 14:47:08 +030074 struct ib_port_attr attr;
75 int ret;
76
Leon Romanovsky7d02f602017-06-20 11:30:33 +030077 if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DEV_INDEX, device->index))
78 return -EMSGSIZE;
79 if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, device->name))
80 return -EMSGSIZE;
81 if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port))
82 return -EMSGSIZE;
Leon Romanovskyac505252017-06-20 14:47:08 +030083
84 ret = ib_query_port(device, port, &attr);
85 if (ret)
86 return ret;
87
88 BUILD_BUG_ON(sizeof(attr.port_cap_flags) > sizeof(u64));
89 if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CAP_FLAGS,
90 (u64)attr.port_cap_flags, 0))
91 return -EMSGSIZE;
92
Leon Romanovsky7d02f602017-06-20 11:30:33 +030093 return 0;
94}
95
Leon Romanovskye5c94692017-06-15 20:33:08 +030096static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
97 struct netlink_ext_ack *extack)
98{
99 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
100 struct ib_device *device;
101 struct sk_buff *msg;
102 u32 index;
103 int err;
104
105 err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
106 nldev_policy, extack);
107 if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
108 return -EINVAL;
109
110 index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
111
112 device = __ib_device_get_by_index(index);
113 if (!device)
114 return -EINVAL;
115
116 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
117 if (!msg)
118 return -ENOMEM;
119
120 nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
121 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
122 0, 0);
123
124 err = fill_dev_info(msg, device);
125 if (err) {
126 nlmsg_free(msg);
127 return err;
128 }
129
130 nlmsg_end(msg, nlh);
131
132 return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
133}
134
Leon Romanovskyb4c598a2017-06-20 09:59:14 +0300135static int _nldev_get_dumpit(struct ib_device *device,
136 struct sk_buff *skb,
137 struct netlink_callback *cb,
138 unsigned int idx)
139{
140 int start = cb->args[0];
141 struct nlmsghdr *nlh;
142
143 if (idx < start)
144 return 0;
145
146 nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
147 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
148 0, NLM_F_MULTI);
149
150 if (fill_dev_info(skb, device)) {
151 nlmsg_cancel(skb, nlh);
152 goto out;
153 }
154
155 nlmsg_end(skb, nlh);
156
157 idx++;
158
159out: cb->args[0] = idx;
160 return skb->len;
161}
162
163static int nldev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
164{
165 /*
166 * There is no need to take lock, because
167 * we are relying on ib_core's lists_rwsem
168 */
169 return ib_enum_all_devs(_nldev_get_dumpit, skb, cb);
170}
171
Leon Romanovskyc3f66f72017-06-22 16:10:38 +0300172static int nldev_port_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
173 struct netlink_ext_ack *extack)
174{
175 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
176 struct ib_device *device;
177 struct sk_buff *msg;
178 u32 index;
179 u32 port;
180 int err;
181
182 err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
183 nldev_policy, extack);
184 if (err || !tb[RDMA_NLDEV_ATTR_PORT_INDEX])
185 return -EINVAL;
186
187 index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
188 device = __ib_device_get_by_index(index);
189 if (!device)
190 return -EINVAL;
191
192 port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
193 if (!rdma_is_port_valid(device, port))
194 return -EINVAL;
195
196 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
197 if (!msg)
198 return -ENOMEM;
199
200 nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
201 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
202 0, 0);
203
204 err = fill_port_info(msg, device, port);
205 if (err) {
206 nlmsg_free(msg);
207 return err;
208 }
209
210 nlmsg_end(msg, nlh);
211
212 return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
213}
214
Leon Romanovsky7d02f602017-06-20 11:30:33 +0300215static int nldev_port_get_dumpit(struct sk_buff *skb,
216 struct netlink_callback *cb)
217{
218 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
219 struct ib_device *device;
220 int start = cb->args[0];
221 struct nlmsghdr *nlh;
222 u32 idx = 0;
223 u32 ifindex;
224 int err;
225 u32 p;
226
227 err = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
228 nldev_policy, NULL);
229 if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
230 return -EINVAL;
231
232 ifindex = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
233 device = __ib_device_get_by_index(ifindex);
234 if (!device)
235 return -EINVAL;
236
237 for (p = rdma_start_port(device); p <= rdma_end_port(device); ++p) {
238 /*
239 * The dumpit function returns all information from specific
240 * index. This specific index is taken from the netlink
241 * messages request sent by user and it is available
242 * in cb->args[0].
243 *
244 * Usually, the user doesn't fill this field and it causes
245 * to return everything.
246 *
247 */
248 if (idx < start) {
249 idx++;
250 continue;
251 }
252
253 nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid,
254 cb->nlh->nlmsg_seq,
255 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
256 RDMA_NLDEV_CMD_PORT_GET),
257 0, NLM_F_MULTI);
258
259 if (fill_port_info(skb, device, p)) {
260 nlmsg_cancel(skb, nlh);
261 goto out;
262 }
263 idx++;
264 nlmsg_end(skb, nlh);
265 }
266
267out: cb->args[0] = idx;
268 return skb->len;
269}
270
Leon Romanovskyb4c598a2017-06-20 09:59:14 +0300271static const struct rdma_nl_cbs nldev_cb_table[] = {
272 [RDMA_NLDEV_CMD_GET] = {
Leon Romanovskye5c94692017-06-15 20:33:08 +0300273 .doit = nldev_get_doit,
Leon Romanovskyb4c598a2017-06-20 09:59:14 +0300274 .dump = nldev_get_dumpit,
275 },
Leon Romanovsky7d02f602017-06-20 11:30:33 +0300276 [RDMA_NLDEV_CMD_PORT_GET] = {
Leon Romanovskyc3f66f72017-06-22 16:10:38 +0300277 .doit = nldev_port_get_doit,
Leon Romanovsky7d02f602017-06-20 11:30:33 +0300278 .dump = nldev_port_get_dumpit,
279 },
Leon Romanovskyb4c598a2017-06-20 09:59:14 +0300280};
281
Leon Romanovsky6c80b412017-06-20 09:14:15 +0300282void __init nldev_init(void)
283{
Leon Romanovskyb4c598a2017-06-20 09:59:14 +0300284 rdma_nl_register(RDMA_NL_NLDEV, nldev_cb_table);
Leon Romanovsky6c80b412017-06-20 09:14:15 +0300285}
286
287void __exit nldev_exit(void)
288{
289 rdma_nl_unregister(RDMA_NL_NLDEV);
290}