Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
0003  *
0004  * This software is available to you under a choice of one of two
0005  * licenses.  You may choose to be licensed under the terms of the GNU
0006  * General Public License (GPL) Version 2, available from the file
0007  * COPYING in the main directory of this source tree, or the
0008  * OpenIB.org BSD license below:
0009  *
0010  *     Redistribution and use in source and binary forms, with or
0011  *     without modification, are permitted provided that the following
0012  *     conditions are met:
0013  *
0014  *      - Redistributions of source code must retain the above
0015  *        copyright notice, this list of conditions and the following
0016  *        disclaimer.
0017  *
0018  *      - Redistributions in binary form must reproduce the above
0019  *        copyright notice, this list of conditions and the following
0020  *        disclaimer in the documentation and/or other materials
0021  *        provided with the distribution.
0022  *
0023  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0024  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0025  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0026  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0027  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0028  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0029  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0030  * SOFTWARE.
0031  *
0032  */
0033 #include <linux/module.h>
0034 #include <rdma/rdma_cm.h>
0035 
0036 #include "rds_single_path.h"
0037 #include "rdma_transport.h"
0038 #include "ib.h"
0039 
0040 /* Global IPv4 and IPv6 RDS RDMA listener cm_id */
0041 static struct rdma_cm_id *rds_rdma_listen_id;
0042 #if IS_ENABLED(CONFIG_IPV6)
0043 static struct rdma_cm_id *rds6_rdma_listen_id;
0044 #endif
0045 
0046 /* Per IB specification 7.7.3, service level is a 4-bit field. */
0047 #define TOS_TO_SL(tos)      ((tos) & 0xF)
0048 
0049 static int rds_rdma_cm_event_handler_cmn(struct rdma_cm_id *cm_id,
0050                      struct rdma_cm_event *event,
0051                      bool isv6)
0052 {
0053     /* this can be null in the listening path */
0054     struct rds_connection *conn = cm_id->context;
0055     struct rds_transport *trans;
0056     int ret = 0;
0057     int *err;
0058     u8 len;
0059 
0060     rdsdebug("conn %p id %p handling event %u (%s)\n", conn, cm_id,
0061          event->event, rdma_event_msg(event->event));
0062 
0063     if (cm_id->device->node_type == RDMA_NODE_IB_CA)
0064         trans = &rds_ib_transport;
0065 
0066     /* Prevent shutdown from tearing down the connection
0067      * while we're executing. */
0068     if (conn) {
0069         mutex_lock(&conn->c_cm_lock);
0070 
0071         /* If the connection is being shut down, bail out
0072          * right away. We return 0 so cm_id doesn't get
0073          * destroyed prematurely */
0074         if (rds_conn_state(conn) == RDS_CONN_DISCONNECTING) {
0075             /* Reject incoming connections while we're tearing
0076              * down an existing one. */
0077             if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST)
0078                 ret = 1;
0079             goto out;
0080         }
0081     }
0082 
0083     switch (event->event) {
0084     case RDMA_CM_EVENT_CONNECT_REQUEST:
0085         ret = trans->cm_handle_connect(cm_id, event, isv6);
0086         break;
0087 
0088     case RDMA_CM_EVENT_ADDR_RESOLVED:
0089         rdma_set_service_type(cm_id, conn->c_tos);
0090         rdma_set_min_rnr_timer(cm_id, IB_RNR_TIMER_000_32);
0091         /* XXX do we need to clean up if this fails? */
0092         ret = rdma_resolve_route(cm_id,
0093                      RDS_RDMA_RESOLVE_TIMEOUT_MS);
0094         break;
0095 
0096     case RDMA_CM_EVENT_ROUTE_RESOLVED:
0097         /* Connection could have been dropped so make sure the
0098          * cm_id is valid before proceeding
0099          */
0100         if (conn) {
0101             struct rds_ib_connection *ibic;
0102 
0103             ibic = conn->c_transport_data;
0104             if (ibic && ibic->i_cm_id == cm_id) {
0105                 cm_id->route.path_rec[0].sl =
0106                     TOS_TO_SL(conn->c_tos);
0107                 ret = trans->cm_initiate_connect(cm_id, isv6);
0108             } else {
0109                 rds_conn_drop(conn);
0110             }
0111         }
0112         break;
0113 
0114     case RDMA_CM_EVENT_ESTABLISHED:
0115         if (conn)
0116             trans->cm_connect_complete(conn, event);
0117         break;
0118 
0119     case RDMA_CM_EVENT_REJECTED:
0120         if (!conn)
0121             break;
0122         err = (int *)rdma_consumer_reject_data(cm_id, event, &len);
0123         if (!err ||
0124             (err && len >= sizeof(*err) &&
0125              ((*err) <= RDS_RDMA_REJ_INCOMPAT))) {
0126             pr_warn("RDS/RDMA: conn <%pI6c, %pI6c> rejected, dropping connection\n",
0127                 &conn->c_laddr, &conn->c_faddr);
0128 
0129             if (!conn->c_tos)
0130                 conn->c_proposed_version = RDS_PROTOCOL_COMPAT_VERSION;
0131 
0132             rds_conn_drop(conn);
0133         }
0134         rdsdebug("Connection rejected: %s\n",
0135              rdma_reject_msg(cm_id, event->status));
0136         break;
0137     case RDMA_CM_EVENT_ADDR_ERROR:
0138     case RDMA_CM_EVENT_ROUTE_ERROR:
0139     case RDMA_CM_EVENT_CONNECT_ERROR:
0140     case RDMA_CM_EVENT_UNREACHABLE:
0141     case RDMA_CM_EVENT_DEVICE_REMOVAL:
0142     case RDMA_CM_EVENT_ADDR_CHANGE:
0143         if (conn)
0144             rds_conn_drop(conn);
0145         break;
0146 
0147     case RDMA_CM_EVENT_DISCONNECTED:
0148         if (!conn)
0149             break;
0150         rdsdebug("DISCONNECT event - dropping connection "
0151              "%pI6c->%pI6c\n", &conn->c_laddr,
0152              &conn->c_faddr);
0153         rds_conn_drop(conn);
0154         break;
0155 
0156     case RDMA_CM_EVENT_TIMEWAIT_EXIT:
0157         if (conn) {
0158             pr_info("RDS: RDMA_CM_EVENT_TIMEWAIT_EXIT event: dropping connection %pI6c->%pI6c\n",
0159                 &conn->c_laddr, &conn->c_faddr);
0160             rds_conn_drop(conn);
0161         }
0162         break;
0163 
0164     default:
0165         /* things like device disconnect? */
0166         printk(KERN_ERR "RDS: unknown event %u (%s)!\n",
0167                event->event, rdma_event_msg(event->event));
0168         break;
0169     }
0170 
0171 out:
0172     if (conn)
0173         mutex_unlock(&conn->c_cm_lock);
0174 
0175     rdsdebug("id %p event %u (%s) handling ret %d\n", cm_id, event->event,
0176          rdma_event_msg(event->event), ret);
0177 
0178     return ret;
0179 }
0180 
0181 int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
0182                   struct rdma_cm_event *event)
0183 {
0184     return rds_rdma_cm_event_handler_cmn(cm_id, event, false);
0185 }
0186 
0187 #if IS_ENABLED(CONFIG_IPV6)
0188 int rds6_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
0189                    struct rdma_cm_event *event)
0190 {
0191     return rds_rdma_cm_event_handler_cmn(cm_id, event, true);
0192 }
0193 #endif
0194 
0195 static int rds_rdma_listen_init_common(rdma_cm_event_handler handler,
0196                        struct sockaddr *sa,
0197                        struct rdma_cm_id **ret_cm_id)
0198 {
0199     struct rdma_cm_id *cm_id;
0200     int ret;
0201 
0202     cm_id = rdma_create_id(&init_net, handler, NULL,
0203                    RDMA_PS_TCP, IB_QPT_RC);
0204     if (IS_ERR(cm_id)) {
0205         ret = PTR_ERR(cm_id);
0206         printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
0207                "rdma_create_id() returned %d\n", ret);
0208         return ret;
0209     }
0210 
0211     /*
0212      * XXX I bet this binds the cm_id to a device.  If we want to support
0213      * fail-over we'll have to take this into consideration.
0214      */
0215     ret = rdma_bind_addr(cm_id, sa);
0216     if (ret) {
0217         printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
0218                "rdma_bind_addr() returned %d\n", ret);
0219         goto out;
0220     }
0221 
0222     ret = rdma_listen(cm_id, 128);
0223     if (ret) {
0224         printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
0225                "rdma_listen() returned %d\n", ret);
0226         goto out;
0227     }
0228 
0229     rdsdebug("cm %p listening on port %u\n", cm_id, RDS_PORT);
0230 
0231     *ret_cm_id = cm_id;
0232     cm_id = NULL;
0233 out:
0234     if (cm_id)
0235         rdma_destroy_id(cm_id);
0236     return ret;
0237 }
0238 
0239 /* Initialize the RDS RDMA listeners.  We create two listeners for
0240  * compatibility reason.  The one on RDS_PORT is used for IPv4
0241  * requests only.  The one on RDS_CM_PORT is used for IPv6 requests
0242  * only.  So only IPv6 enabled RDS module will communicate using this
0243  * port.
0244  */
0245 static int rds_rdma_listen_init(void)
0246 {
0247     int ret;
0248 #if IS_ENABLED(CONFIG_IPV6)
0249     struct sockaddr_in6 sin6;
0250 #endif
0251     struct sockaddr_in sin;
0252 
0253     sin.sin_family = PF_INET;
0254     sin.sin_addr.s_addr = htonl(INADDR_ANY);
0255     sin.sin_port = htons(RDS_PORT);
0256     ret = rds_rdma_listen_init_common(rds_rdma_cm_event_handler,
0257                       (struct sockaddr *)&sin,
0258                       &rds_rdma_listen_id);
0259     if (ret != 0)
0260         return ret;
0261 
0262 #if IS_ENABLED(CONFIG_IPV6)
0263     sin6.sin6_family = PF_INET6;
0264     sin6.sin6_addr = in6addr_any;
0265     sin6.sin6_port = htons(RDS_CM_PORT);
0266     sin6.sin6_scope_id = 0;
0267     sin6.sin6_flowinfo = 0;
0268     ret = rds_rdma_listen_init_common(rds6_rdma_cm_event_handler,
0269                       (struct sockaddr *)&sin6,
0270                       &rds6_rdma_listen_id);
0271     /* Keep going even when IPv6 is not enabled in the system. */
0272     if (ret != 0)
0273         rdsdebug("Cannot set up IPv6 RDMA listener\n");
0274 #endif
0275     return 0;
0276 }
0277 
0278 static void rds_rdma_listen_stop(void)
0279 {
0280     if (rds_rdma_listen_id) {
0281         rdsdebug("cm %p\n", rds_rdma_listen_id);
0282         rdma_destroy_id(rds_rdma_listen_id);
0283         rds_rdma_listen_id = NULL;
0284     }
0285 #if IS_ENABLED(CONFIG_IPV6)
0286     if (rds6_rdma_listen_id) {
0287         rdsdebug("cm %p\n", rds6_rdma_listen_id);
0288         rdma_destroy_id(rds6_rdma_listen_id);
0289         rds6_rdma_listen_id = NULL;
0290     }
0291 #endif
0292 }
0293 
0294 static int rds_rdma_init(void)
0295 {
0296     int ret;
0297 
0298     ret = rds_ib_init();
0299     if (ret)
0300         goto out;
0301 
0302     ret = rds_rdma_listen_init();
0303     if (ret)
0304         rds_ib_exit();
0305 out:
0306     return ret;
0307 }
0308 module_init(rds_rdma_init);
0309 
0310 static void rds_rdma_exit(void)
0311 {
0312     /* stop listening first to ensure no new connections are attempted */
0313     rds_rdma_listen_stop();
0314     rds_ib_exit();
0315 }
0316 module_exit(rds_rdma_exit);
0317 
0318 MODULE_AUTHOR("Oracle Corporation <rds-devel@oss.oracle.com>");
0319 MODULE_DESCRIPTION("RDS: IB transport");
0320 MODULE_LICENSE("Dual BSD/GPL");