Commit 50cb6a04 authored by Seth Howell's avatar Seth Howell Committed by Tomasz Zawadzki
Browse files

lib/nvmf: handle RDMA_CM_EVENT_ADDR_CHANGE



This allows features like transparent failover on
target RNICs.

Signed-off-by: default avatarSeth Howell <seth.howell@intel.com>
Change-Id: Iab494ad3e9e4efea4db9cbb30bc18ea5b584f345
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/478879


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatar <jacek.kalwas@intel.com>
Reviewed-by: default avatarAlexey Marchuk <alexeymar@mellanox.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
parent 12ae64f8
Loading
Loading
Loading
Loading
+52 −3
Original line number Diff line number Diff line
@@ -2959,12 +2959,59 @@ static const char *CM_EVENT_STR[] = {
};
#endif /* DEBUG */

static bool
nvmf_rdma_handle_cm_event_addr_change(struct spdk_nvmf_transport *transport,
				      struct rdma_cm_event *event)
{
	struct spdk_nvme_transport_id		trid;
	struct spdk_nvmf_rdma_qpair		*rqpair;
	struct spdk_nvmf_rdma_poll_group	*rgroup;
	struct spdk_nvmf_rdma_poller		*rpoller;
	struct spdk_nvmf_rdma_port		*port;
	struct spdk_nvmf_rdma_transport		*rtransport;
	uint32_t				ref, i;
	bool					event_acked = false;

	rtransport = SPDK_CONTAINEROF(transport, struct spdk_nvmf_rdma_transport, transport);
	TAILQ_FOREACH(port, &rtransport->ports, link) {
		if (port->id == event->id) {
			SPDK_ERRLOG("ADDR_CHANGE: IP %s:%s migrated\n", port->trid.traddr, port->trid.trsvcid);
			rdma_ack_cm_event(event);
			event_acked = true;
			trid = port->trid;
			ref = port->ref;
			break;
		}
	}
	if (event_acked) {
		TAILQ_FOREACH(rgroup, &rtransport->poll_groups, link) {
			TAILQ_FOREACH(rpoller, &rgroup->pollers, link) {
				TAILQ_FOREACH(rqpair, &rpoller->qpairs, link) {
					if (rqpair->listen_id == port->id) {
						spdk_nvmf_rdma_start_disconnect(rqpair);
					}
				}
			}
		}

		for (i = 0; i < ref; i++) {
			spdk_nvmf_rdma_stop_listen(transport, &trid);
		}
		while (ref > 0) {
			spdk_nvmf_rdma_listen(transport, &trid);
			ref--;
		}
	}
	return event_acked;
}

static void
spdk_nvmf_process_cm_event(struct spdk_nvmf_transport *transport, new_qpair_fn cb_fn, void *cb_arg)
{
	struct spdk_nvmf_rdma_transport *rtransport;
	struct rdma_cm_event		*event;
	int				rc;
	bool				event_acked;

	rtransport = SPDK_CONTAINEROF(transport, struct spdk_nvmf_rdma_transport, transport);

@@ -2973,6 +3020,7 @@ spdk_nvmf_process_cm_event(struct spdk_nvmf_transport *transport, new_qpair_fn c
	}

	while (1) {
		event_acked = false;
		rc = rdma_get_cm_event(rtransport->event_channel, &event);
		if (rc == 0) {
			SPDK_DEBUGLOG(SPDK_LOG_RDMA, "Acceptor Event: %s\n", CM_EVENT_STR[event->event]);
@@ -3019,7 +3067,7 @@ spdk_nvmf_process_cm_event(struct spdk_nvmf_transport *transport, new_qpair_fn c
				/* Multicast is not used */
				break;
			case RDMA_CM_EVENT_ADDR_CHANGE:
				/* Not utilizing this event */
				event_acked = nvmf_rdma_handle_cm_event_addr_change(transport, event);
				break;
			case RDMA_CM_EVENT_TIMEWAIT_EXIT:
				/* For now, do nothing. The target never re-uses queue pairs. */
@@ -3028,8 +3076,9 @@ spdk_nvmf_process_cm_event(struct spdk_nvmf_transport *transport, new_qpair_fn c
				SPDK_ERRLOG("Unexpected Acceptor Event [%d]\n", event->event);
				break;
			}

			if (!event_acked) {
				rdma_ack_cm_event(event);
			}
		} else {
			if (errno != EAGAIN && errno != EWOULDBLOCK) {
				SPDK_ERRLOG("Acceptor Event Error: %s\n", spdk_strerror(errno));