2 * Copyright (c) 2017 Mellanox Technologies Inc. All rights reserved.
3 * Copyright (c) 2010 Voltaire Inc. All rights reserved.
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:
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
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.
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
34 #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
36 #include <linux/export.h>
37 #include <net/netlink.h>
38 #include <net/net_namespace.h>
39 #include <net/netns/generic.h>
41 #include <rdma/rdma_netlink.h>
42 #include <linux/module.h>
43 #include "core_priv.h"
46 const struct rdma_nl_cbs
*cb_table
;
47 /* Synchronizes between ongoing netlink commands and netlink client
50 struct rw_semaphore sem
;
51 } rdma_nl_types
[RDMA_NL_NUM_CLIENTS
];
53 bool rdma_nl_chk_listeners(unsigned int group
)
55 struct rdma_dev_net
*rnet
= rdma_net_to_dev_net(&init_net
);
57 return netlink_has_listeners(rnet
->nl_sock
, group
);
59 EXPORT_SYMBOL(rdma_nl_chk_listeners
);
61 static bool is_nl_msg_valid(unsigned int type
, unsigned int op
)
63 static const unsigned int max_num_ops
[RDMA_NL_NUM_CLIENTS
] = {
64 [RDMA_NL_IWCM
] = RDMA_NL_IWPM_NUM_OPS
,
65 [RDMA_NL_LS
] = RDMA_NL_LS_NUM_OPS
,
66 [RDMA_NL_NLDEV
] = RDMA_NLDEV_NUM_OPS
,
70 * This BUILD_BUG_ON is intended to catch addition of new
71 * RDMA netlink protocol without updating the array above.
73 BUILD_BUG_ON(RDMA_NL_NUM_CLIENTS
!= 6);
75 if (type
>= RDMA_NL_NUM_CLIENTS
)
78 return (op
< max_num_ops
[type
]) ? true : false;
81 static const struct rdma_nl_cbs
*
82 get_cb_table(const struct sk_buff
*skb
, unsigned int type
, unsigned int op
)
84 const struct rdma_nl_cbs
*cb_table
;
87 * Currently only NLDEV client is supporting netlink commands in
88 * non init_net net namespace.
90 if (sock_net(skb
->sk
) != &init_net
&& type
!= RDMA_NL_NLDEV
)
93 cb_table
= READ_ONCE(rdma_nl_types
[type
].cb_table
);
96 * Didn't get valid reference of the table, attempt module
99 up_read(&rdma_nl_types
[type
].sem
);
101 request_module("rdma-netlink-subsys-%d", type
);
103 down_read(&rdma_nl_types
[type
].sem
);
104 cb_table
= READ_ONCE(rdma_nl_types
[type
].cb_table
);
106 if (!cb_table
|| (!cb_table
[op
].dump
&& !cb_table
[op
].doit
))
111 void rdma_nl_register(unsigned int index
,
112 const struct rdma_nl_cbs cb_table
[])
114 if (WARN_ON(!is_nl_msg_valid(index
, 0)) ||
115 WARN_ON(READ_ONCE(rdma_nl_types
[index
].cb_table
)))
118 /* Pairs with the READ_ONCE in is_nl_valid() */
119 smp_store_release(&rdma_nl_types
[index
].cb_table
, cb_table
);
121 EXPORT_SYMBOL(rdma_nl_register
);
123 void rdma_nl_unregister(unsigned int index
)
125 down_write(&rdma_nl_types
[index
].sem
);
126 rdma_nl_types
[index
].cb_table
= NULL
;
127 up_write(&rdma_nl_types
[index
].sem
);
129 EXPORT_SYMBOL(rdma_nl_unregister
);
131 void *ibnl_put_msg(struct sk_buff
*skb
, struct nlmsghdr
**nlh
, int seq
,
132 int len
, int client
, int op
, int flags
)
134 *nlh
= nlmsg_put(skb
, 0, seq
, RDMA_NL_GET_TYPE(client
, op
), len
, flags
);
137 return nlmsg_data(*nlh
);
139 EXPORT_SYMBOL(ibnl_put_msg
);
141 int ibnl_put_attr(struct sk_buff
*skb
, struct nlmsghdr
*nlh
,
142 int len
, void *data
, int type
)
144 if (nla_put(skb
, type
, len
, data
)) {
145 nlmsg_cancel(skb
, nlh
);
150 EXPORT_SYMBOL(ibnl_put_attr
);
152 static int rdma_nl_rcv_msg(struct sk_buff
*skb
, struct nlmsghdr
*nlh
,
153 struct netlink_ext_ack
*extack
)
155 int type
= nlh
->nlmsg_type
;
156 unsigned int index
= RDMA_NL_GET_CLIENT(type
);
157 unsigned int op
= RDMA_NL_GET_OP(type
);
158 const struct rdma_nl_cbs
*cb_table
;
161 if (!is_nl_msg_valid(index
, op
))
164 down_read(&rdma_nl_types
[index
].sem
);
165 cb_table
= get_cb_table(skb
, index
, op
);
169 if ((cb_table
[op
].flags
& RDMA_NL_ADMIN_PERM
) &&
170 !netlink_capable(skb
, CAP_NET_ADMIN
)) {
176 * LS responses overload the 0x100 (NLM_F_ROOT) flag. Don't
177 * mistakenly call the .dump() function.
179 if (index
== RDMA_NL_LS
) {
180 if (cb_table
[op
].doit
)
181 err
= cb_table
[op
].doit(skb
, nlh
, extack
);
184 /* FIXME: Convert IWCM to properly handle doit callbacks */
185 if ((nlh
->nlmsg_flags
& NLM_F_DUMP
) || index
== RDMA_NL_IWCM
) {
186 struct netlink_dump_control c
= {
187 .dump
= cb_table
[op
].dump
,
190 err
= netlink_dump_start(skb
->sk
, skb
, nlh
, &c
);
194 if (cb_table
[op
].doit
)
195 err
= cb_table
[op
].doit(skb
, nlh
, extack
);
197 up_read(&rdma_nl_types
[index
].sem
);
202 * This function is similar to netlink_rcv_skb with one exception:
203 * It calls to the callback for the netlink messages without NLM_F_REQUEST
204 * flag. These messages are intended for RDMA_NL_LS consumer, so it is allowed
205 * for that consumer only.
207 static int rdma_nl_rcv_skb(struct sk_buff
*skb
, int (*cb
)(struct sk_buff
*,
209 struct netlink_ext_ack
*))
211 struct netlink_ext_ack extack
= {};
212 struct nlmsghdr
*nlh
;
215 while (skb
->len
>= nlmsg_total_size(0)) {
218 nlh
= nlmsg_hdr(skb
);
221 if (nlh
->nlmsg_len
< NLMSG_HDRLEN
|| skb
->len
< nlh
->nlmsg_len
)
225 * Generally speaking, the only requests are handled
226 * by the kernel, but RDMA_NL_LS is different, because it
227 * runs backward netlink scheme. Kernel initiates messages
228 * and waits for reply with data to keep pathrecord cache
231 if (!(nlh
->nlmsg_flags
& NLM_F_REQUEST
) &&
232 (RDMA_NL_GET_CLIENT(nlh
->nlmsg_type
) != RDMA_NL_LS
))
235 /* Skip control messages */
236 if (nlh
->nlmsg_type
< NLMSG_MIN_TYPE
)
239 err
= cb(skb
, nlh
, &extack
);
244 if (nlh
->nlmsg_flags
& NLM_F_ACK
|| err
)
245 netlink_ack(skb
, nlh
, err
, &extack
);
248 msglen
= NLMSG_ALIGN(nlh
->nlmsg_len
);
249 if (msglen
> skb
->len
)
251 skb_pull(skb
, msglen
);
257 static void rdma_nl_rcv(struct sk_buff
*skb
)
259 rdma_nl_rcv_skb(skb
, &rdma_nl_rcv_msg
);
262 int rdma_nl_unicast(struct net
*net
, struct sk_buff
*skb
, u32 pid
)
264 struct rdma_dev_net
*rnet
= rdma_net_to_dev_net(net
);
267 err
= netlink_unicast(rnet
->nl_sock
, skb
, pid
, MSG_DONTWAIT
);
268 return (err
< 0) ? err
: 0;
270 EXPORT_SYMBOL(rdma_nl_unicast
);
272 int rdma_nl_unicast_wait(struct net
*net
, struct sk_buff
*skb
, __u32 pid
)
274 struct rdma_dev_net
*rnet
= rdma_net_to_dev_net(net
);
277 err
= netlink_unicast(rnet
->nl_sock
, skb
, pid
, 0);
278 return (err
< 0) ? err
: 0;
280 EXPORT_SYMBOL(rdma_nl_unicast_wait
);
282 int rdma_nl_multicast(struct net
*net
, struct sk_buff
*skb
,
283 unsigned int group
, gfp_t flags
)
285 struct rdma_dev_net
*rnet
= rdma_net_to_dev_net(net
);
287 return nlmsg_multicast(rnet
->nl_sock
, skb
, 0, group
, flags
);
289 EXPORT_SYMBOL(rdma_nl_multicast
);
291 void rdma_nl_init(void)
295 for (idx
= 0; idx
< RDMA_NL_NUM_CLIENTS
; idx
++)
296 init_rwsem(&rdma_nl_types
[idx
].sem
);
299 void rdma_nl_exit(void)
303 for (idx
= 0; idx
< RDMA_NL_NUM_CLIENTS
; idx
++)
304 WARN(rdma_nl_types
[idx
].cb_table
,
305 "Netlink client %d wasn't released prior to unloading %s\n",
306 idx
, KBUILD_MODNAME
);
309 int rdma_nl_net_init(struct rdma_dev_net
*rnet
)
311 struct net
*net
= read_pnet(&rnet
->net
);
312 struct netlink_kernel_cfg cfg
= {
313 .input
= rdma_nl_rcv
,
317 nls
= netlink_kernel_create(net
, NETLINK_RDMA
, &cfg
);
321 nls
->sk_sndtimeo
= 10 * HZ
;
326 void rdma_nl_net_exit(struct rdma_dev_net
*rnet
)
328 netlink_kernel_release(rnet
->nl_sock
);
331 MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK
, NETLINK_RDMA
);