aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTatyana Nikolova <Tatyana.E.Nikolova@intel.com>2014-03-26 18:07:35 -0400
committerRoland Dreier <roland@purestorage.com>2014-06-10 13:11:45 -0400
commit30dc5e63d6a5ad24894b5512d10b228d73645a44 (patch)
treecbb54ab8d06b165dbbd83a243cf743c8b6ad64da
parentd6d211db37e75de2ddc3a4f979038c40df7cc79c (diff)
RDMA/core: Add support for iWARP Port Mapper user space service
This patch adds iWARP Port Mapper (IWPM) Version 2 support. The iWARP Port Mapper implementation is based on the port mapper specification section in the Sockets Direct Protocol paper - http://www.rdmaconsortium.org/home/draft-pinkerton-iwarp-sdp-v1.0.pdf Existing iWARP RDMA providers use the same IP address as the native TCP/IP stack when creating RDMA connections. They need a mechanism to claim the TCP ports used for RDMA connections to prevent TCP port collisions when other host applications use TCP ports. The iWARP Port Mapper provides a standard mechanism to accomplish this. Without this service it is possible for RDMA application to bind/listen on the same port which is already being used by native TCP host application. If that happens the incoming TCP connection data can be passed to the RDMA stack with error. The iWARP Port Mapper solution doesn't contain any changes to the existing network stack in the kernel space. All the changes are contained with the infiniband tree and also in user space. The iWARP Port Mapper service is implemented as a user space daemon process. Source for the IWPM service is located at http://git.openfabrics.org/git?p=~tnikolova/libiwpm-1.0.0/.git;a=summary The iWARP driver (port mapper client) sends to the IWPM service the local IP address and TCP port it has received from the RDMA application, when starting a connection. The IWPM service performs a socket bind from user space to get an available TCP port, called a mapped port, and communicates it back to the client. In that sense, the IWPM service is used to map the TCP port, which the RDMA application uses to any port available from the host TCP port space. The mapped ports are used in iWARP RDMA connections to avoid collisions with native TCP stack which is aware that these ports are taken. When an RDMA connection using a mapped port is terminated, the client notifies the IWPM service, which then releases the TCP port. The message exchange between the IWPM service and the iWARP drivers (between user space and kernel space) is implemented using netlink sockets. 1) Netlink interface functions are added: ibnl_unicast() and ibnl_mulitcast() for sending netlink messages to user space 2) The signature of the existing ibnl_put_msg() is changed to be more generic 3) Two netlink clients are added: RDMA_NL_NES, RDMA_NL_C4IW corresponding to the two iWarp drivers - nes and cxgb4 which use the IWPM service 4) Enums are added to enumerate the attributes in the netlink messages, which are exchanged between the user space IWPM service and the iWARP drivers Signed-off-by: Tatyana Nikolova <tatyana.e.nikolova@intel.com> Signed-off-by: Steve Wise <swise@opengridcomputing.com> Reviewed-by: PJ Waskiewicz <pj.waskiewicz@solidfire.com> [ Fold in range checking fixes and nlh_next removal as suggested by Dan Carpenter and Steve Wise. Fix sparse endianness in hash. - Roland ] Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r--drivers/infiniband/core/Makefile2
-rw-r--r--drivers/infiniband/core/cma.c3
-rw-r--r--drivers/infiniband/core/iwpm_msg.c685
-rw-r--r--drivers/infiniband/core/iwpm_util.c607
-rw-r--r--drivers/infiniband/core/iwpm_util.h238
-rw-r--r--drivers/infiniband/core/netlink.c18
-rw-r--r--include/rdma/iw_portmap.h199
-rw-r--r--include/rdma/rdma_netlink.h23
-rw-r--r--include/uapi/rdma/rdma_netlink.h96
9 files changed, 1865 insertions, 6 deletions
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index 3ab3865544bb..ffd0af6734af 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -18,7 +18,7 @@ ib_sa-y := sa_query.o multicast.o
18 18
19ib_cm-y := cm.o 19ib_cm-y := cm.o
20 20
21iw_cm-y := iwcm.o 21iw_cm-y := iwcm.o iwpm_util.o iwpm_msg.o
22 22
23rdma_cm-y := cma.o 23rdma_cm-y := cma.o
24 24
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 42c3058e6e9c..d570030d899c 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -3607,7 +3607,8 @@ static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb)
3607 3607
3608 id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq, 3608 id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq,
3609 sizeof *id_stats, RDMA_NL_RDMA_CM, 3609 sizeof *id_stats, RDMA_NL_RDMA_CM,
3610 RDMA_NL_RDMA_CM_ID_STATS); 3610 RDMA_NL_RDMA_CM_ID_STATS,
3611 NLM_F_MULTI);
3611 if (!id_stats) 3612 if (!id_stats)
3612 goto out; 3613 goto out;
3613 3614
diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c
new file mode 100644
index 000000000000..b85ddbc979e0
--- /dev/null
+++ b/drivers/infiniband/core/iwpm_msg.c
@@ -0,0 +1,685 @@
1/*
2 * Copyright (c) 2014 Intel Corporation. All rights reserved.
3 * Copyright (c) 2014 Chelsio, Inc. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 *
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
18 *
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 */
33
34#include "iwpm_util.h"
35
36static const char iwpm_ulib_name[] = "iWarpPortMapperUser";
37static int iwpm_ulib_version = 3;
38static int iwpm_user_pid = IWPM_PID_UNDEFINED;
39static atomic_t echo_nlmsg_seq;
40
41int iwpm_valid_pid(void)
42{
43 return iwpm_user_pid > 0;
44}
45EXPORT_SYMBOL(iwpm_valid_pid);
46
47/*
48 * iwpm_register_pid - Send a netlink query to user space
49 * for the iwarp port mapper pid
50 *
51 * nlmsg attributes:
52 * [IWPM_NLA_REG_PID_SEQ]
53 * [IWPM_NLA_REG_IF_NAME]
54 * [IWPM_NLA_REG_IBDEV_NAME]
55 * [IWPM_NLA_REG_ULIB_NAME]
56 */
57int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
58{
59 struct sk_buff *skb = NULL;
60 struct iwpm_nlmsg_request *nlmsg_request = NULL;
61 struct nlmsghdr *nlh;
62 u32 msg_seq;
63 const char *err_str = "";
64 int ret = -EINVAL;
65
66 if (!iwpm_valid_client(nl_client)) {
67 err_str = "Invalid port mapper client";
68 goto pid_query_error;
69 }
70 if (iwpm_registered_client(nl_client))
71 return 0;
72 skb = iwpm_create_nlmsg(RDMA_NL_IWPM_REG_PID, &nlh, nl_client);
73 if (!skb) {
74 err_str = "Unable to create a nlmsg";
75 goto pid_query_error;
76 }
77 nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
78 nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq, nl_client, GFP_KERNEL);
79 if (!nlmsg_request) {
80 err_str = "Unable to allocate netlink request";
81 goto pid_query_error;
82 }
83 msg_seq = atomic_read(&echo_nlmsg_seq);
84
85 /* fill in the pid request message */
86 err_str = "Unable to put attribute of the nlmsg";
87 ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_REG_PID_SEQ);
88 if (ret)
89 goto pid_query_error;
90 ret = ibnl_put_attr(skb, nlh, IWPM_IFNAME_SIZE,
91 pm_msg->if_name, IWPM_NLA_REG_IF_NAME);
92 if (ret)
93 goto pid_query_error;
94 ret = ibnl_put_attr(skb, nlh, IWPM_DEVNAME_SIZE,
95 pm_msg->dev_name, IWPM_NLA_REG_IBDEV_NAME);
96 if (ret)
97 goto pid_query_error;
98 ret = ibnl_put_attr(skb, nlh, IWPM_ULIBNAME_SIZE,
99 (char *)iwpm_ulib_name, IWPM_NLA_REG_ULIB_NAME);
100 if (ret)
101 goto pid_query_error;
102
103 pr_debug("%s: Multicasting a nlmsg (dev = %s ifname = %s iwpm = %s)\n",
104 __func__, pm_msg->dev_name, pm_msg->if_name, iwpm_ulib_name);
105
106 ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_IWPM, GFP_KERNEL);
107 if (ret) {
108 skb = NULL; /* skb is freed in the netlink send-op handling */
109 iwpm_set_registered(nl_client, 1);
110 iwpm_user_pid = IWPM_PID_UNAVAILABLE;
111 err_str = "Unable to send a nlmsg";
112 goto pid_query_error;
113 }
114 nlmsg_request->req_buffer = pm_msg;
115 ret = iwpm_wait_complete_req(nlmsg_request);
116 return ret;
117pid_query_error:
118 pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
119 if (skb)
120 dev_kfree_skb(skb);
121 if (nlmsg_request)
122 iwpm_free_nlmsg_request(&nlmsg_request->kref);
123 return ret;
124}
125EXPORT_SYMBOL(iwpm_register_pid);
126
127/*
128 * iwpm_add_mapping - Send a netlink add mapping message
129 * to the port mapper
130 * nlmsg attributes:
131 * [IWPM_NLA_MANAGE_MAPPING_SEQ]
132 * [IWPM_NLA_MANAGE_ADDR]
133 */
134int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
135{
136 struct sk_buff *skb = NULL;
137 struct iwpm_nlmsg_request *nlmsg_request = NULL;
138 struct nlmsghdr *nlh;
139 u32 msg_seq;
140 const char *err_str = "";
141 int ret = -EINVAL;
142
143 if (!iwpm_valid_client(nl_client)) {
144 err_str = "Invalid port mapper client";
145 goto add_mapping_error;
146 }
147 if (!iwpm_registered_client(nl_client)) {
148 err_str = "Unregistered port mapper client";
149 goto add_mapping_error;
150 }
151 if (!iwpm_valid_pid())
152 return 0;
153 skb = iwpm_create_nlmsg(RDMA_NL_IWPM_ADD_MAPPING, &nlh, nl_client);
154 if (!skb) {
155 err_str = "Unable to create a nlmsg";
156 goto add_mapping_error;
157 }
158 nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
159 nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq, nl_client, GFP_KERNEL);
160 if (!nlmsg_request) {
161 err_str = "Unable to allocate netlink request";
162 goto add_mapping_error;
163 }
164 msg_seq = atomic_read(&echo_nlmsg_seq);
165 /* fill in the add mapping message */
166 err_str = "Unable to put attribute of the nlmsg";
167 ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
168 IWPM_NLA_MANAGE_MAPPING_SEQ);
169 if (ret)
170 goto add_mapping_error;
171 ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
172 &pm_msg->loc_addr, IWPM_NLA_MANAGE_ADDR);
173 if (ret)
174 goto add_mapping_error;
175 nlmsg_request->req_buffer = pm_msg;
176
177 ret = ibnl_unicast(skb, nlh, iwpm_user_pid);
178 if (ret) {
179 skb = NULL; /* skb is freed in the netlink send-op handling */
180 iwpm_user_pid = IWPM_PID_UNDEFINED;
181 err_str = "Unable to send a nlmsg";
182 goto add_mapping_error;
183 }
184 ret = iwpm_wait_complete_req(nlmsg_request);
185 return ret;
186add_mapping_error:
187 pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
188 if (skb)
189 dev_kfree_skb(skb);
190 if (nlmsg_request)
191 iwpm_free_nlmsg_request(&nlmsg_request->kref);
192 return ret;
193}
194EXPORT_SYMBOL(iwpm_add_mapping);
195
196/*
197 * iwpm_add_and_query_mapping - Send a netlink add and query
198 * mapping message to the port mapper
199 * nlmsg attributes:
200 * [IWPM_NLA_QUERY_MAPPING_SEQ]
201 * [IWPM_NLA_QUERY_LOCAL_ADDR]
202 * [IWPM_NLA_QUERY_REMOTE_ADDR]
203 */
204int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
205{
206 struct sk_buff *skb = NULL;
207 struct iwpm_nlmsg_request *nlmsg_request = NULL;
208 struct nlmsghdr *nlh;
209 u32 msg_seq;
210 const char *err_str = "";
211 int ret = -EINVAL;
212
213 if (!iwpm_valid_client(nl_client)) {
214 err_str = "Invalid port mapper client";
215 goto query_mapping_error;
216 }
217 if (!iwpm_registered_client(nl_client)) {
218 err_str = "Unregistered port mapper client";
219 goto query_mapping_error;
220 }
221 if (!iwpm_valid_pid())
222 return 0;
223 ret = -ENOMEM;
224 skb = iwpm_create_nlmsg(RDMA_NL_IWPM_QUERY_MAPPING, &nlh, nl_client);
225 if (!skb) {
226 err_str = "Unable to create a nlmsg";
227 goto query_mapping_error;
228 }
229 nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
230 nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq,
231 nl_client, GFP_KERNEL);
232 if (!nlmsg_request) {
233 err_str = "Unable to allocate netlink request";
234 goto query_mapping_error;
235 }
236 msg_seq = atomic_read(&echo_nlmsg_seq);
237
238 /* fill in the query message */
239 err_str = "Unable to put attribute of the nlmsg";
240 ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
241 IWPM_NLA_QUERY_MAPPING_SEQ);
242 if (ret)
243 goto query_mapping_error;
244 ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
245 &pm_msg->loc_addr, IWPM_NLA_QUERY_LOCAL_ADDR);
246 if (ret)
247 goto query_mapping_error;
248 ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
249 &pm_msg->rem_addr, IWPM_NLA_QUERY_REMOTE_ADDR);
250 if (ret)
251 goto query_mapping_error;
252 nlmsg_request->req_buffer = pm_msg;
253
254 ret = ibnl_unicast(skb, nlh, iwpm_user_pid);
255 if (ret) {
256 skb = NULL; /* skb is freed in the netlink send-op handling */
257 err_str = "Unable to send a nlmsg";
258 goto query_mapping_error;
259 }
260 ret = iwpm_wait_complete_req(nlmsg_request);
261 return ret;
262query_mapping_error:
263 pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
264 if (skb)
265 dev_kfree_skb(skb);
266 if (nlmsg_request)
267 iwpm_free_nlmsg_request(&nlmsg_request->kref);
268 return ret;
269}
270EXPORT_SYMBOL(iwpm_add_and_query_mapping);
271
272/*
273 * iwpm_remove_mapping - Send a netlink remove mapping message
274 * to the port mapper
275 * nlmsg attributes:
276 * [IWPM_NLA_MANAGE_MAPPING_SEQ]
277 * [IWPM_NLA_MANAGE_ADDR]
278 */
279int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client)
280{
281 struct sk_buff *skb = NULL;
282 struct nlmsghdr *nlh;
283 u32 msg_seq;
284 const char *err_str = "";
285 int ret = -EINVAL;
286
287 if (!iwpm_valid_client(nl_client)) {
288 err_str = "Invalid port mapper client";
289 goto remove_mapping_error;
290 }
291 if (!iwpm_registered_client(nl_client)) {
292 err_str = "Unregistered port mapper client";
293 goto remove_mapping_error;
294 }
295 if (!iwpm_valid_pid())
296 return 0;
297 skb = iwpm_create_nlmsg(RDMA_NL_IWPM_REMOVE_MAPPING, &nlh, nl_client);
298 if (!skb) {
299 ret = -ENOMEM;
300 err_str = "Unable to create a nlmsg";
301 goto remove_mapping_error;
302 }
303 msg_seq = atomic_read(&echo_nlmsg_seq);
304 nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
305 err_str = "Unable to put attribute of the nlmsg";
306 ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
307 IWPM_NLA_MANAGE_MAPPING_SEQ);
308 if (ret)
309 goto remove_mapping_error;
310 ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
311 local_addr, IWPM_NLA_MANAGE_ADDR);
312 if (ret)
313 goto remove_mapping_error;
314
315 ret = ibnl_unicast(skb, nlh, iwpm_user_pid);
316 if (ret) {
317 skb = NULL; /* skb is freed in the netlink send-op handling */
318 iwpm_user_pid = IWPM_PID_UNDEFINED;
319 err_str = "Unable to send a nlmsg";
320 goto remove_mapping_error;
321 }
322 iwpm_print_sockaddr(local_addr,
323 "remove_mapping: Local sockaddr:");
324 return 0;
325remove_mapping_error:
326 pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
327 if (skb)
328 dev_kfree_skb_any(skb);
329 return ret;
330}
331EXPORT_SYMBOL(iwpm_remove_mapping);
332
333/* netlink attribute policy for the received response to register pid request */
334static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = {
335 [IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 },
336 [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING,
337 .len = IWPM_DEVNAME_SIZE - 1 },
338 [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING,
339 .len = IWPM_ULIBNAME_SIZE - 1 },
340 [IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 },
341 [IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 }
342};
343
344/*
345 * iwpm_register_pid_cb - Process a port mapper response to
346 * iwpm_register_pid()
347 */
348int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
349{
350 struct iwpm_nlmsg_request *nlmsg_request = NULL;
351 struct nlattr *nltb[IWPM_NLA_RREG_PID_MAX];
352 struct iwpm_dev_data *pm_msg;
353 char *dev_name, *iwpm_name;
354 u32 msg_seq;
355 u8 nl_client;
356 u16 iwpm_version;
357 const char *msg_type = "Register Pid response";
358
359 if (iwpm_parse_nlmsg(cb, IWPM_NLA_RREG_PID_MAX,
360 resp_reg_policy, nltb, msg_type))
361 return -EINVAL;
362
363 msg_seq = nla_get_u32(nltb[IWPM_NLA_RREG_PID_SEQ]);
364 nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
365 if (!nlmsg_request) {
366 pr_info("%s: Could not find a matching request (seq = %u)\n",
367 __func__, msg_seq);
368 return -EINVAL;
369 }
370 pm_msg = nlmsg_request->req_buffer;
371 nl_client = nlmsg_request->nl_client;
372 dev_name = (char *)nla_data(nltb[IWPM_NLA_RREG_IBDEV_NAME]);
373 iwpm_name = (char *)nla_data(nltb[IWPM_NLA_RREG_ULIB_NAME]);
374 iwpm_version = nla_get_u16(nltb[IWPM_NLA_RREG_ULIB_VER]);
375
376 /* check device name, ulib name and version */
377 if (strcmp(pm_msg->dev_name, dev_name) ||
378 strcmp(iwpm_ulib_name, iwpm_name) ||
379 iwpm_version != iwpm_ulib_version) {
380
381 pr_info("%s: Incorrect info (dev = %s name = %s version = %d)\n",
382 __func__, dev_name, iwpm_name, iwpm_version);
383 nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
384 goto register_pid_response_exit;
385 }
386 iwpm_user_pid = cb->nlh->nlmsg_pid;
387 atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
388 pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
389 __func__, iwpm_user_pid);
390 if (iwpm_valid_client(nl_client))
391 iwpm_set_registered(nl_client, 1);
392register_pid_response_exit:
393 nlmsg_request->request_done = 1;
394 /* always for found nlmsg_request */
395 kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
396 barrier();
397 wake_up(&nlmsg_request->waitq);
398 return 0;
399}
400EXPORT_SYMBOL(iwpm_register_pid_cb);
401
402/* netlink attribute policy for the received response to add mapping request */
403static const struct nla_policy resp_add_policy[IWPM_NLA_RMANAGE_MAPPING_MAX] = {
404 [IWPM_NLA_MANAGE_MAPPING_SEQ] = { .type = NLA_U32 },
405 [IWPM_NLA_MANAGE_ADDR] = { .len = sizeof(struct sockaddr_storage) },
406 [IWPM_NLA_MANAGE_MAPPED_LOC_ADDR] = { .len = sizeof(struct sockaddr_storage) },
407 [IWPM_NLA_RMANAGE_MAPPING_ERR] = { .type = NLA_U16 }
408};
409
410/*
411 * iwpm_add_mapping_cb - Process a port mapper response to
412 * iwpm_add_mapping()
413 */
414int iwpm_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb)
415{
416 struct iwpm_sa_data *pm_msg;
417 struct iwpm_nlmsg_request *nlmsg_request = NULL;
418 struct nlattr *nltb[IWPM_NLA_RMANAGE_MAPPING_MAX];
419 struct sockaddr_storage *local_sockaddr;
420 struct sockaddr_storage *mapped_sockaddr;
421 const char *msg_type;
422 u32 msg_seq;
423
424 msg_type = "Add Mapping response";
425 if (iwpm_parse_nlmsg(cb, IWPM_NLA_RMANAGE_MAPPING_MAX,
426 resp_add_policy, nltb, msg_type))
427 return -EINVAL;
428
429 atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
430
431 msg_seq = nla_get_u32(nltb[IWPM_NLA_MANAGE_MAPPING_SEQ]);
432 nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
433 if (!nlmsg_request) {
434 pr_info("%s: Could not find a matching request (seq = %u)\n",
435 __func__, msg_seq);
436 return -EINVAL;
437 }
438 pm_msg = nlmsg_request->req_buffer;
439 local_sockaddr = (struct sockaddr_storage *)
440 nla_data(nltb[IWPM_NLA_MANAGE_ADDR]);
441 mapped_sockaddr = (struct sockaddr_storage *)
442 nla_data(nltb[IWPM_NLA_MANAGE_MAPPED_LOC_ADDR]);
443
444 if (iwpm_compare_sockaddr(local_sockaddr, &pm_msg->loc_addr)) {
445 nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
446 goto add_mapping_response_exit;
447 }
448 if (mapped_sockaddr->ss_family != local_sockaddr->ss_family) {
449 pr_info("%s: Sockaddr family doesn't match the requested one\n",
450 __func__);
451 nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
452 goto add_mapping_response_exit;
453 }
454 memcpy(&pm_msg->mapped_loc_addr, mapped_sockaddr,
455 sizeof(*mapped_sockaddr));
456 iwpm_print_sockaddr(&pm_msg->loc_addr,
457 "add_mapping: Local sockaddr:");
458 iwpm_print_sockaddr(&pm_msg->mapped_loc_addr,
459 "add_mapping: Mapped local sockaddr:");
460
461add_mapping_response_exit:
462 nlmsg_request->request_done = 1;
463 /* always for found request */
464 kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
465 barrier();
466 wake_up(&nlmsg_request->waitq);
467 return 0;
468}
469EXPORT_SYMBOL(iwpm_add_mapping_cb);
470
471/* netlink attribute policy for the response to add and query mapping request */
472static const struct nla_policy resp_query_policy[IWPM_NLA_RQUERY_MAPPING_MAX] = {
473 [IWPM_NLA_QUERY_MAPPING_SEQ] = { .type = NLA_U32 },
474 [IWPM_NLA_QUERY_LOCAL_ADDR] = { .len = sizeof(struct sockaddr_storage) },
475 [IWPM_NLA_QUERY_REMOTE_ADDR] = { .len = sizeof(struct sockaddr_storage) },
476 [IWPM_NLA_RQUERY_MAPPED_LOC_ADDR] = { .len = sizeof(struct sockaddr_storage) },
477 [IWPM_NLA_RQUERY_MAPPED_REM_ADDR] = { .len = sizeof(struct sockaddr_storage) },
478 [IWPM_NLA_RQUERY_MAPPING_ERR] = { .type = NLA_U16 }
479};
480
481/*
482 * iwpm_add_and_query_mapping_cb - Process a port mapper response to
483 * iwpm_add_and_query_mapping()
484 */
485int iwpm_add_and_query_mapping_cb(struct sk_buff *skb,
486 struct netlink_callback *cb)
487{
488 struct iwpm_sa_data *pm_msg;
489 struct iwpm_nlmsg_request *nlmsg_request = NULL;
490 struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX];
491 struct sockaddr_storage *local_sockaddr, *remote_sockaddr;
492 struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr;
493 const char *msg_type;
494 u32 msg_seq;
495 u16 err_code;
496
497 msg_type = "Query Mapping response";
498 if (iwpm_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX,
499 resp_query_policy, nltb, msg_type))
500 return -EINVAL;
501 atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
502
503 msg_seq = nla_get_u32(nltb[IWPM_NLA_QUERY_MAPPING_SEQ]);
504 nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
505 if (!nlmsg_request) {
506 pr_info("%s: Could not find a matching request (seq = %u)\n",
507 __func__, msg_seq);
508 return -EINVAL;
509 }
510 pm_msg = nlmsg_request->req_buffer;
511 local_sockaddr = (struct sockaddr_storage *)
512 nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]);
513 remote_sockaddr = (struct sockaddr_storage *)
514 nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]);
515 mapped_loc_sockaddr = (struct sockaddr_storage *)
516 nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]);
517 mapped_rem_sockaddr = (struct sockaddr_storage *)
518 nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]);
519
520 err_code = nla_get_u16(nltb[IWPM_NLA_RQUERY_MAPPING_ERR]);
521 if (err_code == IWPM_REMOTE_QUERY_REJECT) {
522 pr_info("%s: Received a Reject (pid = %u, echo seq = %u)\n",
523 __func__, cb->nlh->nlmsg_pid, msg_seq);
524 nlmsg_request->err_code = IWPM_REMOTE_QUERY_REJECT;
525 }
526 if (iwpm_compare_sockaddr(local_sockaddr, &pm_msg->loc_addr) ||
527 iwpm_compare_sockaddr(remote_sockaddr, &pm_msg->rem_addr)) {
528 pr_info("%s: Incorrect local sockaddr\n", __func__);
529 nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
530 goto query_mapping_response_exit;
531 }
532 if (mapped_loc_sockaddr->ss_family != local_sockaddr->ss_family ||
533 mapped_rem_sockaddr->ss_family != remote_sockaddr->ss_family) {
534 pr_info("%s: Sockaddr family doesn't match the requested one\n",
535 __func__);
536 nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
537 goto query_mapping_response_exit;
538 }
539 memcpy(&pm_msg->mapped_loc_addr, mapped_loc_sockaddr,
540 sizeof(*mapped_loc_sockaddr));
541 memcpy(&pm_msg->mapped_rem_addr, mapped_rem_sockaddr,
542 sizeof(*mapped_rem_sockaddr));
543
544 iwpm_print_sockaddr(&pm_msg->loc_addr,
545 "query_mapping: Local sockaddr:");
546 iwpm_print_sockaddr(&pm_msg->mapped_loc_addr,
547 "query_mapping: Mapped local sockaddr:");
548 iwpm_print_sockaddr(&pm_msg->rem_addr,
549 "query_mapping: Remote sockaddr:");
550 iwpm_print_sockaddr(&pm_msg->mapped_rem_addr,
551 "query_mapping: Mapped remote sockaddr:");
552query_mapping_response_exit:
553 nlmsg_request->request_done = 1;
554 /* always for found request */
555 kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
556 barrier();
557 wake_up(&nlmsg_request->waitq);
558 return 0;
559}
560EXPORT_SYMBOL(iwpm_add_and_query_mapping_cb);
561
562/* netlink attribute policy for the received request for mapping info */
563static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = {
564 [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING,
565 .len = IWPM_ULIBNAME_SIZE - 1 },
566 [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 }
567};
568
569/*
570 * iwpm_mapping_info_cb - Process a port mapper request for mapping info
571 */
572int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
573{
574 struct nlattr *nltb[IWPM_NLA_MAPINFO_REQ_MAX];
575 const char *msg_type = "Mapping Info response";
576 int iwpm_pid;
577 u8 nl_client;
578 char *iwpm_name;
579 u16 iwpm_version;
580 int ret = -EINVAL;
581
582 if (iwpm_parse_nlmsg(cb, IWPM_NLA_MAPINFO_REQ_MAX,
583 resp_mapinfo_policy, nltb, msg_type)) {
584 pr_info("%s: Unable to parse nlmsg\n", __func__);
585 return ret;
586 }
587 iwpm_name = (char *)nla_data(nltb[IWPM_NLA_MAPINFO_ULIB_NAME]);
588 iwpm_version = nla_get_u16(nltb[IWPM_NLA_MAPINFO_ULIB_VER]);
589 if (strcmp(iwpm_ulib_name, iwpm_name) ||
590 iwpm_version != iwpm_ulib_version) {
591 pr_info("%s: Invalid port mapper name = %s version = %d\n",
592 __func__, iwpm_name, iwpm_version);
593 return ret;
594 }
595 nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
596 if (!iwpm_valid_client(nl_client)) {
597 pr_info("%s: Invalid port mapper client = %d\n",
598 __func__, nl_client);
599 return ret;
600 }
601 iwpm_set_registered(nl_client, 0);
602 atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
603 if (!iwpm_mapinfo_available())
604 return 0;
605 iwpm_pid = cb->nlh->nlmsg_pid;
606 pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
607 __func__, iwpm_pid);
608 ret = iwpm_send_mapinfo(nl_client, iwpm_pid);
609 return ret;
610}
611EXPORT_SYMBOL(iwpm_mapping_info_cb);
612
613/* netlink attribute policy for the received mapping info ack */
614static const struct nla_policy ack_mapinfo_policy[IWPM_NLA_MAPINFO_NUM_MAX] = {
615 [IWPM_NLA_MAPINFO_SEQ] = { .type = NLA_U32 },
616 [IWPM_NLA_MAPINFO_SEND_NUM] = { .type = NLA_U32 },
617 [IWPM_NLA_MAPINFO_ACK_NUM] = { .type = NLA_U32 }
618};
619
620/*
621 * iwpm_ack_mapping_info_cb - Process a port mapper ack for
622 * the provided mapping info records
623 */
624int iwpm_ack_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
625{
626 struct nlattr *nltb[IWPM_NLA_MAPINFO_NUM_MAX];
627 u32 mapinfo_send, mapinfo_ack;
628 const char *msg_type = "Mapping Info Ack";
629
630 if (iwpm_parse_nlmsg(cb, IWPM_NLA_MAPINFO_NUM_MAX,
631 ack_mapinfo_policy, nltb, msg_type))
632 return -EINVAL;
633 mapinfo_send = nla_get_u32(nltb[IWPM_NLA_MAPINFO_SEND_NUM]);
634 mapinfo_ack = nla_get_u32(nltb[IWPM_NLA_MAPINFO_ACK_NUM]);
635 if (mapinfo_ack != mapinfo_send)
636 pr_info("%s: Invalid mapinfo number (sent = %u ack-ed = %u)\n",
637 __func__, mapinfo_send, mapinfo_ack);
638 atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
639 return 0;
640}
641EXPORT_SYMBOL(iwpm_ack_mapping_info_cb);
642
643/* netlink attribute policy for the received port mapper error message */
644static const struct nla_policy map_error_policy[IWPM_NLA_ERR_MAX] = {
645 [IWPM_NLA_ERR_SEQ] = { .type = NLA_U32 },
646 [IWPM_NLA_ERR_CODE] = { .type = NLA_U16 },
647};
648
649/*
650 * iwpm_mapping_error_cb - Process a port mapper error message
651 */
652int iwpm_mapping_error_cb(struct sk_buff *skb, struct netlink_callback *cb)
653{
654 struct iwpm_nlmsg_request *nlmsg_request = NULL;
655 int nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
656 struct nlattr *nltb[IWPM_NLA_ERR_MAX];
657 u32 msg_seq;
658 u16 err_code;
659 const char *msg_type = "Mapping Error Msg";
660
661 if (iwpm_parse_nlmsg(cb, IWPM_NLA_ERR_MAX,
662 map_error_policy, nltb, msg_type))
663 return -EINVAL;
664
665 msg_seq = nla_get_u32(nltb[IWPM_NLA_ERR_SEQ]);
666 err_code = nla_get_u16(nltb[IWPM_NLA_ERR_CODE]);
667 pr_info("%s: Received msg seq = %u err code = %u client = %d\n",
668 __func__, msg_seq, err_code, nl_client);
669 /* look for nlmsg_request */
670 nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
671 if (!nlmsg_request) {
672 /* not all errors have associated requests */
673 pr_debug("Could not find matching req (seq = %u)\n", msg_seq);
674 return 0;
675 }
676 atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
677 nlmsg_request->err_code = err_code;
678 nlmsg_request->request_done = 1;
679 /* always for found request */
680 kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
681 barrier();
682 wake_up(&nlmsg_request->waitq);
683 return 0;
684}
685EXPORT_SYMBOL(iwpm_mapping_error_cb);
diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c
new file mode 100644
index 000000000000..69e9f84c1605
--- /dev/null
+++ b/drivers/infiniband/core/iwpm_util.c
@@ -0,0 +1,607 @@
1/*
2 * Copyright (c) 2014 Chelsio, Inc. All rights reserved.
3 * Copyright (c) 2014 Intel Corporation. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 *
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
18 *
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 */
33
34#include "iwpm_util.h"
35
36#define IWPM_HASH_BUCKET_SIZE 512
37#define IWPM_HASH_BUCKET_MASK (IWPM_HASH_BUCKET_SIZE - 1)
38
39static LIST_HEAD(iwpm_nlmsg_req_list);
40static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock);
41
42static struct hlist_head *iwpm_hash_bucket;
43static DEFINE_SPINLOCK(iwpm_mapinfo_lock);
44
45static DEFINE_MUTEX(iwpm_admin_lock);
46static struct iwpm_admin_data iwpm_admin;
47
48int iwpm_init(u8 nl_client)
49{
50 if (iwpm_valid_client(nl_client))
51 return -EINVAL;
52 mutex_lock(&iwpm_admin_lock);
53 if (atomic_read(&iwpm_admin.refcount) == 0) {
54 iwpm_hash_bucket = kzalloc(IWPM_HASH_BUCKET_SIZE *
55 sizeof(struct hlist_head), GFP_KERNEL);
56 if (!iwpm_hash_bucket) {
57 mutex_unlock(&iwpm_admin_lock);
58 pr_err("%s Unable to create mapinfo hash table\n", __func__);
59 return -ENOMEM;
60 }
61 }
62 atomic_inc(&iwpm_admin.refcount);
63 mutex_unlock(&iwpm_admin_lock);
64 iwpm_set_valid(nl_client, 1);
65 return 0;
66}
67EXPORT_SYMBOL(iwpm_init);
68
69static void free_hash_bucket(void);
70
71int iwpm_exit(u8 nl_client)
72{
73
74 if (!iwpm_valid_client(nl_client))
75 return -EINVAL;
76 mutex_lock(&iwpm_admin_lock);
77 if (atomic_read(&iwpm_admin.refcount) == 0) {
78 mutex_unlock(&iwpm_admin_lock);
79 pr_err("%s Incorrect usage - negative refcount\n", __func__);
80 return -EINVAL;
81 }
82 if (atomic_dec_and_test(&iwpm_admin.refcount)) {
83 free_hash_bucket();
84 pr_debug("%s: Mapinfo hash table is destroyed\n", __func__);
85 }
86 mutex_unlock(&iwpm_admin_lock);
87 iwpm_set_valid(nl_client, 0);
88 return 0;
89}
90EXPORT_SYMBOL(iwpm_exit);
91
92static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage *,
93 struct sockaddr_storage *);
94
95int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
96 struct sockaddr_storage *mapped_sockaddr,
97 u8 nl_client)
98{
99 struct hlist_head *hash_bucket_head;
100 struct iwpm_mapping_info *map_info;
101 unsigned long flags;
102
103 if (!iwpm_valid_client(nl_client))
104 return -EINVAL;
105 map_info = kzalloc(sizeof(struct iwpm_mapping_info), GFP_KERNEL);
106 if (!map_info) {
107 pr_err("%s: Unable to allocate a mapping info\n", __func__);
108 return -ENOMEM;
109 }
110 memcpy(&map_info->local_sockaddr, local_sockaddr,
111 sizeof(struct sockaddr_storage));
112 memcpy(&map_info->mapped_sockaddr, mapped_sockaddr,
113 sizeof(struct sockaddr_storage));
114 map_info->nl_client = nl_client;
115
116 spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
117 if (iwpm_hash_bucket) {
118 hash_bucket_head = get_hash_bucket_head(
119 &map_info->local_sockaddr,
120 &map_info->mapped_sockaddr);
121 hlist_add_head(&map_info->hlist_node, hash_bucket_head);
122 }
123 spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
124 return 0;
125}
126EXPORT_SYMBOL(iwpm_create_mapinfo);
127
128int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr,
129 struct sockaddr_storage *mapped_local_addr)
130{
131 struct hlist_node *tmp_hlist_node;
132 struct hlist_head *hash_bucket_head;
133 struct iwpm_mapping_info *map_info = NULL;
134 unsigned long flags;
135 int ret = -EINVAL;
136
137 spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
138 if (iwpm_hash_bucket) {
139 hash_bucket_head = get_hash_bucket_head(
140 local_sockaddr,
141 mapped_local_addr);
142 hlist_for_each_entry_safe(map_info, tmp_hlist_node,
143 hash_bucket_head, hlist_node) {
144
145 if (!iwpm_compare_sockaddr(&map_info->mapped_sockaddr,
146 mapped_local_addr)) {
147
148 hlist_del_init(&map_info->hlist_node);
149 kfree(map_info);
150 ret = 0;
151 break;
152 }
153 }
154 }
155 spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
156 return ret;
157}
158EXPORT_SYMBOL(iwpm_remove_mapinfo);
159
160static void free_hash_bucket(void)
161{
162 struct hlist_node *tmp_hlist_node;
163 struct iwpm_mapping_info *map_info;
164 unsigned long flags;
165 int i;
166
167 /* remove all the mapinfo data from the list */
168 spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
169 for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
170 hlist_for_each_entry_safe(map_info, tmp_hlist_node,
171 &iwpm_hash_bucket[i], hlist_node) {
172
173 hlist_del_init(&map_info->hlist_node);
174 kfree(map_info);
175 }
176 }
177 /* free the hash list */
178 kfree(iwpm_hash_bucket);
179 iwpm_hash_bucket = NULL;
180 spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
181}
182
183struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
184 u8 nl_client, gfp_t gfp)
185{
186 struct iwpm_nlmsg_request *nlmsg_request = NULL;
187 unsigned long flags;
188
189 nlmsg_request = kzalloc(sizeof(struct iwpm_nlmsg_request), gfp);
190 if (!nlmsg_request) {
191 pr_err("%s Unable to allocate a nlmsg_request\n", __func__);
192 return NULL;
193 }
194 spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
195 list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list);
196 spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
197
198 kref_init(&nlmsg_request->kref);
199 kref_get(&nlmsg_request->kref);
200 nlmsg_request->nlmsg_seq = nlmsg_seq;
201 nlmsg_request->nl_client = nl_client;
202 nlmsg_request->request_done = 0;
203 nlmsg_request->err_code = 0;
204 return nlmsg_request;
205}
206
207void iwpm_free_nlmsg_request(struct kref *kref)
208{
209 struct iwpm_nlmsg_request *nlmsg_request;
210 unsigned long flags;
211
212 nlmsg_request = container_of(kref, struct iwpm_nlmsg_request, kref);
213
214 spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
215 list_del_init(&nlmsg_request->inprocess_list);
216 spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
217
218 if (!nlmsg_request->request_done)
219 pr_debug("%s Freeing incomplete nlmsg request (seq = %u).\n",
220 __func__, nlmsg_request->nlmsg_seq);
221 kfree(nlmsg_request);
222}
223
224struct iwpm_nlmsg_request *iwpm_find_nlmsg_request(__u32 echo_seq)
225{
226 struct iwpm_nlmsg_request *nlmsg_request;
227 struct iwpm_nlmsg_request *found_request = NULL;
228 unsigned long flags;
229
230 spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
231 list_for_each_entry(nlmsg_request, &iwpm_nlmsg_req_list,
232 inprocess_list) {
233 if (nlmsg_request->nlmsg_seq == echo_seq) {
234 found_request = nlmsg_request;
235 kref_get(&nlmsg_request->kref);
236 break;
237 }
238 }
239 spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
240 return found_request;
241}
242
243int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request)
244{
245 int ret;
246 init_waitqueue_head(&nlmsg_request->waitq);
247
248 ret = wait_event_timeout(nlmsg_request->waitq,
249 (nlmsg_request->request_done != 0), IWPM_NL_TIMEOUT);
250 if (!ret) {
251 ret = -EINVAL;
252 pr_info("%s: Timeout %d sec for netlink request (seq = %u)\n",
253 __func__, (IWPM_NL_TIMEOUT/HZ), nlmsg_request->nlmsg_seq);
254 } else {
255 ret = nlmsg_request->err_code;
256 }
257 kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
258 return ret;
259}
260
261int iwpm_get_nlmsg_seq(void)
262{
263 return atomic_inc_return(&iwpm_admin.nlmsg_seq);
264}
265
266int iwpm_valid_client(u8 nl_client)
267{
268 if (nl_client >= RDMA_NL_NUM_CLIENTS)
269 return 0;
270 return iwpm_admin.client_list[nl_client];
271}
272
273void iwpm_set_valid(u8 nl_client, int valid)
274{
275 if (nl_client >= RDMA_NL_NUM_CLIENTS)
276 return;
277 iwpm_admin.client_list[nl_client] = valid;
278}
279
280/* valid client */
281int iwpm_registered_client(u8 nl_client)
282{
283 return iwpm_admin.reg_list[nl_client];
284}
285
286/* valid client */
287void iwpm_set_registered(u8 nl_client, int reg)
288{
289 iwpm_admin.reg_list[nl_client] = reg;
290}
291
292int iwpm_compare_sockaddr(struct sockaddr_storage *a_sockaddr,
293 struct sockaddr_storage *b_sockaddr)
294{
295 if (a_sockaddr->ss_family != b_sockaddr->ss_family)
296 return 1;
297 if (a_sockaddr->ss_family == AF_INET) {
298 struct sockaddr_in *a4_sockaddr =
299 (struct sockaddr_in *)a_sockaddr;
300 struct sockaddr_in *b4_sockaddr =
301 (struct sockaddr_in *)b_sockaddr;
302 if (!memcmp(&a4_sockaddr->sin_addr,
303 &b4_sockaddr->sin_addr, sizeof(struct in_addr))
304 && a4_sockaddr->sin_port == b4_sockaddr->sin_port)
305 return 0;
306
307 } else if (a_sockaddr->ss_family == AF_INET6) {
308 struct sockaddr_in6 *a6_sockaddr =
309 (struct sockaddr_in6 *)a_sockaddr;
310 struct sockaddr_in6 *b6_sockaddr =
311 (struct sockaddr_in6 *)b_sockaddr;
312 if (!memcmp(&a6_sockaddr->sin6_addr,
313 &b6_sockaddr->sin6_addr, sizeof(struct in6_addr))
314 && a6_sockaddr->sin6_port == b6_sockaddr->sin6_port)
315 return 0;
316
317 } else {
318 pr_err("%s: Invalid sockaddr family\n", __func__);
319 }
320 return 1;
321}
322
323struct sk_buff *iwpm_create_nlmsg(u32 nl_op, struct nlmsghdr **nlh,
324 int nl_client)
325{
326 struct sk_buff *skb = NULL;
327
328 skb = dev_alloc_skb(NLMSG_GOODSIZE);
329 if (!skb) {
330 pr_err("%s Unable to allocate skb\n", __func__);
331 goto create_nlmsg_exit;
332 }
333 if (!(ibnl_put_msg(skb, nlh, 0, 0, nl_client, nl_op,
334 NLM_F_REQUEST))) {
335 pr_warn("%s: Unable to put the nlmsg header\n", __func__);
336 dev_kfree_skb(skb);
337 skb = NULL;
338 }
339create_nlmsg_exit:
340 return skb;
341}
342
343int iwpm_parse_nlmsg(struct netlink_callback *cb, int policy_max,
344 const struct nla_policy *nlmsg_policy,
345 struct nlattr *nltb[], const char *msg_type)
346{
347 int nlh_len = 0;
348 int ret;
349 const char *err_str = "";
350
351 ret = nlmsg_validate(cb->nlh, nlh_len, policy_max-1, nlmsg_policy);
352 if (ret) {
353 err_str = "Invalid attribute";
354 goto parse_nlmsg_error;
355 }
356 ret = nlmsg_parse(cb->nlh, nlh_len, nltb, policy_max-1, nlmsg_policy);
357 if (ret) {
358 err_str = "Unable to parse the nlmsg";
359 goto parse_nlmsg_error;
360 }
361 ret = iwpm_validate_nlmsg_attr(nltb, policy_max);
362 if (ret) {
363 err_str = "Invalid NULL attribute";
364 goto parse_nlmsg_error;
365 }
366 return 0;
367parse_nlmsg_error:
368 pr_warn("%s: %s (msg type %s ret = %d)\n",
369 __func__, err_str, msg_type, ret);
370 return ret;
371}
372
373void iwpm_print_sockaddr(struct sockaddr_storage *sockaddr, char *msg)
374{
375 struct sockaddr_in6 *sockaddr_v6;
376 struct sockaddr_in *sockaddr_v4;
377
378 switch (sockaddr->ss_family) {
379 case AF_INET:
380 sockaddr_v4 = (struct sockaddr_in *)sockaddr;
381 pr_debug("%s IPV4 %pI4: %u(0x%04X)\n",
382 msg, &sockaddr_v4->sin_addr,
383 ntohs(sockaddr_v4->sin_port),
384 ntohs(sockaddr_v4->sin_port));
385 break;
386 case AF_INET6:
387 sockaddr_v6 = (struct sockaddr_in6 *)sockaddr;
388 pr_debug("%s IPV6 %pI6: %u(0x%04X)\n",
389 msg, &sockaddr_v6->sin6_addr,
390 ntohs(sockaddr_v6->sin6_port),
391 ntohs(sockaddr_v6->sin6_port));
392 break;
393 default:
394 break;
395 }
396}
397
398static u32 iwpm_ipv6_jhash(struct sockaddr_in6 *ipv6_sockaddr)
399{
400 u32 ipv6_hash = jhash(&ipv6_sockaddr->sin6_addr, sizeof(struct in6_addr), 0);
401 u32 hash = jhash_2words(ipv6_hash, (__force u32) ipv6_sockaddr->sin6_port, 0);
402 return hash;
403}
404
405static u32 iwpm_ipv4_jhash(struct sockaddr_in *ipv4_sockaddr)
406{
407 u32 ipv4_hash = jhash(&ipv4_sockaddr->sin_addr, sizeof(struct in_addr), 0);
408 u32 hash = jhash_2words(ipv4_hash, (__force u32) ipv4_sockaddr->sin_port, 0);
409 return hash;
410}
411
412static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage
413 *local_sockaddr,
414 struct sockaddr_storage
415 *mapped_sockaddr)
416{
417 u32 local_hash, mapped_hash, hash;
418
419 if (local_sockaddr->ss_family == AF_INET) {
420 local_hash = iwpm_ipv4_jhash((struct sockaddr_in *) local_sockaddr);
421 mapped_hash = iwpm_ipv4_jhash((struct sockaddr_in *) mapped_sockaddr);
422
423 } else if (local_sockaddr->ss_family == AF_INET6) {
424 local_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) local_sockaddr);
425 mapped_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) mapped_sockaddr);
426 } else {
427 pr_err("%s: Invalid sockaddr family\n", __func__);
428 return NULL;
429 }
430
431 if (local_hash == mapped_hash) /* if port mapper isn't available */
432 hash = local_hash;
433 else
434 hash = jhash_2words(local_hash, mapped_hash, 0);
435
436 return &iwpm_hash_bucket[hash & IWPM_HASH_BUCKET_MASK];
437}
438
439static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid)
440{
441 struct sk_buff *skb = NULL;
442 struct nlmsghdr *nlh;
443 u32 msg_seq;
444 const char *err_str = "";
445 int ret = -EINVAL;
446
447 skb = iwpm_create_nlmsg(RDMA_NL_IWPM_MAPINFO_NUM, &nlh, nl_client);
448 if (!skb) {
449 err_str = "Unable to create a nlmsg";
450 goto mapinfo_num_error;
451 }
452 nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
453 msg_seq = 0;
454 err_str = "Unable to put attribute of mapinfo number nlmsg";
455 ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_MAPINFO_SEQ);
456 if (ret)
457 goto mapinfo_num_error;
458 ret = ibnl_put_attr(skb, nlh, sizeof(u32),
459 &mapping_num, IWPM_NLA_MAPINFO_SEND_NUM);
460 if (ret)
461 goto mapinfo_num_error;
462 ret = ibnl_unicast(skb, nlh, iwpm_pid);
463 if (ret) {
464 skb = NULL;
465 err_str = "Unable to send a nlmsg";
466 goto mapinfo_num_error;
467 }
468 pr_debug("%s: Sent mapping number = %d\n", __func__, mapping_num);
469 return 0;
470mapinfo_num_error:
471 pr_info("%s: %s\n", __func__, err_str);
472 if (skb)
473 dev_kfree_skb(skb);
474 return ret;
475}
476
477static int send_nlmsg_done(struct sk_buff *skb, u8 nl_client, int iwpm_pid)
478{
479 struct nlmsghdr *nlh = NULL;
480 int ret = 0;
481
482 if (!skb)
483 return ret;
484 if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
485 RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
486 pr_warn("%s Unable to put NLMSG_DONE\n", __func__);
487 return -ENOMEM;
488 }
489 nlh->nlmsg_type = NLMSG_DONE;
490 ret = ibnl_unicast(skb, (struct nlmsghdr *)skb->data, iwpm_pid);
491 if (ret)
492 pr_warn("%s Unable to send a nlmsg\n", __func__);
493 return ret;
494}
495
496int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid)
497{
498 struct iwpm_mapping_info *map_info;
499 struct sk_buff *skb = NULL;
500 struct nlmsghdr *nlh;
501 int skb_num = 0, mapping_num = 0;
502 int i = 0, nlmsg_bytes = 0;
503 unsigned long flags;
504 const char *err_str = "";
505 int ret;
506
507 skb = dev_alloc_skb(NLMSG_GOODSIZE);
508 if (!skb) {
509 ret = -ENOMEM;
510 err_str = "Unable to allocate skb";
511 goto send_mapping_info_exit;
512 }
513 skb_num++;
514 spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
515 for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
516 hlist_for_each_entry(map_info, &iwpm_hash_bucket[i],
517 hlist_node) {
518 if (map_info->nl_client != nl_client)
519 continue;
520 nlh = NULL;
521 if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
522 RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
523 ret = -ENOMEM;
524 err_str = "Unable to put the nlmsg header";
525 goto send_mapping_info_unlock;
526 }
527 err_str = "Unable to put attribute of the nlmsg";
528 ret = ibnl_put_attr(skb, nlh,
529 sizeof(struct sockaddr_storage),
530 &map_info->local_sockaddr,
531 IWPM_NLA_MAPINFO_LOCAL_ADDR);
532 if (ret)
533 goto send_mapping_info_unlock;
534
535 ret = ibnl_put_attr(skb, nlh,
536 sizeof(struct sockaddr_storage),
537 &map_info->mapped_sockaddr,
538 IWPM_NLA_MAPINFO_MAPPED_ADDR);
539 if (ret)
540 goto send_mapping_info_unlock;
541
542 iwpm_print_sockaddr(&map_info->local_sockaddr,
543 "send_mapping_info: Local sockaddr:");
544 iwpm_print_sockaddr(&map_info->mapped_sockaddr,
545 "send_mapping_info: Mapped local sockaddr:");
546 mapping_num++;
547 nlmsg_bytes += nlh->nlmsg_len;
548
549 /* check if all mappings can fit in one skb */
550 if (NLMSG_GOODSIZE - nlmsg_bytes < nlh->nlmsg_len * 2) {
551 /* and leave room for NLMSG_DONE */
552 nlmsg_bytes = 0;
553 skb_num++;
554 spin_unlock_irqrestore(&iwpm_mapinfo_lock,
555 flags);
556 /* send the skb */
557 ret = send_nlmsg_done(skb, nl_client, iwpm_pid);
558 skb = NULL;
559 if (ret) {
560 err_str = "Unable to send map info";
561 goto send_mapping_info_exit;
562 }
563 if (skb_num == IWPM_MAPINFO_SKB_COUNT) {
564 ret = -ENOMEM;
565 err_str = "Insufficient skbs for map info";
566 goto send_mapping_info_exit;
567 }
568 skb = dev_alloc_skb(NLMSG_GOODSIZE);
569 if (!skb) {
570 ret = -ENOMEM;
571 err_str = "Unable to allocate skb";
572 goto send_mapping_info_exit;
573 }
574 spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
575 }
576 }
577 }
578send_mapping_info_unlock:
579 spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
580send_mapping_info_exit:
581 if (ret) {
582 pr_warn("%s: %s (ret = %d)\n", __func__, err_str, ret);
583 if (skb)
584 dev_kfree_skb(skb);
585 return ret;
586 }
587 send_nlmsg_done(skb, nl_client, iwpm_pid);
588 return send_mapinfo_num(mapping_num, nl_client, iwpm_pid);
589}
590
591int iwpm_mapinfo_available(void)
592{
593 unsigned long flags;
594 int full_bucket = 0, i = 0;
595
596 spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
597 if (iwpm_hash_bucket) {
598 for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
599 if (!hlist_empty(&iwpm_hash_bucket[i])) {
600 full_bucket = 1;
601 break;
602 }
603 }
604 }
605 spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
606 return full_bucket;
607}
diff --git a/drivers/infiniband/core/iwpm_util.h b/drivers/infiniband/core/iwpm_util.h
new file mode 100644
index 000000000000..9777c869a140
--- /dev/null
+++ b/drivers/infiniband/core/iwpm_util.h
@@ -0,0 +1,238 @@
1/*
2 * Copyright (c) 2014 Intel Corporation. All rights reserved.
3 * Copyright (c) 2014 Chelsio, Inc. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 *
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
18 *
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 */
33#ifndef _IWPM_UTIL_H
34#define _IWPM_UTIL_H
35
36#include <linux/module.h>
37#include <linux/io.h>
38#include <linux/in.h>
39#include <linux/in6.h>
40#include <linux/spinlock.h>
41#include <linux/kernel.h>
42#include <linux/netdevice.h>
43#include <linux/delay.h>
44#include <linux/workqueue.h>
45#include <linux/mutex.h>
46#include <linux/jhash.h>
47#include <linux/kref.h>
48#include <net/netlink.h>
49#include <linux/errno.h>
50#include <rdma/iw_portmap.h>
51#include <rdma/rdma_netlink.h>
52
53
54#define IWPM_NL_RETRANS 3
55#define IWPM_NL_TIMEOUT (10*HZ)
56#define IWPM_MAPINFO_SKB_COUNT 20
57
58#define IWPM_PID_UNDEFINED -1
59#define IWPM_PID_UNAVAILABLE -2
60
61struct iwpm_nlmsg_request {
62 struct list_head inprocess_list;
63 __u32 nlmsg_seq;
64 void *req_buffer;
65 u8 nl_client;
66 u8 request_done;
67 u16 err_code;
68 wait_queue_head_t waitq;
69 struct kref kref;
70};
71
72struct iwpm_mapping_info {
73 struct hlist_node hlist_node;
74 struct sockaddr_storage local_sockaddr;
75 struct sockaddr_storage mapped_sockaddr;
76 u8 nl_client;
77};
78
79struct iwpm_admin_data {
80 atomic_t refcount;
81 atomic_t nlmsg_seq;
82 int client_list[RDMA_NL_NUM_CLIENTS];
83 int reg_list[RDMA_NL_NUM_CLIENTS];
84};
85
86/**
87 * iwpm_get_nlmsg_request - Allocate and initialize netlink message request
88 * @nlmsg_seq: Sequence number of the netlink message
89 * @nl_client: The index of the netlink client
90 * @gfp: Indicates how the memory for the request should be allocated
91 *
92 * Returns the newly allocated netlink request object if successful,
93 * otherwise returns NULL
94 */
95struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
96 u8 nl_client, gfp_t gfp);
97
98/**
99 * iwpm_free_nlmsg_request - Deallocate netlink message request
100 * @kref: Holds reference of netlink message request
101 */
102void iwpm_free_nlmsg_request(struct kref *kref);
103
104/**
105 * iwpm_find_nlmsg_request - Find netlink message request in the request list
106 * @echo_seq: Sequence number of the netlink request to find
107 *
108 * Returns the found netlink message request,
109 * if not found, returns NULL
110 */
111struct iwpm_nlmsg_request *iwpm_find_nlmsg_request(__u32 echo_seq);
112
113/**
114 * iwpm_wait_complete_req - Block while servicing the netlink request
115 * @nlmsg_request: Netlink message request to service
116 *
117 * Wakes up, after the request is completed or expired
118 * Returns 0 if the request is complete without error
119 */
120int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request);
121
122/**
123 * iwpm_get_nlmsg_seq - Get the sequence number for a netlink
124 * message to send to the port mapper
125 *
126 * Returns the sequence number for the netlink message.
127 */
128int iwpm_get_nlmsg_seq(void);
129
130/**
131 * iwpm_valid_client - Check if the port mapper client is valid
132 * @nl_client: The index of the netlink client
133 *
134 * Valid clients need to call iwpm_init() before using
135 * the port mapper
136 */
137int iwpm_valid_client(u8 nl_client);
138
139/**
140 * iwpm_set_valid - Set the port mapper client to valid or not
141 * @nl_client: The index of the netlink client
142 * @valid: 1 if valid or 0 if invalid
143 */
144void iwpm_set_valid(u8 nl_client, int valid);
145
146/**
147 * iwpm_registered_client - Check if the port mapper client is registered
148 * @nl_client: The index of the netlink client
149 *
150 * Call iwpm_register_pid() to register a client
151 */
152int iwpm_registered_client(u8 nl_client);
153
154/**
155 * iwpm_set_registered - Set the port mapper client to registered or not
156 * @nl_client: The index of the netlink client
157 * @reg: 1 if registered or 0 if not
158 */
159void iwpm_set_registered(u8 nl_client, int reg);
160
161/**
162 * iwpm_send_mapinfo - Send local and mapped IPv4/IPv6 address info of
163 * a client to the user space port mapper
164 * @nl_client: The index of the netlink client
165 * @iwpm_pid: The pid of the user space port mapper
166 *
167 * If successful, returns the number of sent mapping info records
168 */
169int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid);
170
171/**
172 * iwpm_mapinfo_available - Check if any mapping info records is available
173 * in the hash table
174 *
175 * Returns 1 if mapping information is available, otherwise returns 0
176 */
177int iwpm_mapinfo_available(void);
178
179/**
180 * iwpm_compare_sockaddr - Compare two sockaddr storage structs
181 *
182 * Returns 0 if they are holding the same ip/tcp address info,
183 * otherwise returns 1
184 */
185int iwpm_compare_sockaddr(struct sockaddr_storage *a_sockaddr,
186 struct sockaddr_storage *b_sockaddr);
187
188/**
189 * iwpm_validate_nlmsg_attr - Check for NULL netlink attributes
190 * @nltb: Holds address of each netlink message attributes
191 * @nla_count: Number of netlink message attributes
192 *
193 * Returns error if any of the nla_count attributes is NULL
194 */
195static inline int iwpm_validate_nlmsg_attr(struct nlattr *nltb[],
196 int nla_count)
197{
198 int i;
199 for (i = 1; i < nla_count; i++) {
200 if (!nltb[i])
201 return -EINVAL;
202 }
203 return 0;
204}
205
206/**
207 * iwpm_create_nlmsg - Allocate skb and form a netlink message
208 * @nl_op: Netlink message opcode
209 * @nlh: Holds address of the netlink message header in skb
210 * @nl_client: The index of the netlink client
211 *
212 * Returns the newly allcated skb, or NULL if the tailroom of the skb
213 * is insufficient to store the message header and payload
214 */
215struct sk_buff *iwpm_create_nlmsg(u32 nl_op, struct nlmsghdr **nlh,
216 int nl_client);
217
218/**
219 * iwpm_parse_nlmsg - Validate and parse the received netlink message
220 * @cb: Netlink callback structure
221 * @policy_max: Maximum attribute type to be expected
222 * @nlmsg_policy: Validation policy
223 * @nltb: Array to store policy_max parsed elements
224 * @msg_type: Type of netlink message
225 *
226 * Returns 0 on success or a negative error code
227 */
228int iwpm_parse_nlmsg(struct netlink_callback *cb, int policy_max,
229 const struct nla_policy *nlmsg_policy,
230 struct nlattr *nltb[], const char *msg_type);
231
232/**
233 * iwpm_print_sockaddr - Print IPv4/IPv6 address and TCP port
234 * @sockaddr: Socket address to print
235 * @msg: Message to print
236 */
237void iwpm_print_sockaddr(struct sockaddr_storage *sockaddr, char *msg);
238#endif
diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c
index a1e9cba84944..23dd5a5c7597 100644
--- a/drivers/infiniband/core/netlink.c
+++ b/drivers/infiniband/core/netlink.c
@@ -103,13 +103,13 @@ int ibnl_remove_client(int index)
103EXPORT_SYMBOL(ibnl_remove_client); 103EXPORT_SYMBOL(ibnl_remove_client);
104 104
105void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, 105void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
106 int len, int client, int op) 106 int len, int client, int op, int flags)
107{ 107{
108 unsigned char *prev_tail; 108 unsigned char *prev_tail;
109 109
110 prev_tail = skb_tail_pointer(skb); 110 prev_tail = skb_tail_pointer(skb);
111 *nlh = nlmsg_put(skb, 0, seq, RDMA_NL_GET_TYPE(client, op), 111 *nlh = nlmsg_put(skb, 0, seq, RDMA_NL_GET_TYPE(client, op),
112 len, NLM_F_MULTI); 112 len, flags);
113 if (!*nlh) 113 if (!*nlh)
114 goto out_nlmsg_trim; 114 goto out_nlmsg_trim;
115 (*nlh)->nlmsg_len = skb_tail_pointer(skb) - prev_tail; 115 (*nlh)->nlmsg_len = skb_tail_pointer(skb) - prev_tail;
@@ -172,6 +172,20 @@ static void ibnl_rcv(struct sk_buff *skb)
172 mutex_unlock(&ibnl_mutex); 172 mutex_unlock(&ibnl_mutex);
173} 173}
174 174
175int ibnl_unicast(struct sk_buff *skb, struct nlmsghdr *nlh,
176 __u32 pid)
177{
178 return nlmsg_unicast(nls, skb, pid);
179}
180EXPORT_SYMBOL(ibnl_unicast);
181
182int ibnl_multicast(struct sk_buff *skb, struct nlmsghdr *nlh,
183 unsigned int group, gfp_t flags)
184{
185 return nlmsg_multicast(nls, skb, 0, group, flags);
186}
187EXPORT_SYMBOL(ibnl_multicast);
188
175int __init ibnl_init(void) 189int __init ibnl_init(void)
176{ 190{
177 struct netlink_kernel_cfg cfg = { 191 struct netlink_kernel_cfg cfg = {
diff --git a/include/rdma/iw_portmap.h b/include/rdma/iw_portmap.h
new file mode 100644
index 000000000000..928b2775e992
--- /dev/null
+++ b/include/rdma/iw_portmap.h
@@ -0,0 +1,199 @@
1/*
2 * Copyright (c) 2014 Intel Corporation. All rights reserved.
3 * Copyright (c) 2014 Chelsio, Inc. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 *
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
18 *
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 */
33#ifndef _IW_PORTMAP_H
34#define _IW_PORTMAP_H
35
36#define IWPM_ULIBNAME_SIZE 32
37#define IWPM_DEVNAME_SIZE 32
38#define IWPM_IFNAME_SIZE 16
39#define IWPM_IPADDR_SIZE 16
40
41enum {
42 IWPM_INVALID_NLMSG_ERR = 10,
43 IWPM_CREATE_MAPPING_ERR,
44 IWPM_DUPLICATE_MAPPING_ERR,
45 IWPM_UNKNOWN_MAPPING_ERR,
46 IWPM_CLIENT_DEV_INFO_ERR,
47 IWPM_USER_LIB_INFO_ERR,
48 IWPM_REMOTE_QUERY_REJECT
49};
50
51struct iwpm_dev_data {
52 char dev_name[IWPM_DEVNAME_SIZE];
53 char if_name[IWPM_IFNAME_SIZE];
54};
55
56struct iwpm_sa_data {
57 struct sockaddr_storage loc_addr;
58 struct sockaddr_storage mapped_loc_addr;
59 struct sockaddr_storage rem_addr;
60 struct sockaddr_storage mapped_rem_addr;
61};
62
63/**
64 * iwpm_init - Allocate resources for the iwarp port mapper
65 *
66 * Should be called when network interface goes up.
67 */
68int iwpm_init(u8);
69
70/**
71 * iwpm_exit - Deallocate resources for the iwarp port mapper
72 *
73 * Should be called when network interface goes down.
74 */
75int iwpm_exit(u8);
76
77/**
78 * iwpm_valid_pid - Check if the userspace iwarp port mapper pid is valid
79 *
80 * Returns true if the pid is greater than zero, otherwise returns false
81 */
82int iwpm_valid_pid(void);
83
84/**
85 * iwpm_register_pid - Send a netlink query to userspace
86 * to get the iwarp port mapper pid
87 * @pm_msg: Contains driver info to send to the userspace port mapper
88 * @nl_client: The index of the netlink client
89 */
90int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client);
91
92/**
93 * iwpm_add_mapping - Send a netlink add mapping request to
94 * the userspace port mapper
95 * @pm_msg: Contains the local ip/tcp address info to send
96 * @nl_client: The index of the netlink client
97 *
98 * If the request is successful, the pm_msg stores
99 * the port mapper response (mapped address info)
100 */
101int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client);
102
103/**
104 * iwpm_add_and_query_mapping - Send a netlink add and query mapping request
105 * to the userspace port mapper
106 * @pm_msg: Contains the local and remote ip/tcp address info to send
107 * @nl_client: The index of the netlink client
108 *
109 * If the request is successful, the pm_msg stores the
110 * port mapper response (mapped local and remote address info)
111 */
112int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client);
113
114/**
115 * iwpm_remove_mapping - Send a netlink remove mapping request
116 * to the userspace port mapper
117 *
118 * @local_addr: Local ip/tcp address to remove
119 * @nl_client: The index of the netlink client
120 */
121int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client);
122
123/**
124 * iwpm_register_pid_cb - Process the port mapper response to
125 * iwpm_register_pid query
126 * @skb:
127 * @cb: Contains the received message (payload and netlink header)
128 *
129 * If successful, the function receives the userspace port mapper pid
130 * which is used in future communication with the port mapper
131 */
132int iwpm_register_pid_cb(struct sk_buff *, struct netlink_callback *);
133
134/**
135 * iwpm_add_mapping_cb - Process the port mapper response to
136 * iwpm_add_mapping request
137 * @skb:
138 * @cb: Contains the received message (payload and netlink header)
139 */
140int iwpm_add_mapping_cb(struct sk_buff *, struct netlink_callback *);
141
142/**
143 * iwpm_add_and_query_mapping_cb - Process the port mapper response to
144 * iwpm_add_and_query_mapping request
145 * @skb:
146 * @cb: Contains the received message (payload and netlink header)
147 */
148int iwpm_add_and_query_mapping_cb(struct sk_buff *, struct netlink_callback *);
149
150/**
151 * iwpm_mapping_error_cb - Process port mapper notification for error
152 *
153 * @skb:
154 * @cb: Contains the received message (payload and netlink header)
155 */
156int iwpm_mapping_error_cb(struct sk_buff *, struct netlink_callback *);
157
158/**
159 * iwpm_mapping_info_cb - Process a notification that the userspace
160 * port mapper daemon is started
161 * @skb:
162 * @cb: Contains the received message (payload and netlink header)
163 *
164 * Using the received port mapper pid, send all the local mapping
165 * info records to the userspace port mapper
166 */
167int iwpm_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
168
169/**
170 * iwpm_ack_mapping_info_cb - Process the port mapper ack for
171 * the provided local mapping info records
172 * @skb:
173 * @cb: Contains the received message (payload and netlink header)
174 */
175int iwpm_ack_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
176
177/**
178 * iwpm_create_mapinfo - Store local and mapped IPv4/IPv6 address
179 * info in a hash table
180 * @local_addr: Local ip/tcp address
181 * @mapped_addr: Mapped local ip/tcp address
182 * @nl_client: The index of the netlink client
183 */
184int iwpm_create_mapinfo(struct sockaddr_storage *local_addr,
185 struct sockaddr_storage *mapped_addr, u8 nl_client);
186
187/**
188 * iwpm_remove_mapinfo - Remove local and mapped IPv4/IPv6 address
189 * info from the hash table
190 * @local_addr: Local ip/tcp address
191 * @mapped_addr: Mapped local ip/tcp address
192 *
193 * Returns err code if mapping info is not found in the hash table,
194 * otherwise returns 0
195 */
196int iwpm_remove_mapinfo(struct sockaddr_storage *local_addr,
197 struct sockaddr_storage *mapped_addr);
198
199#endif /* _IW_PORTMAP_H */
diff --git a/include/rdma/rdma_netlink.h b/include/rdma/rdma_netlink.h
index e38de79eeb48..0790882e0c9b 100644
--- a/include/rdma/rdma_netlink.h
+++ b/include/rdma/rdma_netlink.h
@@ -43,7 +43,7 @@ int ibnl_remove_client(int index);
43 * Returns the allocated buffer on success and NULL on failure. 43 * Returns the allocated buffer on success and NULL on failure.
44 */ 44 */
45void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, 45void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
46 int len, int client, int op); 46 int len, int client, int op, int flags);
47/** 47/**
48 * Put a new attribute in a supplied skb. 48 * Put a new attribute in a supplied skb.
49 * @skb: The netlink skb. 49 * @skb: The netlink skb.
@@ -56,4 +56,25 @@ void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
56int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh, 56int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh,
57 int len, void *data, int type); 57 int len, void *data, int type);
58 58
59/**
60 * Send the supplied skb to a specific userspace PID.
61 * @skb: The netlink skb
62 * @nlh: Header of the netlink message to send
63 * @pid: Userspace netlink process ID
64 * Returns 0 on success or a negative error code.
65 */
66int ibnl_unicast(struct sk_buff *skb, struct nlmsghdr *nlh,
67 __u32 pid);
68
69/**
70 * Send the supplied skb to a netlink group.
71 * @skb: The netlink skb
72 * @nlh: Header of the netlink message to send
73 * @group: Netlink group ID
74 * @flags: allocation flags
75 * Returns 0 on success or a negative error code.
76 */
77int ibnl_multicast(struct sk_buff *skb, struct nlmsghdr *nlh,
78 unsigned int group, gfp_t flags);
79
59#endif /* _RDMA_NETLINK_H */ 80#endif /* _RDMA_NETLINK_H */
diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h
index 8297285b6288..de69170a30ce 100644
--- a/include/uapi/rdma/rdma_netlink.h
+++ b/include/uapi/rdma/rdma_netlink.h
@@ -4,7 +4,16 @@
4#include <linux/types.h> 4#include <linux/types.h>
5 5
6enum { 6enum {
7 RDMA_NL_RDMA_CM = 1 7 RDMA_NL_RDMA_CM = 1,
8 RDMA_NL_NES,
9 RDMA_NL_C4IW,
10 RDMA_NL_NUM_CLIENTS
11};
12
13enum {
14 RDMA_NL_GROUP_CM = 1,
15 RDMA_NL_GROUP_IWPM,
16 RDMA_NL_NUM_GROUPS
8}; 17};
9 18
10#define RDMA_NL_GET_CLIENT(type) ((type & (((1 << 6) - 1) << 10)) >> 10) 19#define RDMA_NL_GET_CLIENT(type) ((type & (((1 << 6) - 1) << 10)) >> 10)
@@ -22,6 +31,18 @@ enum {
22 RDMA_NL_RDMA_CM_NUM_ATTR, 31 RDMA_NL_RDMA_CM_NUM_ATTR,
23}; 32};
24 33
34/* iwarp port mapper op-codes */
35enum {
36 RDMA_NL_IWPM_REG_PID = 0,
37 RDMA_NL_IWPM_ADD_MAPPING,
38 RDMA_NL_IWPM_QUERY_MAPPING,
39 RDMA_NL_IWPM_REMOVE_MAPPING,
40 RDMA_NL_IWPM_HANDLE_ERR,
41 RDMA_NL_IWPM_MAPINFO,
42 RDMA_NL_IWPM_MAPINFO_NUM,
43 RDMA_NL_IWPM_NUM_OPS
44};
45
25struct rdma_cm_id_stats { 46struct rdma_cm_id_stats {
26 __u32 qp_num; 47 __u32 qp_num;
27 __u32 bound_dev_if; 48 __u32 bound_dev_if;
@@ -33,5 +54,78 @@ struct rdma_cm_id_stats {
33 __u8 qp_type; 54 __u8 qp_type;
34}; 55};
35 56
57enum {
58 IWPM_NLA_REG_PID_UNSPEC = 0,
59 IWPM_NLA_REG_PID_SEQ,
60 IWPM_NLA_REG_IF_NAME,
61 IWPM_NLA_REG_IBDEV_NAME,
62 IWPM_NLA_REG_ULIB_NAME,
63 IWPM_NLA_REG_PID_MAX
64};
65
66enum {
67 IWPM_NLA_RREG_PID_UNSPEC = 0,
68 IWPM_NLA_RREG_PID_SEQ,
69 IWPM_NLA_RREG_IBDEV_NAME,
70 IWPM_NLA_RREG_ULIB_NAME,
71 IWPM_NLA_RREG_ULIB_VER,
72 IWPM_NLA_RREG_PID_ERR,
73 IWPM_NLA_RREG_PID_MAX
74
75};
76
77enum {
78 IWPM_NLA_MANAGE_MAPPING_UNSPEC = 0,
79 IWPM_NLA_MANAGE_MAPPING_SEQ,
80 IWPM_NLA_MANAGE_ADDR,
81 IWPM_NLA_MANAGE_MAPPED_LOC_ADDR,
82 IWPM_NLA_RMANAGE_MAPPING_ERR,
83 IWPM_NLA_RMANAGE_MAPPING_MAX
84};
85
86#define IWPM_NLA_MANAGE_MAPPING_MAX 3
87#define IWPM_NLA_QUERY_MAPPING_MAX 4
88#define IWPM_NLA_MAPINFO_SEND_MAX 3
89
90enum {
91 IWPM_NLA_QUERY_MAPPING_UNSPEC = 0,
92 IWPM_NLA_QUERY_MAPPING_SEQ,
93 IWPM_NLA_QUERY_LOCAL_ADDR,
94 IWPM_NLA_QUERY_REMOTE_ADDR,
95 IWPM_NLA_RQUERY_MAPPED_LOC_ADDR,
96 IWPM_NLA_RQUERY_MAPPED_REM_ADDR,
97 IWPM_NLA_RQUERY_MAPPING_ERR,
98 IWPM_NLA_RQUERY_MAPPING_MAX
99};
100
101enum {
102 IWPM_NLA_MAPINFO_REQ_UNSPEC = 0,
103 IWPM_NLA_MAPINFO_ULIB_NAME,
104 IWPM_NLA_MAPINFO_ULIB_VER,
105 IWPM_NLA_MAPINFO_REQ_MAX
106};
107
108enum {
109 IWPM_NLA_MAPINFO_UNSPEC = 0,
110 IWPM_NLA_MAPINFO_LOCAL_ADDR,
111 IWPM_NLA_MAPINFO_MAPPED_ADDR,
112 IWPM_NLA_MAPINFO_MAX
113};
114
115enum {
116 IWPM_NLA_MAPINFO_NUM_UNSPEC = 0,
117 IWPM_NLA_MAPINFO_SEQ,
118 IWPM_NLA_MAPINFO_SEND_NUM,
119 IWPM_NLA_MAPINFO_ACK_NUM,
120 IWPM_NLA_MAPINFO_NUM_MAX
121};
122
123enum {
124 IWPM_NLA_ERR_UNSPEC = 0,
125 IWPM_NLA_ERR_SEQ,
126 IWPM_NLA_ERR_CODE,
127 IWPM_NLA_ERR_MAX
128};
129
36 130
37#endif /* _UAPI_RDMA_NETLINK_H */ 131#endif /* _UAPI_RDMA_NETLINK_H */