Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/rds/rdma_transport.c
15109 views
1
/*
2
* Copyright (c) 2009 Oracle. 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 <rdma/rdma_cm.h>
34
35
#include "rdma_transport.h"
36
37
static struct rdma_cm_id *rds_rdma_listen_id;
38
39
static char *rds_cm_event_strings[] = {
40
#define RDS_CM_EVENT_STRING(foo) \
41
[RDMA_CM_EVENT_##foo] = __stringify(RDMA_CM_EVENT_##foo)
42
RDS_CM_EVENT_STRING(ADDR_RESOLVED),
43
RDS_CM_EVENT_STRING(ADDR_ERROR),
44
RDS_CM_EVENT_STRING(ROUTE_RESOLVED),
45
RDS_CM_EVENT_STRING(ROUTE_ERROR),
46
RDS_CM_EVENT_STRING(CONNECT_REQUEST),
47
RDS_CM_EVENT_STRING(CONNECT_RESPONSE),
48
RDS_CM_EVENT_STRING(CONNECT_ERROR),
49
RDS_CM_EVENT_STRING(UNREACHABLE),
50
RDS_CM_EVENT_STRING(REJECTED),
51
RDS_CM_EVENT_STRING(ESTABLISHED),
52
RDS_CM_EVENT_STRING(DISCONNECTED),
53
RDS_CM_EVENT_STRING(DEVICE_REMOVAL),
54
RDS_CM_EVENT_STRING(MULTICAST_JOIN),
55
RDS_CM_EVENT_STRING(MULTICAST_ERROR),
56
RDS_CM_EVENT_STRING(ADDR_CHANGE),
57
RDS_CM_EVENT_STRING(TIMEWAIT_EXIT),
58
#undef RDS_CM_EVENT_STRING
59
};
60
61
static char *rds_cm_event_str(enum rdma_cm_event_type type)
62
{
63
return rds_str_array(rds_cm_event_strings,
64
ARRAY_SIZE(rds_cm_event_strings), type);
65
};
66
67
int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
68
struct rdma_cm_event *event)
69
{
70
/* this can be null in the listening path */
71
struct rds_connection *conn = cm_id->context;
72
struct rds_transport *trans;
73
int ret = 0;
74
75
rdsdebug("conn %p id %p handling event %u (%s)\n", conn, cm_id,
76
event->event, rds_cm_event_str(event->event));
77
78
if (cm_id->device->node_type == RDMA_NODE_RNIC)
79
trans = &rds_iw_transport;
80
else
81
trans = &rds_ib_transport;
82
83
/* Prevent shutdown from tearing down the connection
84
* while we're executing. */
85
if (conn) {
86
mutex_lock(&conn->c_cm_lock);
87
88
/* If the connection is being shut down, bail out
89
* right away. We return 0 so cm_id doesn't get
90
* destroyed prematurely */
91
if (rds_conn_state(conn) == RDS_CONN_DISCONNECTING) {
92
/* Reject incoming connections while we're tearing
93
* down an existing one. */
94
if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST)
95
ret = 1;
96
goto out;
97
}
98
}
99
100
switch (event->event) {
101
case RDMA_CM_EVENT_CONNECT_REQUEST:
102
ret = trans->cm_handle_connect(cm_id, event);
103
break;
104
105
case RDMA_CM_EVENT_ADDR_RESOLVED:
106
/* XXX do we need to clean up if this fails? */
107
ret = rdma_resolve_route(cm_id,
108
RDS_RDMA_RESOLVE_TIMEOUT_MS);
109
break;
110
111
case RDMA_CM_EVENT_ROUTE_RESOLVED:
112
/* XXX worry about racing with listen acceptance */
113
ret = trans->cm_initiate_connect(cm_id);
114
break;
115
116
case RDMA_CM_EVENT_ESTABLISHED:
117
trans->cm_connect_complete(conn, event);
118
break;
119
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_REJECTED:
125
case RDMA_CM_EVENT_DEVICE_REMOVAL:
126
case RDMA_CM_EVENT_ADDR_CHANGE:
127
if (conn)
128
rds_conn_drop(conn);
129
break;
130
131
case RDMA_CM_EVENT_DISCONNECTED:
132
rdsdebug("DISCONNECT event - dropping connection "
133
"%pI4->%pI4\n", &conn->c_laddr,
134
&conn->c_faddr);
135
rds_conn_drop(conn);
136
break;
137
138
default:
139
/* things like device disconnect? */
140
printk(KERN_ERR "RDS: unknown event %u (%s)!\n",
141
event->event, rds_cm_event_str(event->event));
142
break;
143
}
144
145
out:
146
if (conn)
147
mutex_unlock(&conn->c_cm_lock);
148
149
rdsdebug("id %p event %u (%s) handling ret %d\n", cm_id, event->event,
150
rds_cm_event_str(event->event), ret);
151
152
return ret;
153
}
154
155
static int rds_rdma_listen_init(void)
156
{
157
struct sockaddr_in sin;
158
struct rdma_cm_id *cm_id;
159
int ret;
160
161
cm_id = rdma_create_id(rds_rdma_cm_event_handler, NULL, RDMA_PS_TCP,
162
IB_QPT_RC);
163
if (IS_ERR(cm_id)) {
164
ret = PTR_ERR(cm_id);
165
printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
166
"rdma_create_id() returned %d\n", ret);
167
return ret;
168
}
169
170
sin.sin_family = AF_INET,
171
sin.sin_addr.s_addr = (__force u32)htonl(INADDR_ANY);
172
sin.sin_port = (__force u16)htons(RDS_PORT);
173
174
/*
175
* XXX I bet this binds the cm_id to a device. If we want to support
176
* fail-over we'll have to take this into consideration.
177
*/
178
ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin);
179
if (ret) {
180
printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
181
"rdma_bind_addr() returned %d\n", ret);
182
goto out;
183
}
184
185
ret = rdma_listen(cm_id, 128);
186
if (ret) {
187
printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
188
"rdma_listen() returned %d\n", ret);
189
goto out;
190
}
191
192
rdsdebug("cm %p listening on port %u\n", cm_id, RDS_PORT);
193
194
rds_rdma_listen_id = cm_id;
195
cm_id = NULL;
196
out:
197
if (cm_id)
198
rdma_destroy_id(cm_id);
199
return ret;
200
}
201
202
static void rds_rdma_listen_stop(void)
203
{
204
if (rds_rdma_listen_id) {
205
rdsdebug("cm %p\n", rds_rdma_listen_id);
206
rdma_destroy_id(rds_rdma_listen_id);
207
rds_rdma_listen_id = NULL;
208
}
209
}
210
211
static int rds_rdma_init(void)
212
{
213
int ret;
214
215
ret = rds_rdma_listen_init();
216
if (ret)
217
goto out;
218
219
ret = rds_iw_init();
220
if (ret)
221
goto err_iw_init;
222
223
ret = rds_ib_init();
224
if (ret)
225
goto err_ib_init;
226
227
goto out;
228
229
err_ib_init:
230
rds_iw_exit();
231
err_iw_init:
232
rds_rdma_listen_stop();
233
out:
234
return ret;
235
}
236
module_init(rds_rdma_init);
237
238
static void rds_rdma_exit(void)
239
{
240
/* stop listening first to ensure no new connections are attempted */
241
rds_rdma_listen_stop();
242
rds_ib_exit();
243
rds_iw_exit();
244
}
245
module_exit(rds_rdma_exit);
246
247
MODULE_AUTHOR("Oracle Corporation <[email protected]>");
248
MODULE_DESCRIPTION("RDS: IB/iWARP transport");
249
MODULE_LICENSE("Dual BSD/GPL");
250
251
252