| 1 | |
| 2 | * Copyright (c) 2006, 2019 Oracle and/or its affiliates. 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 | #include <linux/kernel.h>
|
| 34 | #include <linux/in.h>
|
| 35 | #include <linux/if.h>
|
| 36 | #include <linux/netdevice.h>
|
| 37 | #include <linux/inetdevice.h>
|
| 38 | #include <linux/if_arp.h>
|
| 39 | #include <linux/delay.h>
|
| 40 | #include <linux/slab.h>
|
| 41 | #include <linux/module.h>
|
| 42 | #include <net/addrconf.h>
|
| 43 |
|
| 44 | #include "rds_single_path.h"
|
| 45 | #include "rds.h"
|
| 46 | #include "ib.h"
|
| 47 | #include "ib_mr.h"
|
| 48 |
|
| 49 | static unsigned int rds_ib_mr_1m_pool_size = RDS_MR_1M_POOL_SIZE;
|
| 50 | static unsigned int rds_ib_mr_8k_pool_size = RDS_MR_8K_POOL_SIZE;
|
| 51 | unsigned int rds_ib_retry_count = RDS_IB_DEFAULT_RETRY_COUNT;
|
| 52 | static atomic_t rds_ib_unloading;
|
| 53 |
|
| 54 | module_param(rds_ib_mr_1m_pool_size, int, 0444);
|
| 55 | MODULE_PARM_DESC(rds_ib_mr_1m_pool_size, " Max number of 1M mr per HCA");
|
| 56 | module_param(rds_ib_mr_8k_pool_size, int, 0444);
|
| 57 | MODULE_PARM_DESC(rds_ib_mr_8k_pool_size, " Max number of 8K mr per HCA");
|
| 58 | module_param(rds_ib_retry_count, int, 0444);
|
| 59 | MODULE_PARM_DESC(rds_ib_retry_count, " Number of hw retries before reporting an error");
|
| 60 |
|
| 61 | |
| 62 | * we have a clumsy combination of RCU and a rwsem protecting this list
|
| 63 | * because it is used both in the get_mr fast path and while blocking in
|
| 64 | * the FMR flushing path.
|
| 65 |
|
| 66 | DECLARE_RWSEM(rds_ib_devices_lock);
|
| 67 | struct list_head rds_ib_devices;
|
| 68 |
|
| 69 |
|
| 70 | DEFINE_SPINLOCK(ib_nodev_conns_lock);
|
| 71 | LIST_HEAD(ib_nodev_conns);
|
| 72 |
|
| 73 | static void rds_ib_nodev_connect(void)
|
| 74 | {
|
| 75 | struct rds_ib_connection *ic;
|
| 76 |
|
| 77 | spin_lock(&ib_nodev_conns_lock);
|
| 78 | list_for_each_entry(ic, &ib_nodev_conns, ib_node)
|
| 79 | rds_conn_connect_if_down(ic->conn);
|
| 80 | spin_unlock(&ib_nodev_conns_lock);
|
| 81 | }
|
| 82 |
|
| 83 | static void rds_ib_dev_shutdown(struct rds_ib_device *rds_ibdev)
|
| 84 | {
|
| 85 | struct rds_ib_connection *ic;
|
| 86 | unsigned long flags;
|
| 87 |
|
| 88 | spin_lock_irqsave(&rds_ibdev->spinlock, flags);
|
| 89 | list_for_each_entry(ic, &rds_ibdev->conn_list, ib_node)
|
| 90 | rds_conn_path_drop(&ic->conn->c_path[0], true);
|
| 91 | spin_unlock_irqrestore(&rds_ibdev->spinlock, flags);
|
| 92 | }
|
| 93 |
|
| 94 | |
| 95 | * rds_ib_destroy_mr_pool() blocks on a few things and mrs drop references
|
| 96 | * from interrupt context so we push freing off into a work struct in krdsd.
|
| 97 |
|
| 98 | static void rds_ib_dev_free(struct work_struct *work)
|
| 99 | {
|
| 100 | struct rds_ib_ipaddr *i_ipaddr, *i_next;
|
| 101 | struct rds_ib_device *rds_ibdev = container_of(work,
|
| 102 | struct rds_ib_device, free_work);
|
| 103 |
|
| 104 | if (rds_ibdev->mr_8k_pool)
|
| 105 | rds_ib_destroy_mr_pool(rds_ibdev->mr_8k_pool);
|
| 106 | if (rds_ibdev->mr_1m_pool)
|
| 107 | rds_ib_destroy_mr_pool(rds_ibdev->mr_1m_pool);
|
| 108 | if (rds_ibdev->pd)
|
| 109 | ib_dealloc_pd(rds_ibdev->pd);
|
| 110 |
|
| 111 | list_for_each_entry_safe(i_ipaddr, i_next, &rds_ibdev->ipaddr_list, list) {
|
| 112 | list_del(&i_ipaddr->list);
|
| 113 | kfree(i_ipaddr);
|
| 114 | }
|
| 115 |
|
| 116 | kfree(rds_ibdev->vector_load);
|
| 117 |
|
| 118 | kfree(rds_ibdev);
|
| 119 | }
|
| 120 |
|
| 121 | void rds_ib_dev_put(struct rds_ib_device *rds_ibdev)
|
| 122 | {
|
| 123 | BUG_ON(refcount_read(&rds_ibdev->refcount) == 0);
|
| 124 | if (refcount_dec_and_test(&rds_ibdev->refcount))
|
| 125 | queue_work(rds_wq, &rds_ibdev->free_work);
|
| 126 | }
|
| 127 |
|
| 128 | static int rds_ib_add_one(struct ib_device *device)
|
| 129 | {
|
| 130 | struct rds_ib_device *rds_ibdev;
|
| 131 | int ret;
|
| 132 |
|
| 133 |
|
| 134 | if (device->node_type != RDMA_NODE_IB_CA)
|
| 135 | return -EOPNOTSUPP;
|
| 136 |
|
| 137 |
|
| 138 | if (!(device->attrs.device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS))
|
| 139 | return -EOPNOTSUPP;
|
| 140 |
|
| 141 | rds_ibdev = kzalloc_node(sizeof(struct rds_ib_device), GFP_KERNEL,
|
| 142 | ibdev_to_node(device));
|
| 143 | if (!rds_ibdev)
|
| 144 | return -ENOMEM;
|
| 145 |
|
| 146 | spin_lock_init(&rds_ibdev->spinlock);
|
| 147 | refcount_set(&rds_ibdev->refcount, 1);
|
| 148 | INIT_WORK(&rds_ibdev->free_work, rds_ib_dev_free);
|
| 149 |
|
| 150 | INIT_LIST_HEAD(&rds_ibdev->ipaddr_list);
|
| 151 | INIT_LIST_HEAD(&rds_ibdev->conn_list);
|
| 152 |
|
| 153 | rds_ibdev->max_wrs = device->attrs.max_qp_wr;
|
| 154 | rds_ibdev->max_sge = min(device->attrs.max_send_sge, RDS_IB_MAX_SGE);
|
| 155 |
|
| 156 | rds_ibdev->odp_capable =
|
| 157 | !!(device->attrs.kernel_cap_flags &
|
| 158 | IBK_ON_DEMAND_PAGING) &&
|
| 159 | !!(device->attrs.odp_caps.per_transport_caps.rc_odp_caps &
|
| 160 | IB_ODP_SUPPORT_WRITE) &&
|
| 161 | !!(device->attrs.odp_caps.per_transport_caps.rc_odp_caps &
|
| 162 | IB_ODP_SUPPORT_READ);
|
| 163 |
|
| 164 | rds_ibdev->max_1m_mrs = device->attrs.max_mr ?
|
| 165 | min(device->attrs.max_mr / 2,
|
| 166 | rds_ib_mr_1m_pool_size) : rds_ib_mr_1m_pool_size;
|
| 167 |
|
| 168 | rds_ibdev->max_8k_mrs = device->attrs.max_mr ?
|
| 169 | min((device->attrs.max_mr / 2) * RDS_MR_8K_SCALE,
|
| 170 | rds_ib_mr_8k_pool_size) : rds_ib_mr_8k_pool_size;
|
| 171 |
|
| 172 | rds_ibdev->max_initiator_depth = device->attrs.max_qp_init_rd_atom;
|
| 173 | rds_ibdev->max_responder_resources = device->attrs.max_qp_rd_atom;
|
| 174 |
|
| 175 | rds_ibdev->vector_load = kzalloc_objs(int, device->num_comp_vectors);
|
| 176 | if (!rds_ibdev->vector_load) {
|
| 177 | pr_err("RDS/IB: %s failed to allocate vector memory\n",
|
| 178 | __func__);
|
| 179 | ret = -ENOMEM;
|
| 180 | goto put_dev;
|
| 181 | }
|
| 182 |
|
| 183 | rds_ibdev->dev = device;
|
| 184 | rds_ibdev->pd = ib_alloc_pd(device, 0);
|
| 185 | if (IS_ERR(rds_ibdev->pd)) {
|
| 186 | ret = PTR_ERR(rds_ibdev->pd);
|
| 187 | rds_ibdev->pd = NULL;
|
| 188 | goto put_dev;
|
| 189 | }
|
| 190 |
|
| 191 | rds_ibdev->mr_1m_pool =
|
| 192 | rds_ib_create_mr_pool(rds_ibdev, RDS_IB_MR_1M_POOL);
|
| 193 | if (IS_ERR(rds_ibdev->mr_1m_pool)) {
|
| 194 | ret = PTR_ERR(rds_ibdev->mr_1m_pool);
|
| 195 | rds_ibdev->mr_1m_pool = NULL;
|
| 196 | goto put_dev;
|
| 197 | }
|
| 198 |
|
| 199 | rds_ibdev->mr_8k_pool =
|
| 200 | rds_ib_create_mr_pool(rds_ibdev, RDS_IB_MR_8K_POOL);
|
| 201 | if (IS_ERR(rds_ibdev->mr_8k_pool)) {
|
| 202 | ret = PTR_ERR(rds_ibdev->mr_8k_pool);
|
| 203 | rds_ibdev->mr_8k_pool = NULL;
|
| 204 | goto put_dev;
|
| 205 | }
|
| 206 |
|
| 207 | rdsdebug("RDS/IB: max_mr = %u, max_wrs = %d, max_sge = %d, max_1m_mrs = %d, max_8k_mrs = %d\n",
|
| 208 | device->attrs.max_mr, rds_ibdev->max_wrs, rds_ibdev->max_sge,
|
| 209 | rds_ibdev->max_1m_mrs, rds_ibdev->max_8k_mrs);
|
| 210 |
|
| 211 | pr_info("RDS/IB: %s: added\n", device->name);
|
| 212 |
|
| 213 | down_write(&rds_ib_devices_lock);
|
| 214 | list_add_tail_rcu(&rds_ibdev->list, &rds_ib_devices);
|
| 215 | up_write(&rds_ib_devices_lock);
|
| 216 | refcount_inc(&rds_ibdev->refcount);
|
| 217 |
|
| 218 | ib_set_client_data(device, &rds_ib_client, rds_ibdev);
|
| 219 |
|
| 220 | rds_ib_nodev_connect();
|
| 221 | return 0;
|
| 222 |
|
| 223 | put_dev:
|
| 224 | rds_ib_dev_put(rds_ibdev);
|
| 225 | return ret;
|
| 226 | }
|
| 227 |
|
| 228 | |
| 229 | * New connections use this to find the device to associate with the
|
| 230 | * connection. It's not in the fast path so we're not concerned about the
|
| 231 | * performance of the IB call. (As of this writing, it uses an interrupt
|
| 232 | * blocking spinlock to serialize walking a per-device list of all registered
|
| 233 | * clients.)
|
| 234 | *
|
| 235 | * RCU is used to handle incoming connections racing with device teardown.
|
| 236 | * Rather than use a lock to serialize removal from the client_data and
|
| 237 | * getting a new reference, we use an RCU grace period. The destruction
|
| 238 | * path removes the device from client_data and then waits for all RCU
|
| 239 | * readers to finish.
|
| 240 | *
|
| 241 | * A new connection can get NULL from this if its arriving on a
|
| 242 | * device that is in the process of being removed.
|
| 243 |
|
| 244 | struct rds_ib_device *rds_ib_get_client_data(struct ib_device *device)
|
| 245 | {
|
| 246 | struct rds_ib_device *rds_ibdev;
|
| 247 |
|
| 248 | rcu_read_lock();
|
| 249 | rds_ibdev = ib_get_client_data(device, &rds_ib_client);
|
| 250 | if (rds_ibdev)
|
| 251 | refcount_inc(&rds_ibdev->refcount);
|
| 252 | rcu_read_unlock();
|
| 253 | return rds_ibdev;
|
| 254 | }
|
| 255 |
|
| 256 | |
| 257 | * The IB stack is letting us know that a device is going away. This can
|
| 258 | * happen if the underlying HCA driver is removed or if PCI hotplug is removing
|
| 259 | * the pci function, for example.
|
| 260 | *
|
| 261 | * This can be called at any time and can be racing with any other RDS path.
|
| 262 |
|
| 263 | static void rds_ib_remove_one(struct ib_device *device, void *client_data)
|
| 264 | {
|
| 265 | struct rds_ib_device *rds_ibdev = client_data;
|
| 266 |
|
| 267 | rds_ib_dev_shutdown(rds_ibdev);
|
| 268 |
|
| 269 |
|
| 270 | ib_set_client_data(device, &rds_ib_client, NULL);
|
| 271 |
|
| 272 | down_write(&rds_ib_devices_lock);
|
| 273 | list_del_rcu(&rds_ibdev->list);
|
| 274 | up_write(&rds_ib_devices_lock);
|
| 275 |
|
| 276 | |
| 277 | * This synchronize rcu is waiting for readers of both the ib
|
| 278 | * client data and the devices list to finish before we drop
|
| 279 | * both of those references.
|
| 280 |
|
| 281 | synchronize_rcu();
|
| 282 | rds_ib_dev_put(rds_ibdev);
|
| 283 | rds_ib_dev_put(rds_ibdev);
|
| 284 | }
|
| 285 |
|
| 286 | struct ib_client rds_ib_client = {
|
| 287 | .name = "rds_ib",
|
| 288 | .add = rds_ib_add_one,
|
| 289 | .remove = rds_ib_remove_one
|
| 290 | };
|
| 291 |
|
| 292 | static int rds_ib_conn_info_visitor(struct rds_connection *conn,
|
| 293 | void *buffer)
|
| 294 | {
|
| 295 | struct rds_info_rdma_connection *iinfo = buffer;
|
| 296 | struct rds_ib_connection *ic = conn->c_transport_data;
|
| 297 |
|
| 298 |
|
| 299 | if (conn->c_trans != &rds_ib_transport)
|
| 300 | return 0;
|
| 301 | if (conn->c_isv6)
|
| 302 | return 0;
|
| 303 |
|
| 304 | iinfo->src_addr = conn->c_laddr.s6_addr32[3];
|
| 305 | iinfo->dst_addr = conn->c_faddr.s6_addr32[3];
|
| 306 | if (ic) {
|
| 307 | iinfo->tos = conn->c_tos;
|
| 308 | iinfo->sl = ic->i_sl;
|
| 309 | }
|
| 310 |
|
| 311 | memset(&iinfo->src_gid, 0, sizeof(iinfo->src_gid));
|
| 312 | memset(&iinfo->dst_gid, 0, sizeof(iinfo->dst_gid));
|
| 313 | if (rds_conn_state(conn) == RDS_CONN_UP) {
|
| 314 | struct rds_ib_device *rds_ibdev;
|
| 315 |
|
| 316 | rdma_read_gids(ic->i_cm_id, (union ib_gid *)&iinfo->src_gid,
|
| 317 | (union ib_gid *)&iinfo->dst_gid);
|
| 318 |
|
| 319 | rds_ibdev = ic->rds_ibdev;
|
| 320 | iinfo->max_send_wr = ic->i_send_ring.w_nr;
|
| 321 | iinfo->max_recv_wr = ic->i_recv_ring.w_nr;
|
| 322 | iinfo->max_send_sge = rds_ibdev->max_sge;
|
| 323 | rds_ib_get_mr_info(rds_ibdev, iinfo);
|
| 324 | iinfo->cache_allocs = atomic_read(&ic->i_cache_allocs);
|
| 325 | }
|
| 326 | return 1;
|
| 327 | }
|
| 328 |
|
| 329 | #if IS_ENABLED(CONFIG_IPV6)
|
| 330 |
|
| 331 | static int rds6_ib_conn_info_visitor(struct rds_connection *conn,
|
| 332 | void *buffer)
|
| 333 | {
|
| 334 | struct rds6_info_rdma_connection *iinfo6 = buffer;
|
| 335 | struct rds_ib_connection *ic = conn->c_transport_data;
|
| 336 |
|
| 337 |
|
| 338 | if (conn->c_trans != &rds_ib_transport)
|
| 339 | return 0;
|
| 340 |
|
| 341 | iinfo6->src_addr = conn->c_laddr;
|
| 342 | iinfo6->dst_addr = conn->c_faddr;
|
| 343 | if (ic) {
|
| 344 | iinfo6->tos = conn->c_tos;
|
| 345 | iinfo6->sl = ic->i_sl;
|
| 346 | }
|
| 347 |
|
| 348 | memset(&iinfo6->src_gid, 0, sizeof(iinfo6->src_gid));
|
| 349 | memset(&iinfo6->dst_gid, 0, sizeof(iinfo6->dst_gid));
|
| 350 |
|
| 351 | if (rds_conn_state(conn) == RDS_CONN_UP) {
|
| 352 | struct rds_ib_device *rds_ibdev;
|
| 353 |
|
| 354 | rdma_read_gids(ic->i_cm_id, (union ib_gid *)&iinfo6->src_gid,
|
| 355 | (union ib_gid *)&iinfo6->dst_gid);
|
| 356 | rds_ibdev = ic->rds_ibdev;
|
| 357 | iinfo6->max_send_wr = ic->i_send_ring.w_nr;
|
| 358 | iinfo6->max_recv_wr = ic->i_recv_ring.w_nr;
|
| 359 | iinfo6->max_send_sge = rds_ibdev->max_sge;
|
| 360 | rds6_ib_get_mr_info(rds_ibdev, iinfo6);
|
| 361 | iinfo6->cache_allocs = atomic_read(&ic->i_cache_allocs);
|
| 362 | }
|
| 363 | return 1;
|
| 364 | }
|
| 365 | #endif
|
| 366 |
|
| 367 | static void rds_ib_ic_info(struct socket *sock, unsigned int len,
|
| 368 | struct rds_info_iterator *iter,
|
| 369 | struct rds_info_lengths *lens)
|
| 370 | {
|
| 371 | u64 buffer[(sizeof(struct rds_info_rdma_connection) + 7) / 8];
|
| 372 |
|
| 373 | rds_for_each_conn_info(sock, len, iter, lens,
|
| 374 | rds_ib_conn_info_visitor,
|
| 375 | buffer,
|
| 376 | sizeof(struct rds_info_rdma_connection));
|
| 377 | }
|
| 378 |
|
| 379 | #if IS_ENABLED(CONFIG_IPV6)
|
| 380 |
|
| 381 | static void rds6_ib_ic_info(struct socket *sock, unsigned int len,
|
| 382 | struct rds_info_iterator *iter,
|
| 383 | struct rds_info_lengths *lens)
|
| 384 | {
|
| 385 | u64 buffer[(sizeof(struct rds6_info_rdma_connection) + 7) / 8];
|
| 386 |
|
| 387 | rds_for_each_conn_info(sock, len, iter, lens,
|
| 388 | rds6_ib_conn_info_visitor,
|
| 389 | buffer,
|
| 390 | sizeof(struct rds6_info_rdma_connection));
|
| 391 | }
|
| 392 | #endif
|
| 393 |
|
| 394 | |
| 395 | * Early RDS/IB was built to only bind to an address if there is an IPoIB
|
| 396 | * device with that address set.
|
| 397 | *
|
| 398 | * If it were me, I'd advocate for something more flexible. Sending and
|
| 399 | * receiving should be device-agnostic. Transports would try and maintain
|
| 400 | * connections between peers who have messages queued. Userspace would be
|
| 401 | * allowed to influence which paths have priority. We could call userspace
|
| 402 | * asserting this policy "routing".
|
| 403 |
|
| 404 | static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr,
|
| 405 | __u32 scope_id)
|
| 406 | {
|
| 407 | int ret;
|
| 408 | struct rdma_cm_id *cm_id;
|
| 409 | #if IS_ENABLED(CONFIG_IPV6)
|
| 410 | struct sockaddr_in6 sin6;
|
| 411 | #endif
|
| 412 | struct sockaddr_in sin;
|
| 413 | struct sockaddr *sa;
|
| 414 | bool isv4;
|
| 415 |
|
| 416 | isv4 = ipv6_addr_v4mapped(addr);
|
| 417 | |
| 418 | * IB and iWARP capable NICs.
|
| 419 |
|
| 420 | cm_id = rdma_create_id(&init_net, rds_rdma_cm_event_handler,
|
| 421 | NULL, RDMA_PS_TCP, IB_QPT_RC);
|
| 422 | if (IS_ERR(cm_id))
|
| 423 | return PTR_ERR(cm_id);
|
| 424 |
|
| 425 | if (isv4) {
|
| 426 | memset(&sin, 0, sizeof(sin));
|
| 427 | sin.sin_family = AF_INET;
|
| 428 | sin.sin_addr.s_addr = addr->s6_addr32[3];
|
| 429 | sa = (struct sockaddr *)&sin;
|
| 430 | } else {
|
| 431 | #if IS_ENABLED(CONFIG_IPV6)
|
| 432 | if (!ipv6_mod_enabled()) {
|
| 433 | ret = -EADDRNOTAVAIL;
|
| 434 | goto out;
|
| 435 | }
|
| 436 | memset(&sin6, 0, sizeof(sin6));
|
| 437 | sin6.sin6_family = AF_INET6;
|
| 438 | sin6.sin6_addr = *addr;
|
| 439 | sin6.sin6_scope_id = scope_id;
|
| 440 | sa = (struct sockaddr *)&sin6;
|
| 441 |
|
| 442 | |
| 443 | * reason is that rdma_bind_addr() always succeeds with IPv6
|
| 444 | * link local address regardless it is indeed configured in a
|
| 445 | * system.
|
| 446 |
|
| 447 | if (ipv6_addr_type(addr) & IPV6_ADDR_LINKLOCAL) {
|
| 448 | struct net_device *dev;
|
| 449 |
|
| 450 | if (scope_id == 0) {
|
| 451 | ret = -EADDRNOTAVAIL;
|
| 452 | goto out;
|
| 453 | }
|
| 454 |
|
| 455 | |
| 456 | * name space aware.
|
| 457 |
|
| 458 | dev = dev_get_by_index(&init_net, scope_id);
|
| 459 | if (!dev) {
|
| 460 | ret = -EADDRNOTAVAIL;
|
| 461 | goto out;
|
| 462 | }
|
| 463 | if (!ipv6_chk_addr(&init_net, addr, dev, 1)) {
|
| 464 | dev_put(dev);
|
| 465 | ret = -EADDRNOTAVAIL;
|
| 466 | goto out;
|
| 467 | }
|
| 468 | dev_put(dev);
|
| 469 | }
|
| 470 | #else
|
| 471 | ret = -EADDRNOTAVAIL;
|
| 472 | goto out;
|
| 473 | #endif
|
| 474 | }
|
| 475 |
|
| 476 |
|
| 477 | ret = rdma_bind_addr(cm_id, sa);
|
| 478 | |
| 479 | check node_type.
|
| 480 | if (ret || !cm_id->device ||
|
| 481 | cm_id->device->node_type != RDMA_NODE_IB_CA)
|
| 482 | ret = -EADDRNOTAVAIL;
|
| 483 |
|
| 484 | rdsdebug("addr %pI6c%%%u ret %d node type %d\n",
|
| 485 | addr, scope_id, ret,
|
| 486 | cm_id->device ? cm_id->device->node_type : -1);
|
| 487 |
|
| 488 | out:
|
| 489 | rdma_destroy_id(cm_id);
|
| 490 |
|
| 491 | return ret;
|
| 492 | }
|
| 493 |
|
| 494 | static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr,
|
| 495 | __u32 scope_id)
|
| 496 | {
|
| 497 | struct rds_ib_device *rds_ibdev = NULL;
|
| 498 |
|
| 499 |
|
| 500 | if (!net_eq(net, &init_net))
|
| 501 | return -EPROTOTYPE;
|
| 502 |
|
| 503 | if (ipv6_addr_v4mapped(addr)) {
|
| 504 | rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]);
|
| 505 | if (rds_ibdev) {
|
| 506 | rds_ib_dev_put(rds_ibdev);
|
| 507 | return 0;
|
| 508 | }
|
| 509 | }
|
| 510 |
|
| 511 | return rds_ib_laddr_check_cm(net, addr, scope_id);
|
| 512 | }
|
| 513 |
|
| 514 | static void rds_ib_unregister_client(void)
|
| 515 | {
|
| 516 | ib_unregister_client(&rds_ib_client);
|
| 517 |
|
| 518 | flush_workqueue(rds_wq);
|
| 519 | }
|
| 520 |
|
| 521 | static void rds_ib_set_unloading(void)
|
| 522 | {
|
| 523 | atomic_set(&rds_ib_unloading, 1);
|
| 524 | }
|
| 525 |
|
| 526 | static bool rds_ib_is_unloading(struct rds_connection *conn)
|
| 527 | {
|
| 528 | struct rds_conn_path *cp = &conn->c_path[0];
|
| 529 |
|
| 530 | return (test_bit(RDS_DESTROY_PENDING, &cp->cp_flags) ||
|
| 531 | atomic_read(&rds_ib_unloading) != 0);
|
| 532 | }
|
| 533 |
|
| 534 | void rds_ib_exit(void)
|
| 535 | {
|
| 536 | rds_ib_set_unloading();
|
| 537 | synchronize_rcu();
|
| 538 | rds_info_deregister_func(RDS_INFO_IB_CONNECTIONS, rds_ib_ic_info);
|
| 539 | #if IS_ENABLED(CONFIG_IPV6)
|
| 540 | rds_info_deregister_func(RDS6_INFO_IB_CONNECTIONS, rds6_ib_ic_info);
|
| 541 | #endif
|
| 542 | rds_ib_unregister_client();
|
| 543 | rds_ib_destroy_nodev_conns();
|
| 544 | rds_ib_sysctl_exit();
|
| 545 | rds_ib_recv_exit();
|
| 546 | rds_trans_unregister(&rds_ib_transport);
|
| 547 | rds_ib_mr_exit();
|
| 548 | }
|
| 549 |
|
| 550 | static u8 rds_ib_get_tos_map(u8 tos)
|
| 551 | {
|
| 552 | |
| 553 | * In future, if custom map is desired, hook can export
|
| 554 | * user configurable map.
|
| 555 |
|
| 556 | return tos;
|
| 557 | }
|
| 558 |
|
| 559 | struct rds_transport rds_ib_transport = {
|
| 560 | .laddr_check = rds_ib_laddr_check,
|
| 561 | .xmit_path_complete = rds_ib_xmit_path_complete,
|
| 562 | .xmit = rds_ib_xmit,
|
| 563 | .xmit_rdma = rds_ib_xmit_rdma,
|
| 564 | .xmit_atomic = rds_ib_xmit_atomic,
|
| 565 | .recv_path = rds_ib_recv_path,
|
| 566 | .conn_alloc = rds_ib_conn_alloc,
|
| 567 | .conn_free = rds_ib_conn_free,
|
| 568 | .conn_path_connect = rds_ib_conn_path_connect,
|
| 569 | .conn_path_shutdown = rds_ib_conn_path_shutdown,
|
| 570 | .inc_copy_to_user = rds_ib_inc_copy_to_user,
|
| 571 | .inc_free = rds_ib_inc_free,
|
| 572 | .cm_initiate_connect = rds_ib_cm_initiate_connect,
|
| 573 | .cm_handle_connect = rds_ib_cm_handle_connect,
|
| 574 | .cm_connect_complete = rds_ib_cm_connect_complete,
|
| 575 | .stats_info_copy = rds_ib_stats_info_copy,
|
| 576 | .exit = rds_ib_exit,
|
| 577 | .get_mr = rds_ib_get_mr,
|
| 578 | .sync_mr = rds_ib_sync_mr,
|
| 579 | .free_mr = rds_ib_free_mr,
|
| 580 | .flush_mrs = rds_ib_flush_mrs,
|
| 581 | .get_tos_map = rds_ib_get_tos_map,
|
| 582 | .t_owner = THIS_MODULE,
|
| 583 | .t_name = "infiniband",
|
| 584 | .t_unloading = rds_ib_is_unloading,
|
| 585 | .t_type = RDS_TRANS_IB
|
| 586 | };
|
| 587 |
|
| 588 | int rds_ib_init(void)
|
| 589 | {
|
| 590 | int ret;
|
| 591 |
|
| 592 | INIT_LIST_HEAD(&rds_ib_devices);
|
| 593 |
|
| 594 | ret = rds_ib_mr_init();
|
| 595 | if (ret)
|
| 596 | goto out;
|
| 597 |
|
| 598 | ret = ib_register_client(&rds_ib_client);
|
| 599 | if (ret)
|
| 600 | goto out_mr_exit;
|
| 601 |
|
| 602 | ret = rds_ib_sysctl_init();
|
| 603 | if (ret)
|
| 604 | goto out_ibreg;
|
| 605 |
|
| 606 | ret = rds_ib_recv_init();
|
| 607 | if (ret)
|
| 608 | goto out_sysctl;
|
| 609 |
|
| 610 | rds_trans_register(&rds_ib_transport);
|
| 611 |
|
| 612 | rds_info_register_func(RDS_INFO_IB_CONNECTIONS, rds_ib_ic_info);
|
| 613 | #if IS_ENABLED(CONFIG_IPV6)
|
| 614 | rds_info_register_func(RDS6_INFO_IB_CONNECTIONS, rds6_ib_ic_info);
|
| 615 | #endif
|
| 616 |
|
| 617 | goto out;
|
| 618 |
|
| 619 | out_sysctl:
|
| 620 | rds_ib_sysctl_exit();
|
| 621 | out_ibreg:
|
| 622 | rds_ib_unregister_client();
|
| 623 | out_mr_exit:
|
| 624 | rds_ib_mr_exit();
|
| 625 | out:
|
| 626 | return ret;
|
| 627 | }
|
| 628 |
|
| 629 | MODULE_LICENSE("GPL");
|