rdma_transport.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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. if (conn) {
  80. rdma_set_service_type(cm_id, conn->c_tos);
  81. rdma_set_min_rnr_timer(cm_id, IB_RNR_TIMER_000_32);
  82. /* XXX do we need to clean up if this fails? */
  83. ret = rdma_resolve_route(cm_id,
  84. RDS_RDMA_RESOLVE_TIMEOUT_MS);
  85. }
  86. break;
  87. case RDMA_CM_EVENT_ROUTE_RESOLVED:
  88. /* Connection could have been dropped so make sure the
  89. * cm_id is valid before proceeding
  90. */
  91. if (conn) {
  92. struct rds_ib_connection *ibic;
  93. ibic = conn->c_transport_data;
  94. if (ibic && ibic->i_cm_id == cm_id) {
  95. cm_id->route.path_rec[0].sl =
  96. TOS_TO_SL(conn->c_tos);
  97. ret = trans->cm_initiate_connect(cm_id, isv6);
  98. } else {
  99. rds_conn_drop(conn);
  100. }
  101. }
  102. break;
  103. case RDMA_CM_EVENT_ESTABLISHED:
  104. if (conn)
  105. trans->cm_connect_complete(conn, event);
  106. break;
  107. case RDMA_CM_EVENT_REJECTED:
  108. if (!conn)
  109. break;
  110. err = (int *)rdma_consumer_reject_data(cm_id, event, &len);
  111. if (!err ||
  112. (err && len >= sizeof(*err) &&
  113. ((*err) <= RDS_RDMA_REJ_INCOMPAT))) {
  114. pr_warn("RDS/RDMA: conn <%pI6c, %pI6c> rejected, dropping connection\n",
  115. &conn->c_laddr, &conn->c_faddr);
  116. if (!conn->c_tos)
  117. conn->c_proposed_version = RDS_PROTOCOL_COMPAT_VERSION;
  118. rds_conn_drop(conn);
  119. }
  120. rdsdebug("Connection rejected: %s\n",
  121. rdma_reject_msg(cm_id, event->status));
  122. break;
  123. case RDMA_CM_EVENT_ADDR_ERROR:
  124. case RDMA_CM_EVENT_ROUTE_ERROR:
  125. case RDMA_CM_EVENT_CONNECT_ERROR:
  126. case RDMA_CM_EVENT_UNREACHABLE:
  127. case RDMA_CM_EVENT_DEVICE_REMOVAL:
  128. case RDMA_CM_EVENT_ADDR_CHANGE:
  129. if (conn)
  130. rds_conn_drop(conn);
  131. break;
  132. case RDMA_CM_EVENT_DISCONNECTED:
  133. if (!conn)
  134. break;
  135. rdsdebug("DISCONNECT event - dropping connection "
  136. "%pI6c->%pI6c\n", &conn->c_laddr,
  137. &conn->c_faddr);
  138. rds_conn_drop(conn);
  139. break;
  140. case RDMA_CM_EVENT_TIMEWAIT_EXIT:
  141. if (conn) {
  142. pr_info("RDS: RDMA_CM_EVENT_TIMEWAIT_EXIT event: dropping connection %pI6c->%pI6c\n",
  143. &conn->c_laddr, &conn->c_faddr);
  144. rds_conn_drop(conn);
  145. }
  146. break;
  147. default:
  148. /* things like device disconnect? */
  149. printk(KERN_ERR "RDS: unknown event %u (%s)!\n",
  150. event->event, rdma_event_msg(event->event));
  151. break;
  152. }
  153. out:
  154. if (conn)
  155. mutex_unlock(&conn->c_cm_lock);
  156. rdsdebug("id %p event %u (%s) handling ret %d\n", cm_id, event->event,
  157. rdma_event_msg(event->event), ret);
  158. return ret;
  159. }
  160. int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
  161. struct rdma_cm_event *event)
  162. {
  163. return rds_rdma_cm_event_handler_cmn(cm_id, event, false);
  164. }
  165. #if IS_ENABLED(CONFIG_IPV6)
  166. int rds6_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
  167. struct rdma_cm_event *event)
  168. {
  169. return rds_rdma_cm_event_handler_cmn(cm_id, event, true);
  170. }
  171. #endif
  172. static int rds_rdma_listen_init_common(rdma_cm_event_handler handler,
  173. struct sockaddr *sa,
  174. struct rdma_cm_id **ret_cm_id)
  175. {
  176. struct rdma_cm_id *cm_id;
  177. int ret;
  178. cm_id = rdma_create_id(&init_net, handler, NULL,
  179. RDMA_PS_TCP, IB_QPT_RC);
  180. if (IS_ERR(cm_id)) {
  181. ret = PTR_ERR(cm_id);
  182. printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
  183. "rdma_create_id() returned %d\n", ret);
  184. return ret;
  185. }
  186. /*
  187. * XXX I bet this binds the cm_id to a device. If we want to support
  188. * fail-over we'll have to take this into consideration.
  189. */
  190. ret = rdma_bind_addr(cm_id, sa);
  191. if (ret) {
  192. printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
  193. "rdma_bind_addr() returned %d\n", ret);
  194. goto out;
  195. }
  196. ret = rdma_listen(cm_id, 128);
  197. if (ret) {
  198. printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
  199. "rdma_listen() returned %d\n", ret);
  200. goto out;
  201. }
  202. rdsdebug("cm %p listening on port %u\n", cm_id, RDS_PORT);
  203. *ret_cm_id = cm_id;
  204. cm_id = NULL;
  205. out:
  206. if (cm_id)
  207. rdma_destroy_id(cm_id);
  208. return ret;
  209. }
  210. /* Initialize the RDS RDMA listeners. We create two listeners for
  211. * compatibility reason. The one on RDS_PORT is used for IPv4
  212. * requests only. The one on RDS_CM_PORT is used for IPv6 requests
  213. * only. So only IPv6 enabled RDS module will communicate using this
  214. * port.
  215. */
  216. static int rds_rdma_listen_init(void)
  217. {
  218. int ret;
  219. #if IS_ENABLED(CONFIG_IPV6)
  220. struct sockaddr_in6 sin6;
  221. #endif
  222. struct sockaddr_in sin;
  223. sin.sin_family = PF_INET;
  224. sin.sin_addr.s_addr = htonl(INADDR_ANY);
  225. sin.sin_port = htons(RDS_PORT);
  226. ret = rds_rdma_listen_init_common(rds_rdma_cm_event_handler,
  227. (struct sockaddr *)&sin,
  228. &rds_rdma_listen_id);
  229. if (ret != 0)
  230. return ret;
  231. #if IS_ENABLED(CONFIG_IPV6)
  232. sin6.sin6_family = PF_INET6;
  233. sin6.sin6_addr = in6addr_any;
  234. sin6.sin6_port = htons(RDS_CM_PORT);
  235. sin6.sin6_scope_id = 0;
  236. sin6.sin6_flowinfo = 0;
  237. ret = rds_rdma_listen_init_common(rds6_rdma_cm_event_handler,
  238. (struct sockaddr *)&sin6,
  239. &rds6_rdma_listen_id);
  240. /* Keep going even when IPv6 is not enabled in the system. */
  241. if (ret != 0)
  242. rdsdebug("Cannot set up IPv6 RDMA listener\n");
  243. #endif
  244. return 0;
  245. }
  246. static void rds_rdma_listen_stop(void)
  247. {
  248. if (rds_rdma_listen_id) {
  249. rdsdebug("cm %p\n", rds_rdma_listen_id);
  250. rdma_destroy_id(rds_rdma_listen_id);
  251. rds_rdma_listen_id = NULL;
  252. }
  253. #if IS_ENABLED(CONFIG_IPV6)
  254. if (rds6_rdma_listen_id) {
  255. rdsdebug("cm %p\n", rds6_rdma_listen_id);
  256. rdma_destroy_id(rds6_rdma_listen_id);
  257. rds6_rdma_listen_id = NULL;
  258. }
  259. #endif
  260. }
  261. static int __init rds_rdma_init(void)
  262. {
  263. int ret;
  264. ret = rds_ib_init();
  265. if (ret)
  266. goto out;
  267. ret = rds_rdma_listen_init();
  268. if (ret)
  269. rds_ib_exit();
  270. out:
  271. return ret;
  272. }
  273. module_init(rds_rdma_init);
  274. static void __exit rds_rdma_exit(void)
  275. {
  276. /* stop listening first to ensure no new connections are attempted */
  277. rds_rdma_listen_stop();
  278. rds_ib_exit();
  279. }
  280. module_exit(rds_rdma_exit);
  281. MODULE_AUTHOR("Oracle Corporation <[email protected]>");
  282. MODULE_DESCRIPTION("RDS: IB transport");
  283. MODULE_LICENSE("Dual BSD/GPL");