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