RDMA/core: Add and expose static device index
[linux-2.6-block.git] / drivers / infiniband / core / netlink.c
CommitLineData
b2cbae2c
RD
1/*
2 * Copyright (c) 2010 Voltaire Inc. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32
33#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
34
b108d976 35#include <linux/export.h>
b2cbae2c
RD
36#include <net/netlink.h>
37#include <net/net_namespace.h>
38#include <net/sock.h>
39#include <rdma/rdma_netlink.h>
233c1955 40#include "core_priv.h"
b2cbae2c 41
c9901724 42#include "core_priv.h"
b2cbae2c 43
c9901724 44static DEFINE_MUTEX(rdma_nl_mutex);
b2cbae2c 45static struct sock *nls;
c9901724 46static struct {
3250b4db 47 const struct rdma_nl_cbs *cb_table;
c9901724 48} rdma_nl_types[RDMA_NL_NUM_CLIENTS];
b2cbae2c 49
ff61c425 50int rdma_nl_chk_listeners(unsigned int group)
bc10ed7d 51{
ff61c425 52 return (netlink_has_listeners(nls, group)) ? 0 : -1;
bc10ed7d 53}
ff61c425 54EXPORT_SYMBOL(rdma_nl_chk_listeners);
bc10ed7d 55
c9901724 56static bool is_nl_msg_valid(unsigned int type, unsigned int op)
b2cbae2c 57{
c9901724
LR
58 static const unsigned int max_num_ops[RDMA_NL_NUM_CLIENTS - 1] = {
59 RDMA_NL_RDMA_CM_NUM_OPS,
60 RDMA_NL_IWPM_NUM_OPS,
61 0,
62 RDMA_NL_LS_NUM_OPS,
63 0 };
b2cbae2c 64
c9901724
LR
65 /*
66 * This BUILD_BUG_ON is intended to catch addition of new
67 * RDMA netlink protocol without updating the array above.
68 */
69 BUILD_BUG_ON(RDMA_NL_NUM_CLIENTS != 6);
b2cbae2c 70
c9901724
LR
71 if (type > RDMA_NL_NUM_CLIENTS - 1)
72 return false;
b2cbae2c 73
c9901724
LR
74 return (op < max_num_ops[type - 1]) ? true : false;
75}
b2cbae2c 76
c9901724
LR
77static bool is_nl_valid(unsigned int type, unsigned int op)
78{
79 if (!is_nl_msg_valid(type, op) ||
80 !rdma_nl_types[type].cb_table ||
81 !rdma_nl_types[type].cb_table[op].dump)
82 return false;
83 return true;
84}
b2cbae2c 85
c9901724 86void rdma_nl_register(unsigned int index,
3250b4db 87 const struct rdma_nl_cbs cb_table[])
c9901724
LR
88{
89 mutex_lock(&rdma_nl_mutex);
90 if (!is_nl_msg_valid(index, 0)) {
91 /*
92 * All clients are not interesting in success/failure of
93 * this call. They want to see the print to error log and
94 * continue their initialization. Print warning for them,
95 * because it is programmer's error to be here.
96 */
97 mutex_unlock(&rdma_nl_mutex);
98 WARN(true,
99 "The not-valid %u index was supplied to RDMA netlink\n",
100 index);
101 return;
102 }
b2cbae2c 103
c9901724
LR
104 if (rdma_nl_types[index].cb_table) {
105 mutex_unlock(&rdma_nl_mutex);
106 WARN(true,
107 "The %u index is already registered in RDMA netlink\n",
108 index);
109 return;
110 }
b2cbae2c 111
c9901724
LR
112 rdma_nl_types[index].cb_table = cb_table;
113 mutex_unlock(&rdma_nl_mutex);
b2cbae2c 114}
c9901724 115EXPORT_SYMBOL(rdma_nl_register);
b2cbae2c 116
c9901724 117void rdma_nl_unregister(unsigned int index)
b2cbae2c 118{
c9901724
LR
119 mutex_lock(&rdma_nl_mutex);
120 rdma_nl_types[index].cb_table = NULL;
121 mutex_unlock(&rdma_nl_mutex);
b2cbae2c 122}
c9901724 123EXPORT_SYMBOL(rdma_nl_unregister);
b2cbae2c
RD
124
125void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
30dc5e63 126 int len, int client, int op, int flags)
b2cbae2c 127{
1a1c116f 128 *nlh = nlmsg_put(skb, 0, seq, RDMA_NL_GET_TYPE(client, op), len, flags);
e0527334 129 if (!*nlh)
1a1c116f 130 return NULL;
e0527334 131 return nlmsg_data(*nlh);
b2cbae2c
RD
132}
133EXPORT_SYMBOL(ibnl_put_msg);
134
135int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh,
136 int len, void *data, int type)
137{
1a1c116f
LR
138 if (nla_put(skb, type, len, data)) {
139 nlmsg_cancel(skb, nlh);
140 return -EMSGSIZE;
141 }
b2cbae2c 142 return 0;
b2cbae2c
RD
143}
144EXPORT_SYMBOL(ibnl_put_attr);
145
3c3e75d5
LR
146static int rdma_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
147 struct netlink_ext_ack *extack)
b2cbae2c 148{
b2cbae2c 149 int type = nlh->nlmsg_type;
c9901724 150 unsigned int index = RDMA_NL_GET_CLIENT(type);
1ae5ccc7 151 unsigned int op = RDMA_NL_GET_OP(type);
c9901724
LR
152 struct netlink_callback cb = {};
153 struct netlink_dump_control c = {};
b2cbae2c 154
c9901724
LR
155 if (!is_nl_valid(index, op))
156 return -EINVAL;
157
e3a2b93d
LR
158 if ((rdma_nl_types[index].cb_table[op].flags & RDMA_NL_ADMIN_PERM) &&
159 !netlink_capable(skb, CAP_NET_ADMIN))
160 return -EPERM;
161
c9901724
LR
162 /*
163 * For response or local service set_timeout request,
164 * there is no need to use netlink_dump_start.
165 */
166 if (!(nlh->nlmsg_flags & NLM_F_REQUEST) ||
167 (index == RDMA_NL_LS && op == RDMA_NL_LS_OP_SET_TIMEOUT)) {
168 cb.skb = skb;
169 cb.nlh = nlh;
170 cb.dump = rdma_nl_types[index].cb_table[op].dump;
c9901724 171 return cb.dump(skb, &cb);
b2cbae2c
RD
172 }
173
c9901724 174 c.dump = rdma_nl_types[index].cb_table[op].dump;
c9901724 175 return netlink_dump_start(nls, skb, nlh, &c);
b2cbae2c
RD
176}
177
3c3e75d5
LR
178/*
179 * This function is similar to netlink_rcv_skb with one exception:
180 * It calls to the callback for the netlink messages without NLM_F_REQUEST
181 * flag. These messages are intended for RDMA_NL_LS consumer, so it is allowed
182 * for that consumer only.
183 */
184static int rdma_nl_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
185 struct nlmsghdr *,
186 struct netlink_ext_ack *))
bc10ed7d 187{
3c3e75d5 188 struct netlink_ext_ack extack = {};
bc10ed7d 189 struct nlmsghdr *nlh;
3c3e75d5 190 int err;
bc10ed7d 191
bc10ed7d 192 while (skb->len >= nlmsg_total_size(0)) {
3c3e75d5
LR
193 int msglen;
194
bc10ed7d 195 nlh = nlmsg_hdr(skb);
3c3e75d5 196 err = 0;
bc10ed7d
KW
197
198 if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len)
3c3e75d5 199 return 0;
bc10ed7d 200
3c3e75d5
LR
201 /*
202 * Generally speaking, the only requests are handled
203 * by the kernel, but RDMA_NL_LS is different, because it
204 * runs backward netlink scheme. Kernel initiates messages
205 * and waits for reply with data to keep pathrecord cache
206 * in sync.
207 */
208 if (!(nlh->nlmsg_flags & NLM_F_REQUEST) &&
209 (RDMA_NL_GET_CLIENT(nlh->nlmsg_type) != RDMA_NL_LS))
210 goto ack;
211
212 /* Skip control messages */
213 if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
214 goto ack;
bc10ed7d 215
3c3e75d5
LR
216 err = cb(skb, nlh, &extack);
217 if (err == -EINTR)
218 goto skip;
bc10ed7d 219
3c3e75d5
LR
220ack:
221 if (nlh->nlmsg_flags & NLM_F_ACK || err)
222 netlink_ack(skb, nlh, err, &extack);
223
224skip:
bc10ed7d
KW
225 msglen = NLMSG_ALIGN(nlh->nlmsg_len);
226 if (msglen > skb->len)
227 msglen = skb->len;
228 skb_pull(skb, msglen);
229 }
3c3e75d5
LR
230
231 return 0;
bc10ed7d
KW
232}
233
3c3e75d5 234static void rdma_nl_rcv(struct sk_buff *skb)
b2cbae2c 235{
c9901724 236 mutex_lock(&rdma_nl_mutex);
3c3e75d5 237 rdma_nl_rcv_skb(skb, &rdma_nl_rcv_msg);
c9901724 238 mutex_unlock(&rdma_nl_mutex);
b2cbae2c
RD
239}
240
f00e6463 241int rdma_nl_unicast(struct sk_buff *skb, u32 pid)
30dc5e63 242{
cea05ead
MI
243 int err;
244
9047811b 245 err = netlink_unicast(nls, skb, pid, MSG_DONTWAIT);
cea05ead 246 return (err < 0) ? err : 0;
30dc5e63 247}
f00e6463 248EXPORT_SYMBOL(rdma_nl_unicast);
30dc5e63 249
f00e6463 250int rdma_nl_unicast_wait(struct sk_buff *skb, __u32 pid)
9047811b
IM
251{
252 int err;
253
254 err = netlink_unicast(nls, skb, pid, 0);
255 return (err < 0) ? err : 0;
256}
f00e6463 257EXPORT_SYMBOL(rdma_nl_unicast_wait);
9047811b 258
4d7f693a 259int rdma_nl_multicast(struct sk_buff *skb, unsigned int group, gfp_t flags)
30dc5e63
TN
260{
261 return nlmsg_multicast(nls, skb, 0, group, flags);
262}
4d7f693a 263EXPORT_SYMBOL(rdma_nl_multicast);
30dc5e63 264
c9901724 265int __init rdma_nl_init(void)
b2cbae2c 266{
a31f2d17 267 struct netlink_kernel_cfg cfg = {
3c3e75d5 268 .input = rdma_nl_rcv,
a31f2d17
PNA
269 };
270
9f00d977 271 nls = netlink_kernel_create(&init_net, NETLINK_RDMA, &cfg);
c9901724 272 if (!nls)
b2cbae2c 273 return -ENOMEM;
b2cbae2c 274
cea05ead 275 nls->sk_sndtimeo = 10 * HZ;
b2cbae2c
RD
276 return 0;
277}
278
c9901724 279void rdma_nl_exit(void)
b2cbae2c 280{
c9901724 281 int idx;
b2cbae2c 282
c9901724
LR
283 for (idx = 0; idx < RDMA_NL_NUM_CLIENTS; idx++)
284 rdma_nl_unregister(idx);
b2cbae2c
RD
285
286 netlink_kernel_release(nls);
287}