FIXUP daemon
authorRalph Boehme <slow@samba.org>
Fri, 30 Sep 2016 04:11:48 +0000 (21:11 -0700)
committerStefan Metzmacher <metze@samba.org>
Fri, 1 Jun 2018 12:35:08 +0000 (14:35 +0200)
libcli/smb/smb_direct_daemon.c

index 04ace86000fce9ac3cb46317fc7abea5b2ef7387..c8212633336cb1cbd4579074b89f0948e3532505 100644 (file)
 #include "libcli/util/tstream.h"
 #include "lib/util/byteorder.h"
 #include "lib/util/samba_util.h"
+#include "lib/util/blocking.h"
+
+#ifdef SMB_TRANSPORT_ENABLE_RDMA
+#include <rdma/rdma_cma_abi.h>
 #include <rdma/rdma_cma.h>
 #include "smb_direct.h"
 #include "smb_direct_util.h"
@@ -516,12 +520,19 @@ static NTSTATUS smbd_direct_daemon_ping(
        return NT_STATUS_OK;
 }
 
+static void rdma_cm_handler(struct tevent_context *ev,
+                           struct tevent_fd *fde,
+                           uint16_t flags,
+                           void *private_data);
+
 static NTSTATUS smbd_direct_daemon_listen(
        struct smb_direct_daemon_conn *conn,
        struct sdd_packet_listen_request *listen_request,
        struct sdd_packet_listen_response *listen_response)
 {
        struct smb_direct_daemon_state *daemon_state = conn->daemon_state;
+       struct sockaddr_in inaddr;
+       int result;
 
        if (daemon_state->listening_conn != NULL) {
                /* There can be only one... */
@@ -535,6 +546,9 @@ static NTSTATUS smbd_direct_daemon_listen(
                return NT_STATUS_INTERNAL_ERROR;
        }
 
+       set_close_on_exec(daemon_state->rdma.cm_channel->fd);
+       set_blocking(daemon_state->rdma.cm_channel->fd, false);
+
 #if RDMA_USER_CM_MAX_ABI_VERSION >= 2
        result = rdma_create_id(daemon_state->rdma.cm_channel,
                                &daemon_state->rdma.cm_id,
@@ -548,7 +562,7 @@ static NTSTATUS smbd_direct_daemon_listen(
        if (result != 0) {
                DBG_ERR("rdma_create_id failed [%s]\n",
                        strerror(errno));
-               goto cleanup;
+               goto fail;
        }
 
        daemon_state->rdma.cm_channel_fde = tevent_add_fd(
@@ -557,10 +571,29 @@ static NTSTATUS smbd_direct_daemon_listen(
                daemon_state->rdma.cm_channel->fd,
                TEVENT_FD_READ,
                rdma_cm_handler,
-               conn);
+               daemon_state);
        if (daemon_state->rdma.cm_channel_fde == NULL) {
                DBG_ERR("tevent_add_fd failed\n");
-               goto cleanup;
+               goto fail;
+       }
+
+       ZERO_STRUCT(inaddr);
+       inaddr.sin_family = AF_INET;
+       inaddr.sin_port = 5445;
+       inaddr.sin_addr.s_addr = INADDR_ANY;
+
+       result = rdma_bind_addr(daemon_state->rdma.cm_id,
+                               (struct sockaddr *)&inaddr);
+       if (result != 0) {
+               DBG_ERR("rdma_bind_addr failed\n");
+               goto fail;
+       }
+
+       result = rdma_listen(daemon_state->rdma.cm_id,
+                            SMB_DIRECT_LISTEN_BACKLOG);
+       if (result != 0) {
+               DBG_ERR("rdma_bind_addr failed\n");
+               goto fail;
        }
 
        conn->listening = true;
@@ -571,11 +604,11 @@ static NTSTATUS smbd_direct_daemon_listen(
 
        return NT_STATUS_OK;
 
-cleanup:
-       rdma_destroy_id(daemon_state->cm_id);
-       daemon_state->cm_id = NULL;
-       rdma_destroy_event_channel(daemon_state->cm_channel);
-       daemon_state->cm_channel = NULL;
+fail:
+       rdma_destroy_id(daemon_state->rdma.cm_id);
+       daemon_state->rdma.cm_id = NULL;
+       rdma_destroy_event_channel(daemon_state->rdma.cm_channel);
+       daemon_state->rdma.cm_channel = NULL;
        return NT_STATUS_INTERNAL_ERROR;
 }
 
@@ -690,19 +723,15 @@ static void smb_direct_daemon_conn_cleanup(struct tevent_req *req,
        daemon_state = conn->daemon_state;
        daemon_state->listening_conn = NULL;
 
-       result = rdma_destroy_event_channel(daemon_state->rdma_ec);
-       if (result != 0) {
-               DBG_ERR("rdma_destroy_event_channel failed [%s]\n",
-                       strerror(errno));
-       }
-       daemon_state->rdma_ec = 0;
+       rdma_destroy_event_channel(daemon_state->rdma.cm_channel);
+       daemon_state->rdma.cm_channel = NULL;
 
-       result = rdma_destroy_id(daemon_state->rdma_cm_id);
+       result = rdma_destroy_id(daemon_state->rdma.cm_id);
        if (result != 0) {
                DBG_ERR("rdma_destroy_id failed [%s]\n",
                        strerror(errno));
        }
-       daemon_state->rdma_cm_id = 0;
+       daemon_state->rdma.cm_id = NULL;
 }
 
 /**
@@ -735,12 +764,13 @@ static struct tevent_req *smb_direct_daemon_conn_send(
                .privileged = privileged,
        };
 
+       tevent_req_set_cleanup_fn(req, smb_direct_daemon_conn_cleanup);
+
        subreq = smbd_direct_daemon_read_send(conn);
        if (tevent_req_nomem(subreq, req)) {
                tevent_req_post(req, ev);
        }
        tevent_req_set_callback(subreq, smbd_direct_daemon_conn_handler, req);
-       tevent_req_set_cleanup_fn(subreq, smb_direct_daemon_conn_cleanup);
        return req;
 }
 
@@ -815,165 +845,89 @@ static void rdma_cm_handler(struct tevent_context *ev,
                            uint16_t flags,
                            void *private_data)
 {
-       struct smb_direct_daemon_conn *conn = talloc_get_type_abort(
-               private_data, struct smb_direct_daemon_conn);
-       struct smb_direct_daemon_state *daemon_state = conn->daemon_state;
+       struct smb_direct_daemon_state *daemon_state = talloc_get_type_abort(
+               private_data, struct smb_direct_daemon_state);
+       struct smb_direct_connection *sconn = NULL;
        struct rdma_cm_event *cm_ev = NULL;
-       struct rdma_cm_id *cm_id = NULL;
+       struct rdma_cm_event cm_ev_copy;
        int result;
 
-       result = rdma_get_cm_event(daemon_state->cm_channel, &cm_ev);
+       result = rdma_get_cm_event(daemon_state->rdma.cm_channel, &cm_ev);
        if (result != 0) {
                DBG_ERR("rdma_get_cm_event failed [%s]\n", strerror(errno));
-               goto fail;
+               return;
        }
 
-       cm_id = cm_ev->id;
-
-       DBG_DEBUG("cm_event type [%d]\n", cm_ev->event);
+       cm_ev_copy = *cm_ev;
+       result = rdma_ack_cm_event(cm_ev);
+       if (result != 0) {
+               DBG_ERR("rdma_ack_cm_event failed [%s]\n", strerror(errno));
+               goto fail;
+       }
+       cm_ev = NULL;
 
-       switch (cm_ev->event) {
+       DBG_DEBUG("cm_event type [%d] cm_id [%p]\n",
+                 cm_ev_copy.event, cm_ev_copy.id);
 
-       case RDMA_CM_EVENT_ADDR_RESOLVED:
-               DBG_DEBUG("RDMA_CM_EVENT_ADDR_RESOLVED\n");
+       switch (cm_ev_copy.event) {
+       case RDMA_CM_EVENT_CONNECT_REQUEST:
+               DBG_DEBUG("RDMA_CM_EVENT_CONNECT_REQUEST\n");
 
-               result = rdma_resolve_route(cm_id, 2000);
+               result = rdma_accept(cm_ev_copy.id, NULL);
                if (result != 0) {
-                       DBG_ERR("rdma_resolve_route failed [%s]\n", strerror(errno));
+                       DBG_ERR("rdma_accept failed [%s]\n", strerror(errno));
                        goto fail;
                }
-               break;
-
-       case RDMA_CM_EVENT_ROUTE_RESOLVED: {
-               DBG_DEBUG("RDMA_CM_EVENT_ROUTE_RESOLVED\n");
-
-               conn = talloc_get_type(cma_id->context, struct ibw_conn);
 
-               result = ibw_manage_connect(conn);
-               if (rc)
-                       goto error;
-
-               break;
-       }
-
-       case RDMA_CM_EVENT_CONNECT_REQUEST:
-               DEBUG(DEBUG_DEBUG, ("RDMA_CM_EVENT_CONNECT_REQUEST\n"));
-               ctx->state = IBWS_CONNECT_REQUEST;
-               conn = ibw_conn_new(ctx, ctx);
-               pconn = talloc_get_type(conn->internal, struct ibw_conn_priv);
-               pconn->cm_id = cma_id; /* !!! event will be freed but id not */
-               cma_id->context = (void *)conn;
-               DEBUG(DEBUG_DEBUG, ("pconn->cm_id %p\n", pconn->cm_id));
-
-               if (ibw_setup_cq_qp(conn))
-                       goto error;
-
-               conn->state = IBWC_INIT;
-               pctx->connstate_func(ctx, conn);
-
-               /* continued at ibw_accept when invoked by the func above */
-               if (!pconn->is_accepted) {
-                       rc = rdma_reject(cma_id, NULL, 0);
-                       if (rc)
-                               DEBUG(DEBUG_ERR, ("rdma_reject failed with rc=%d\n", rc));
-                       talloc_free(conn);
-                       DEBUG(DEBUG_DEBUG, ("pconn->cm_id %p wasn't accepted\n", pconn->cm_id));
+               sconn = smb_direct_connection_listener(daemon_state,
+                                                      cm_ev_copy.id);
+               if (sconn == NULL) {
+                       DBG_ERR("smb_direct_connection_create failed\n");
+                       return;
                }
 
-               /* TODO: clarify whether if it's needed by upper layer: */
-               ctx->state = IBWS_READY;
-               pctx->connstate_func(ctx, NULL);
-
-               /* NOTE: more requests can arrive until RDMA_CM_EVENT_ESTABLISHED ! */
+               cm_ev_copy.id->context = sconn;
                break;
 
        case RDMA_CM_EVENT_ESTABLISHED:
-               /* expected after ibw_accept and ibw_connect[not directly] */
-               DEBUG(DEBUG_INFO, ("ESTABLISHED (conn: %p)\n", cma_id->context));
-               conn = talloc_get_type(cma_id->context, struct ibw_conn);
-               assert(conn!=NULL); /* important assumption */
-
-               DEBUG(DEBUG_DEBUG, ("ibw_setup_cq_qp succeeded (cmid=%p)\n", cma_id));
-
-               /* client conn is up */
-               conn->state = IBWC_CONNECTED;
-
-               /* both ctx and conn have changed */
-               pctx->connstate_func(ctx, conn);
+               DBG_DEBUG("RDMA_CM_EVENT_ESTABLISHED\n");
+
+               sconn = talloc_get_type_abort(cm_ev_copy.id->context,
+                                             struct smb_direct_connection);
+               sconn = smb_direct_connection_complete_alloc(sconn);
+               /*
+                * TODO: get things going...
+                */
                break;
 
-       case RDMA_CM_EVENT_ADDR_ERROR:
-               sprintf(ibw_lasterr, "RDMA_CM_EVENT_ADDR_ERROR, error %d\n", event->status);
-       case RDMA_CM_EVENT_ROUTE_ERROR:
-               sprintf(ibw_lasterr, "RDMA_CM_EVENT_ROUTE_ERROR, error %d\n", event->status);
-       case RDMA_CM_EVENT_CONNECT_ERROR:
-               sprintf(ibw_lasterr, "RDMA_CM_EVENT_CONNECT_ERROR, error %d\n", event->status);
-       case RDMA_CM_EVENT_UNREACHABLE:
-               sprintf(ibw_lasterr, "RDMA_CM_EVENT_UNREACHABLE, error %d\n", event->status);
-               goto error;
-       case RDMA_CM_EVENT_REJECTED:
-               sprintf(ibw_lasterr, "RDMA_CM_EVENT_REJECTED, error %d\n", event->status);
-               DEBUG(DEBUG_INFO, ("cm event handler: %s", ibw_lasterr));
-               conn = talloc_get_type(cma_id->context, struct ibw_conn);
-               if (conn) {
-                       /* must be done BEFORE connstate */
-                       if ((rc=rdma_ack_cm_event(event)))
-                               DEBUG(DEBUG_ERR, ("reject/rdma_ack_cm_event failed with %d\n", rc));
-                       event = NULL; /* not to touch cma_id or conn */
-                       conn->state = IBWC_ERROR;
-                       /* it should free the conn */
-                       pctx->connstate_func(NULL, conn);
-               }
-               break; /* this is not strictly an error */
-
        case RDMA_CM_EVENT_DISCONNECTED:
-               DEBUG(DEBUG_DEBUG, ("RDMA_CM_EVENT_DISCONNECTED\n"));
-               if ((rc=rdma_ack_cm_event(event)))
-                       DEBUG(DEBUG_ERR, ("disc/rdma_ack_cm_event failed with %d\n", rc));
-               event = NULL; /* don't ack more */
-
-               if (cma_id!=pctx->cm_id) {
-                       DEBUG(DEBUG_ERR, ("client DISCONNECT event cm_id=%p\n", cma_id));
-                       conn = talloc_get_type(cma_id->context, struct ibw_conn);
-                       conn->state = IBWC_DISCONNECTED;
-                       pctx->connstate_func(NULL, conn);
-               }
+               DBG_DEBUG("RDMA_CM_EVENT_DISCONNECTED\n");
+
+               sconn = talloc_get_type(cm_ev_copy.id->context,
+                                       struct smb_direct_connection);
+               TALLOC_FREE(sconn);
                break;
 
        case RDMA_CM_EVENT_DEVICE_REMOVAL:
-               sprintf(ibw_lasterr, "cma detected device removal!\n");
-               goto error;
+               DBG_ERR("RDMA device removal\n");
+               goto fail;
 
        default:
-               sprintf(ibw_lasterr, "unknown event %d\n", event->event);
-               goto error;
+               DBG_ERR("event %d\n", cm_ev_copy.event);
+               goto fail;
        }
 
-       if (event!=NULL && (rc=rdma_ack_cm_event(event))) {
-               sprintf(ibw_lasterr, "rdma_ack_cm_event failed with %d\n", rc);
-               goto error;
-       }
 
        return;
-error:
-       DEBUG(DEBUG_ERR, ("cm event handler: %s", ibw_lasterr));
-
-       if (event!=NULL) {
-               if (cma_id!=NULL && cma_id!=pctx->cm_id) {
-                       conn = talloc_get_type(cma_id->context, struct ibw_conn);
-                       if (conn) {
-                               conn->state = IBWC_ERROR;
-                               pctx->connstate_func(NULL, conn);
-                       }
-               } else {
-                       ctx->state = IBWS_ERROR;
-                       pctx->connstate_func(ctx, NULL);
-               }
 
-               if ((rc=rdma_ack_cm_event(event))!=0) {
-                       DEBUG(DEBUG_ERR, ("rdma_ack_cm_event failed with %d\n", rc));
-               }
+fail:
+       if (cm_ev_copy.id == daemon_state->rdma.cm_id) {
+               /* Listening conn is erroring out, shut it down and die */
+               TALLOC_FREE(daemon_state->listening_conn);
        }
 
+       TALLOC_FREE(sconn);
        return;
 }
+
+#endif /* SMB_TRANSPORT_ENABLE_RDMA */