rdma_transport.c 8.4 KB

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