1 /* 2 * Copyright (c) 2009, 2018 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/module.h> 34 #include <rdma/rdma_cm.h> 35 36 #include "rds_single_path.h" 37 #include "rdma_transport.h" 38 #include "ib.h" 39 40 /* Global IPv4 and IPv6 RDS RDMA listener cm_id */ 41 static struct rdma_cm_id *rds_rdma_listen_id; 42 #if IS_ENABLED(CONFIG_IPV6) 43 static struct rdma_cm_id *rds6_rdma_listen_id; 44 #endif 45 46 static int rds_rdma_cm_event_handler_cmn(struct rdma_cm_id *cm_id, 47 struct rdma_cm_event *event, 48 bool isv6) 49 { 50 /* this can be null in the listening path */ 51 struct rds_connection *conn = cm_id->context; 52 struct rds_transport *trans; 53 int ret = 0; 54 55 rdsdebug("conn %p id %p handling event %u (%s)\n", conn, cm_id, 56 event->event, rdma_event_msg(event->event)); 57 58 if (cm_id->device->node_type == RDMA_NODE_IB_CA) 59 trans = &rds_ib_transport; 60 61 /* Prevent shutdown from tearing down the connection 62 * while we're executing. */ 63 if (conn) { 64 mutex_lock(&conn->c_cm_lock); 65 66 /* If the connection is being shut down, bail out 67 * right away. We return 0 so cm_id doesn't get 68 * destroyed prematurely */ 69 if (rds_conn_state(conn) == RDS_CONN_DISCONNECTING) { 70 /* Reject incoming connections while we're tearing 71 * down an existing one. */ 72 if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) 73 ret = 1; 74 goto out; 75 } 76 } 77 78 switch (event->event) { 79 case RDMA_CM_EVENT_CONNECT_REQUEST: 80 ret = trans->cm_handle_connect(cm_id, event, isv6); 81 break; 82 83 case RDMA_CM_EVENT_ADDR_RESOLVED: 84 /* XXX do we need to clean up if this fails? */ 85 ret = rdma_resolve_route(cm_id, 86 RDS_RDMA_RESOLVE_TIMEOUT_MS); 87 break; 88 89 case RDMA_CM_EVENT_ROUTE_RESOLVED: 90 /* Connection could have been dropped so make sure the 91 * cm_id is valid before proceeding 92 */ 93 if (conn) { 94 struct rds_ib_connection *ibic; 95 96 ibic = conn->c_transport_data; 97 if (ibic && ibic->i_cm_id == cm_id) 98 ret = trans->cm_initiate_connect(cm_id, isv6); 99 else 100 rds_conn_drop(conn); 101 } 102 break; 103 104 case RDMA_CM_EVENT_ESTABLISHED: 105 trans->cm_connect_complete(conn, event); 106 break; 107 108 case RDMA_CM_EVENT_REJECTED: 109 rdsdebug("Connection rejected: %s\n", 110 rdma_reject_msg(cm_id, event->status)); 111 /* FALLTHROUGH */ 112 case RDMA_CM_EVENT_ADDR_ERROR: 113 case RDMA_CM_EVENT_ROUTE_ERROR: 114 case RDMA_CM_EVENT_CONNECT_ERROR: 115 case RDMA_CM_EVENT_UNREACHABLE: 116 case RDMA_CM_EVENT_DEVICE_REMOVAL: 117 case RDMA_CM_EVENT_ADDR_CHANGE: 118 if (conn) 119 rds_conn_drop(conn); 120 break; 121 122 case RDMA_CM_EVENT_DISCONNECTED: 123 rdsdebug("DISCONNECT event - dropping connection " 124 "%pI6c->%pI6c\n", &conn->c_laddr, 125 &conn->c_faddr); 126 rds_conn_drop(conn); 127 break; 128 129 case RDMA_CM_EVENT_TIMEWAIT_EXIT: 130 if (conn) { 131 pr_info("RDS: RDMA_CM_EVENT_TIMEWAIT_EXIT event: dropping connection %pI6c->%pI6c\n", 132 &conn->c_laddr, &conn->c_faddr); 133 rds_conn_drop(conn); 134 } 135 break; 136 137 default: 138 /* things like device disconnect? */ 139 printk(KERN_ERR "RDS: unknown event %u (%s)!\n", 140 event->event, rdma_event_msg(event->event)); 141 break; 142 } 143 144 out: 145 if (conn) 146 mutex_unlock(&conn->c_cm_lock); 147 148 rdsdebug("id %p event %u (%s) handling ret %d\n", cm_id, event->event, 149 rdma_event_msg(event->event), ret); 150 151 return ret; 152 } 153 154 int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id, 155 struct rdma_cm_event *event) 156 { 157 return rds_rdma_cm_event_handler_cmn(cm_id, event, false); 158 } 159 160 #if IS_ENABLED(CONFIG_IPV6) 161 int rds6_rdma_cm_event_handler(struct rdma_cm_id *cm_id, 162 struct rdma_cm_event *event) 163 { 164 return rds_rdma_cm_event_handler_cmn(cm_id, event, true); 165 } 166 #endif 167 168 static int rds_rdma_listen_init_common(rdma_cm_event_handler handler, 169 struct sockaddr *sa, 170 struct rdma_cm_id **ret_cm_id) 171 { 172 struct rdma_cm_id *cm_id; 173 int ret; 174 175 cm_id = rdma_create_id(&init_net, handler, NULL, 176 RDMA_PS_TCP, IB_QPT_RC); 177 if (IS_ERR(cm_id)) { 178 ret = PTR_ERR(cm_id); 179 printk(KERN_ERR "RDS/RDMA: failed to setup listener, " 180 "rdma_create_id() returned %d\n", ret); 181 return ret; 182 } 183 184 /* 185 * XXX I bet this binds the cm_id to a device. If we want to support 186 * fail-over we'll have to take this into consideration. 187 */ 188 ret = rdma_bind_addr(cm_id, sa); 189 if (ret) { 190 printk(KERN_ERR "RDS/RDMA: failed to setup listener, " 191 "rdma_bind_addr() returned %d\n", ret); 192 goto out; 193 } 194 195 ret = rdma_listen(cm_id, 128); 196 if (ret) { 197 printk(KERN_ERR "RDS/RDMA: failed to setup listener, " 198 "rdma_listen() returned %d\n", ret); 199 goto out; 200 } 201 202 rdsdebug("cm %p listening on port %u\n", cm_id, RDS_PORT); 203 204 *ret_cm_id = cm_id; 205 cm_id = NULL; 206 out: 207 if (cm_id) 208 rdma_destroy_id(cm_id); 209 return ret; 210 } 211 212 /* Initialize the RDS RDMA listeners. We create two listeners for 213 * compatibility reason. The one on RDS_PORT is used for IPv4 214 * requests only. The one on RDS_CM_PORT is used for IPv6 requests 215 * only. So only IPv6 enabled RDS module will communicate using this 216 * port. 217 */ 218 static int rds_rdma_listen_init(void) 219 { 220 int ret; 221 #if IS_ENABLED(CONFIG_IPV6) 222 struct sockaddr_in6 sin6; 223 #endif 224 struct sockaddr_in sin; 225 226 sin.sin_family = PF_INET; 227 sin.sin_addr.s_addr = htonl(INADDR_ANY); 228 sin.sin_port = htons(RDS_PORT); 229 ret = rds_rdma_listen_init_common(rds_rdma_cm_event_handler, 230 (struct sockaddr *)&sin, 231 &rds_rdma_listen_id); 232 if (ret != 0) 233 return ret; 234 235 #if IS_ENABLED(CONFIG_IPV6) 236 sin6.sin6_family = PF_INET6; 237 sin6.sin6_addr = in6addr_any; 238 sin6.sin6_port = htons(RDS_CM_PORT); 239 sin6.sin6_scope_id = 0; 240 sin6.sin6_flowinfo = 0; 241 ret = rds_rdma_listen_init_common(rds6_rdma_cm_event_handler, 242 (struct sockaddr *)&sin6, 243 &rds6_rdma_listen_id); 244 /* Keep going even when IPv6 is not enabled in the system. */ 245 if (ret != 0) 246 rdsdebug("Cannot set up IPv6 RDMA listener\n"); 247 #endif 248 return 0; 249 } 250 251 static void rds_rdma_listen_stop(void) 252 { 253 if (rds_rdma_listen_id) { 254 rdsdebug("cm %p\n", rds_rdma_listen_id); 255 rdma_destroy_id(rds_rdma_listen_id); 256 rds_rdma_listen_id = NULL; 257 } 258 #if IS_ENABLED(CONFIG_IPV6) 259 if (rds6_rdma_listen_id) { 260 rdsdebug("cm %p\n", rds6_rdma_listen_id); 261 rdma_destroy_id(rds6_rdma_listen_id); 262 rds6_rdma_listen_id = NULL; 263 } 264 #endif 265 } 266 267 static int rds_rdma_init(void) 268 { 269 int ret; 270 271 ret = rds_ib_init(); 272 if (ret) 273 goto out; 274 275 ret = rds_rdma_listen_init(); 276 if (ret) 277 rds_ib_exit(); 278 out: 279 return ret; 280 } 281 module_init(rds_rdma_init); 282 283 static void rds_rdma_exit(void) 284 { 285 /* stop listening first to ensure no new connections are attempted */ 286 rds_rdma_listen_stop(); 287 rds_ib_exit(); 288 } 289 module_exit(rds_rdma_exit); 290 291 MODULE_AUTHOR("Oracle Corporation <rds-devel@oss.oracle.com>"); 292 MODULE_DESCRIPTION("RDS: IB transport"); 293 MODULE_LICENSE("Dual BSD/GPL"); 294