--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for SMB-Direct RDMA as transport
+ Copyright (C) Stefan Metzmacher 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "../util/tevent_ntstatus.h"
+#include "../lib/tsocket/tsocket.h"
+
+#ifdef SMB_TRANSPORT_ENABLE_RDMA
+#include <rdma/rdma_cma_abi.h>
+#include <rdma/rdma_cma.h>
+#include <infiniband/verbs.h>
+
+struct smb_direct_transport {
+ struct {
+ struct rdma_cm_id *cm_id;
+ struct rdma_event_channel *cm_channel;
+ struct tevent_fd *fde_channel;
+ enum rdma_cm_event_type expected_event;
+ struct rdma_cm_event *cm_event;
+ } rdma;
+};
+
+static int smb_direct_transport_destructor(struct smb_direct_transport *t);
+
+static struct smb_direct_transport *smb_direct_transport_create(TALLOC_CTX *mem_ctx)
+{
+ struct smb_direct_transport *t;
+ int ret;
+
+ t = talloc_zero(mem_ctx, struct smb_direct_transport);
+ if (t == NULL) {
+ return NULL;
+ }
+ talloc_set_destructor(t, smb_direct_transport_destructor);
+
+ t->rdma.cm_channel = rdma_create_event_channel();
+ if (t->rdma.cm_channel == NULL) {
+ talloc_free(t);
+ return NULL;
+ }
+
+#if RDMA_USER_CM_MAX_ABI_VERSION >= 2
+ ret = rdma_create_id(t->rdma.cm_channel,
+ &t->rdma.cm_id,
+ t, RDMA_PS_TCP);
+#else
+ ret = rdma_create_id(t->rdma.cm_channel,
+ &t->rdma.cm_id,
+ t);
+#endif
+ if (ret != 0) {
+ talloc_free(t);
+ return NULL;
+ }
+
+ return t;
+}
+
+static int smb_direct_transport_destructor(struct smb_direct_transport *t)
+{
+ TALLOC_FREE(t->rdma.fde_channel);
+
+ if (t->rdma.cm_event != NULL) {
+ rdma_ack_cm_event(t->rdma.cm_event);
+ t->rdma.cm_event = NULL;
+ }
+
+ if (t->rdma.cm_id != NULL) {
+ rdma_destroy_id(t->rdma.cm_id);
+ t->rdma.cm_id = NULL;
+ }
+
+ if (t->rdma.cm_channel != NULL) {
+ rdma_destroy_event_channel(t->rdma.cm_channel);
+ t->rdma.cm_channel = NULL;
+ }
+
+ return 0;
+}
+
+struct smb_direct_rdma_connect_state {
+ struct smb_direct_transport *t;
+};
+
+static struct tevent_req *smb_direct_rdma_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smb_direct_transport *transport,
+ struct tsocket_address *local_addr,
+ struct tsocket_address *remote_addr)
+{
+ struct tevent_req *req;
+ struct smb_direct_rdma_connect_state *state;
+ int ret;
+ struct sockaddr *src_addr, *dst_addr;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb_direct_rdma_connect_state);
+ if (!req) {
+ return NULL;
+ }
+ state->t = transport;
+
+/*
+ * ret = smb_direct_transport_setup_ev(transport, ev);
+ if (ret != 0) {
+
+ }
+*/
+ ret = rdma_resolve_addr(state->t->rdma.cm_id,
+ src_addr, dst_addr,
+ 5000);
+ if (ret != 0) {
+ }
+ state->t->rdma.expected_event = RDMA_CM_EVENT_ADDR_RESOLVED;
+
+ return req;
+}
+
+static void smb_direct_rdma_connect_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct smb_direct_rdma_connect_state *state =
+ tevent_req_data(req,
+ struct smb_direct_rdma_connect_state);
+ int ret;
+
+ ret = rdma_get_cm_event(state->t->rdma.cm_channel,
+ &state->t->rdma.cm_event);
+ if (ret != 0) {
+
+ }
+
+ if (state->t->rdma.cm_event->status != 0) {
+
+ }
+
+ if (state->t->rdma.cm_event->event != state->t->rdma.expected_event) {
+
+ }
+
+ switch (state->t->rdma.cm_event->event) {
+ case RDMA_CM_EVENT_ADDR_RESOLVED:
+ ret = rdma_resolve_route(state->t->rdma.cm_id, 5000);
+ if (ret != 0) {
+
+ }
+ break;
+ case RDMA_CM_EVENT_ADDR_ERROR:
+ break;
+ case RDMA_CM_EVENT_ROUTE_RESOLVED:
+
+ case RDMA_CM_EVENT_ROUTE_ERROR:
+ case RDMA_CM_EVENT_CONNECT_REQUEST:
+ case RDMA_CM_EVENT_CONNECT_RESPONSE:
+ case RDMA_CM_EVENT_CONNECT_ERROR:
+ case RDMA_CM_EVENT_UNREACHABLE:
+ case RDMA_CM_EVENT_REJECTED:
+ case RDMA_CM_EVENT_ESTABLISHED:
+ case RDMA_CM_EVENT_DISCONNECTED:
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:
+ case RDMA_CM_EVENT_MULTICAST_JOIN:
+ case RDMA_CM_EVENT_MULTICAST_ERROR:
+ case RDMA_CM_EVENT_ADDR_CHANGE:
+ case RDMA_CM_EVENT_TIMEWAIT_EXIT:
+ //error
+ break;
+ }
+
+ if (state->t->rdma.cm_event != NULL) {
+ rdma_ack_cm_event(state->t->rdma.cm_event);
+ state->t->rdma.cm_event = NULL;
+ }
+}
+
+static NTSTATUS smb_transport_direct_rdma_connect_recv(struct tevent_req *req)
+{
+ struct smb_direct_rdma_connect_state *state =
+ tevent_req_data(req,
+ struct smb_direct_rdma_connect_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+#endif /* SMB_TRANSPORT_ENABLE_RDMA */