xref: /f-stack/dpdk/drivers/net/memif/memif_socket.c (revision 0c6bd470)
14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang  * Copyright 2018-2019 Cisco Systems, Inc.  All rights reserved.
34418919fSjohnjiang  */
44418919fSjohnjiang 
54418919fSjohnjiang #include <stdlib.h>
64418919fSjohnjiang #include <fcntl.h>
74418919fSjohnjiang #include <unistd.h>
84418919fSjohnjiang #include <sys/types.h>
94418919fSjohnjiang #include <sys/socket.h>
104418919fSjohnjiang #include <sys/ioctl.h>
114418919fSjohnjiang #include <errno.h>
124418919fSjohnjiang 
134418919fSjohnjiang #include <rte_version.h>
144418919fSjohnjiang #include <rte_mbuf.h>
154418919fSjohnjiang #include <rte_ether.h>
164418919fSjohnjiang #include <rte_ethdev_driver.h>
174418919fSjohnjiang #include <rte_ethdev_vdev.h>
184418919fSjohnjiang #include <rte_malloc.h>
194418919fSjohnjiang #include <rte_kvargs.h>
204418919fSjohnjiang #include <rte_bus_vdev.h>
214418919fSjohnjiang #include <rte_hash.h>
224418919fSjohnjiang #include <rte_jhash.h>
234418919fSjohnjiang #include <rte_string_fns.h>
244418919fSjohnjiang 
254418919fSjohnjiang #include "rte_eth_memif.h"
264418919fSjohnjiang #include "memif_socket.h"
274418919fSjohnjiang 
284418919fSjohnjiang static void memif_intr_handler(void *arg);
294418919fSjohnjiang 
304418919fSjohnjiang static ssize_t
314418919fSjohnjiang memif_msg_send(int fd, memif_msg_t *msg, int afd)
324418919fSjohnjiang {
334418919fSjohnjiang 	struct msghdr mh = { 0 };
344418919fSjohnjiang 	struct iovec iov[1];
354418919fSjohnjiang 	struct cmsghdr *cmsg;
364418919fSjohnjiang 	char ctl[CMSG_SPACE(sizeof(int))];
374418919fSjohnjiang 
384418919fSjohnjiang 	iov[0].iov_base = msg;
394418919fSjohnjiang 	iov[0].iov_len = sizeof(memif_msg_t);
404418919fSjohnjiang 	mh.msg_iov = iov;
414418919fSjohnjiang 	mh.msg_iovlen = 1;
424418919fSjohnjiang 
434418919fSjohnjiang 	if (afd > 0) {
444418919fSjohnjiang 		memset(&ctl, 0, sizeof(ctl));
454418919fSjohnjiang 		mh.msg_control = ctl;
464418919fSjohnjiang 		mh.msg_controllen = sizeof(ctl);
474418919fSjohnjiang 		cmsg = CMSG_FIRSTHDR(&mh);
484418919fSjohnjiang 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
494418919fSjohnjiang 		cmsg->cmsg_level = SOL_SOCKET;
504418919fSjohnjiang 		cmsg->cmsg_type = SCM_RIGHTS;
514418919fSjohnjiang 		rte_memcpy(CMSG_DATA(cmsg), &afd, sizeof(int));
524418919fSjohnjiang 	}
534418919fSjohnjiang 
544418919fSjohnjiang 	return sendmsg(fd, &mh, 0);
554418919fSjohnjiang }
564418919fSjohnjiang 
574418919fSjohnjiang static int
584418919fSjohnjiang memif_msg_send_from_queue(struct memif_control_channel *cc)
594418919fSjohnjiang {
604418919fSjohnjiang 	ssize_t size;
614418919fSjohnjiang 	int ret = 0;
624418919fSjohnjiang 	struct memif_msg_queue_elt *e;
634418919fSjohnjiang 
644418919fSjohnjiang 	e = TAILQ_FIRST(&cc->msg_queue);
654418919fSjohnjiang 	if (e == NULL)
664418919fSjohnjiang 		return 0;
674418919fSjohnjiang 
684418919fSjohnjiang 	size = memif_msg_send(cc->intr_handle.fd, &e->msg, e->fd);
694418919fSjohnjiang 	if (size != sizeof(memif_msg_t)) {
704418919fSjohnjiang 		MIF_LOG(ERR, "sendmsg fail: %s.", strerror(errno));
714418919fSjohnjiang 		ret = -1;
724418919fSjohnjiang 	} else {
734418919fSjohnjiang 		MIF_LOG(DEBUG, "Sent msg type %u.", e->msg.type);
744418919fSjohnjiang 	}
754418919fSjohnjiang 	TAILQ_REMOVE(&cc->msg_queue, e, next);
764418919fSjohnjiang 	rte_free(e);
774418919fSjohnjiang 
784418919fSjohnjiang 	return ret;
794418919fSjohnjiang }
804418919fSjohnjiang 
814418919fSjohnjiang static struct memif_msg_queue_elt *
824418919fSjohnjiang memif_msg_enq(struct memif_control_channel *cc)
834418919fSjohnjiang {
844418919fSjohnjiang 	struct memif_msg_queue_elt *e;
854418919fSjohnjiang 
864418919fSjohnjiang 	e = rte_zmalloc("memif_msg", sizeof(struct memif_msg_queue_elt), 0);
874418919fSjohnjiang 	if (e == NULL) {
884418919fSjohnjiang 		MIF_LOG(ERR, "Failed to allocate control message.");
894418919fSjohnjiang 		return NULL;
904418919fSjohnjiang 	}
914418919fSjohnjiang 
924418919fSjohnjiang 	e->fd = -1;
934418919fSjohnjiang 	TAILQ_INSERT_TAIL(&cc->msg_queue, e, next);
944418919fSjohnjiang 
954418919fSjohnjiang 	return e;
964418919fSjohnjiang }
974418919fSjohnjiang 
984418919fSjohnjiang void
994418919fSjohnjiang memif_msg_enq_disconnect(struct memif_control_channel *cc, const char *reason,
1004418919fSjohnjiang 			 int err_code)
1014418919fSjohnjiang {
1024418919fSjohnjiang 	struct memif_msg_queue_elt *e;
1034418919fSjohnjiang 	struct pmd_internals *pmd;
1044418919fSjohnjiang 	memif_msg_disconnect_t *d;
1054418919fSjohnjiang 
1064418919fSjohnjiang 	if (cc == NULL) {
1074418919fSjohnjiang 		MIF_LOG(DEBUG, "Missing control channel.");
1084418919fSjohnjiang 		return;
1094418919fSjohnjiang 	}
1104418919fSjohnjiang 
1114418919fSjohnjiang 	e = memif_msg_enq(cc);
1124418919fSjohnjiang 	if (e == NULL) {
1134418919fSjohnjiang 		MIF_LOG(WARNING, "Failed to enqueue disconnect message.");
1144418919fSjohnjiang 		return;
1154418919fSjohnjiang 	}
1164418919fSjohnjiang 
1174418919fSjohnjiang 	d = &e->msg.disconnect;
1184418919fSjohnjiang 
1194418919fSjohnjiang 	e->msg.type = MEMIF_MSG_TYPE_DISCONNECT;
1204418919fSjohnjiang 	d->code = err_code;
1214418919fSjohnjiang 
1224418919fSjohnjiang 	if (reason != NULL) {
1234418919fSjohnjiang 		strlcpy((char *)d->string, reason, sizeof(d->string));
1244418919fSjohnjiang 		if (cc->dev != NULL) {
1254418919fSjohnjiang 			pmd = cc->dev->data->dev_private;
1264418919fSjohnjiang 			strlcpy(pmd->local_disc_string, reason,
1274418919fSjohnjiang 				sizeof(pmd->local_disc_string));
1284418919fSjohnjiang 		}
1294418919fSjohnjiang 	}
1304418919fSjohnjiang }
1314418919fSjohnjiang 
1324418919fSjohnjiang static int
1334418919fSjohnjiang memif_msg_enq_hello(struct memif_control_channel *cc)
1344418919fSjohnjiang {
1354418919fSjohnjiang 	struct memif_msg_queue_elt *e = memif_msg_enq(cc);
1364418919fSjohnjiang 	memif_msg_hello_t *h;
1374418919fSjohnjiang 
1384418919fSjohnjiang 	if (e == NULL)
1394418919fSjohnjiang 		return -1;
1404418919fSjohnjiang 
1414418919fSjohnjiang 	h = &e->msg.hello;
1424418919fSjohnjiang 
1434418919fSjohnjiang 	e->msg.type = MEMIF_MSG_TYPE_HELLO;
1444418919fSjohnjiang 	h->min_version = MEMIF_VERSION;
1454418919fSjohnjiang 	h->max_version = MEMIF_VERSION;
1464418919fSjohnjiang 	h->max_s2m_ring = ETH_MEMIF_MAX_NUM_Q_PAIRS;
1474418919fSjohnjiang 	h->max_m2s_ring = ETH_MEMIF_MAX_NUM_Q_PAIRS;
1484418919fSjohnjiang 	h->max_region = ETH_MEMIF_MAX_REGION_NUM - 1;
1494418919fSjohnjiang 	h->max_log2_ring_size = ETH_MEMIF_MAX_LOG2_RING_SIZE;
1504418919fSjohnjiang 
1514418919fSjohnjiang 	strlcpy((char *)h->name, rte_version(), sizeof(h->name));
1524418919fSjohnjiang 
1534418919fSjohnjiang 	return 0;
1544418919fSjohnjiang }
1554418919fSjohnjiang 
1564418919fSjohnjiang static int
1574418919fSjohnjiang memif_msg_receive_hello(struct rte_eth_dev *dev, memif_msg_t *msg)
1584418919fSjohnjiang {
1594418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
1604418919fSjohnjiang 	memif_msg_hello_t *h = &msg->hello;
1614418919fSjohnjiang 
1624418919fSjohnjiang 	if (h->min_version > MEMIF_VERSION || h->max_version < MEMIF_VERSION) {
1634418919fSjohnjiang 		memif_msg_enq_disconnect(pmd->cc, "Incompatible memif version", 0);
1644418919fSjohnjiang 		return -1;
1654418919fSjohnjiang 	}
1664418919fSjohnjiang 
1674418919fSjohnjiang 	/* Set parameters for active connection */
1684418919fSjohnjiang 	pmd->run.num_s2m_rings = RTE_MIN(h->max_s2m_ring + 1,
1694418919fSjohnjiang 					   pmd->cfg.num_s2m_rings);
1704418919fSjohnjiang 	pmd->run.num_m2s_rings = RTE_MIN(h->max_m2s_ring + 1,
1714418919fSjohnjiang 					   pmd->cfg.num_m2s_rings);
1724418919fSjohnjiang 	pmd->run.log2_ring_size = RTE_MIN(h->max_log2_ring_size,
1734418919fSjohnjiang 					    pmd->cfg.log2_ring_size);
1744418919fSjohnjiang 	pmd->run.pkt_buffer_size = pmd->cfg.pkt_buffer_size;
1754418919fSjohnjiang 
1764418919fSjohnjiang 	strlcpy(pmd->remote_name, (char *)h->name, sizeof(pmd->remote_name));
1774418919fSjohnjiang 
1784418919fSjohnjiang 	MIF_LOG(DEBUG, "Connecting to %s.", pmd->remote_name);
1794418919fSjohnjiang 
1804418919fSjohnjiang 	return 0;
1814418919fSjohnjiang }
1824418919fSjohnjiang 
1834418919fSjohnjiang static int
1844418919fSjohnjiang memif_msg_receive_init(struct memif_control_channel *cc, memif_msg_t *msg)
1854418919fSjohnjiang {
1864418919fSjohnjiang 	memif_msg_init_t *i = &msg->init;
1874418919fSjohnjiang 	struct memif_socket_dev_list_elt *elt;
1884418919fSjohnjiang 	struct pmd_internals *pmd;
1894418919fSjohnjiang 	struct rte_eth_dev *dev;
1904418919fSjohnjiang 
1914418919fSjohnjiang 	if (i->version != MEMIF_VERSION) {
1924418919fSjohnjiang 		memif_msg_enq_disconnect(cc, "Incompatible memif version", 0);
1934418919fSjohnjiang 		return -1;
1944418919fSjohnjiang 	}
1954418919fSjohnjiang 
1964418919fSjohnjiang 	if (cc->socket == NULL) {
1974418919fSjohnjiang 		memif_msg_enq_disconnect(cc, "Device error", 0);
1984418919fSjohnjiang 		return -1;
1994418919fSjohnjiang 	}
2004418919fSjohnjiang 
2014418919fSjohnjiang 	/* Find device with requested ID */
2024418919fSjohnjiang 	TAILQ_FOREACH(elt, &cc->socket->dev_queue, next) {
2034418919fSjohnjiang 		dev = elt->dev;
2044418919fSjohnjiang 		pmd = dev->data->dev_private;
2054418919fSjohnjiang 		if (((pmd->flags & ETH_MEMIF_FLAG_DISABLED) == 0) &&
2064418919fSjohnjiang 		    pmd->id == i->id) {
207*0c6bd470Sfengbojiang 			if (pmd->flags & (ETH_MEMIF_FLAG_CONNECTING |
208*0c6bd470Sfengbojiang 					   ETH_MEMIF_FLAG_CONNECTED)) {
209*0c6bd470Sfengbojiang 				memif_msg_enq_disconnect(cc,
210*0c6bd470Sfengbojiang 							 "Already connected", 0);
211*0c6bd470Sfengbojiang 				return -1;
212*0c6bd470Sfengbojiang 			}
213*0c6bd470Sfengbojiang 
2144418919fSjohnjiang 			/* assign control channel to device */
2154418919fSjohnjiang 			cc->dev = dev;
2164418919fSjohnjiang 			pmd->cc = cc;
2174418919fSjohnjiang 
2184418919fSjohnjiang 			if (i->mode != MEMIF_INTERFACE_MODE_ETHERNET) {
2194418919fSjohnjiang 				memif_msg_enq_disconnect(pmd->cc,
2204418919fSjohnjiang 							 "Only ethernet mode supported",
2214418919fSjohnjiang 							 0);
2224418919fSjohnjiang 				return -1;
2234418919fSjohnjiang 			}
2244418919fSjohnjiang 
2254418919fSjohnjiang 			strlcpy(pmd->remote_name, (char *)i->name,
2264418919fSjohnjiang 				sizeof(pmd->remote_name));
2274418919fSjohnjiang 
2284418919fSjohnjiang 			if (*pmd->secret != '\0') {
2294418919fSjohnjiang 				if (*i->secret == '\0') {
2304418919fSjohnjiang 					memif_msg_enq_disconnect(pmd->cc,
2314418919fSjohnjiang 								 "Secret required", 0);
2324418919fSjohnjiang 					return -1;
2334418919fSjohnjiang 				}
2344418919fSjohnjiang 				if (strncmp(pmd->secret, (char *)i->secret,
2354418919fSjohnjiang 						ETH_MEMIF_SECRET_SIZE) != 0) {
2364418919fSjohnjiang 					memif_msg_enq_disconnect(pmd->cc,
2374418919fSjohnjiang 								 "Incorrect secret", 0);
2384418919fSjohnjiang 					return -1;
2394418919fSjohnjiang 				}
2404418919fSjohnjiang 			}
2414418919fSjohnjiang 
2424418919fSjohnjiang 			pmd->flags |= ETH_MEMIF_FLAG_CONNECTING;
2434418919fSjohnjiang 			return 0;
2444418919fSjohnjiang 		}
2454418919fSjohnjiang 	}
2464418919fSjohnjiang 
2474418919fSjohnjiang 	/* ID not found on this socket */
2484418919fSjohnjiang 	MIF_LOG(DEBUG, "ID %u not found.", i->id);
2494418919fSjohnjiang 	memif_msg_enq_disconnect(cc, "ID not found", 0);
2504418919fSjohnjiang 	return -1;
2514418919fSjohnjiang }
2524418919fSjohnjiang 
2534418919fSjohnjiang static int
2544418919fSjohnjiang memif_msg_receive_add_region(struct rte_eth_dev *dev, memif_msg_t *msg,
2554418919fSjohnjiang 			     int fd)
2564418919fSjohnjiang {
2574418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
2584418919fSjohnjiang 	struct pmd_process_private *proc_private = dev->process_private;
2594418919fSjohnjiang 	memif_msg_add_region_t *ar = &msg->add_region;
2604418919fSjohnjiang 	struct memif_region *r;
2614418919fSjohnjiang 
2624418919fSjohnjiang 	if (fd < 0) {
2634418919fSjohnjiang 		memif_msg_enq_disconnect(pmd->cc, "Missing region fd", 0);
2644418919fSjohnjiang 		return -1;
2654418919fSjohnjiang 	}
2664418919fSjohnjiang 
2674418919fSjohnjiang 	if (ar->index >= ETH_MEMIF_MAX_REGION_NUM ||
2684418919fSjohnjiang 			ar->index != proc_private->regions_num ||
2694418919fSjohnjiang 			proc_private->regions[ar->index] != NULL) {
2704418919fSjohnjiang 		memif_msg_enq_disconnect(pmd->cc, "Invalid region index", 0);
2714418919fSjohnjiang 		return -1;
2724418919fSjohnjiang 	}
2734418919fSjohnjiang 
2744418919fSjohnjiang 	r = rte_zmalloc("region", sizeof(struct memif_region), 0);
2754418919fSjohnjiang 	if (r == NULL) {
2764418919fSjohnjiang 		memif_msg_enq_disconnect(pmd->cc, "Failed to alloc memif region.", 0);
2774418919fSjohnjiang 		return -ENOMEM;
2784418919fSjohnjiang 	}
2794418919fSjohnjiang 
2804418919fSjohnjiang 	r->fd = fd;
2814418919fSjohnjiang 	r->region_size = ar->size;
2824418919fSjohnjiang 	r->addr = NULL;
2834418919fSjohnjiang 
2844418919fSjohnjiang 	proc_private->regions[ar->index] = r;
2854418919fSjohnjiang 	proc_private->regions_num++;
2864418919fSjohnjiang 
2874418919fSjohnjiang 	return 0;
2884418919fSjohnjiang }
2894418919fSjohnjiang 
2904418919fSjohnjiang static int
2914418919fSjohnjiang memif_msg_receive_add_ring(struct rte_eth_dev *dev, memif_msg_t *msg, int fd)
2924418919fSjohnjiang {
2934418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
2944418919fSjohnjiang 	memif_msg_add_ring_t *ar = &msg->add_ring;
2954418919fSjohnjiang 	struct memif_queue *mq;
2964418919fSjohnjiang 
2974418919fSjohnjiang 	if (fd < 0) {
2984418919fSjohnjiang 		memif_msg_enq_disconnect(pmd->cc, "Missing interrupt fd", 0);
2994418919fSjohnjiang 		return -1;
3004418919fSjohnjiang 	}
3014418919fSjohnjiang 
3024418919fSjohnjiang 	/* check if we have enough queues */
3034418919fSjohnjiang 	if (ar->flags & MEMIF_MSG_ADD_RING_FLAG_S2M) {
3044418919fSjohnjiang 		if (ar->index >= pmd->cfg.num_s2m_rings) {
3054418919fSjohnjiang 			memif_msg_enq_disconnect(pmd->cc, "Invalid ring index", 0);
3064418919fSjohnjiang 			return -1;
3074418919fSjohnjiang 		}
3084418919fSjohnjiang 		pmd->run.num_s2m_rings++;
3094418919fSjohnjiang 	} else {
3104418919fSjohnjiang 		if (ar->index >= pmd->cfg.num_m2s_rings) {
3114418919fSjohnjiang 			memif_msg_enq_disconnect(pmd->cc, "Invalid ring index", 0);
3124418919fSjohnjiang 			return -1;
3134418919fSjohnjiang 		}
3144418919fSjohnjiang 		pmd->run.num_m2s_rings++;
3154418919fSjohnjiang 	}
3164418919fSjohnjiang 
3174418919fSjohnjiang 	mq = (ar->flags & MEMIF_MSG_ADD_RING_FLAG_S2M) ?
3184418919fSjohnjiang 	    dev->data->rx_queues[ar->index] : dev->data->tx_queues[ar->index];
3194418919fSjohnjiang 
3204418919fSjohnjiang 	mq->intr_handle.fd = fd;
3214418919fSjohnjiang 	mq->log2_ring_size = ar->log2_ring_size;
3224418919fSjohnjiang 	mq->region = ar->region;
3234418919fSjohnjiang 	mq->ring_offset = ar->offset;
3244418919fSjohnjiang 
3254418919fSjohnjiang 	return 0;
3264418919fSjohnjiang }
3274418919fSjohnjiang 
3284418919fSjohnjiang static int
3294418919fSjohnjiang memif_msg_receive_connect(struct rte_eth_dev *dev, memif_msg_t *msg)
3304418919fSjohnjiang {
3314418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
3324418919fSjohnjiang 	memif_msg_connect_t *c = &msg->connect;
3334418919fSjohnjiang 	int ret;
3344418919fSjohnjiang 
3354418919fSjohnjiang 	ret = memif_connect(dev);
3364418919fSjohnjiang 	if (ret < 0)
3374418919fSjohnjiang 		return ret;
3384418919fSjohnjiang 
3394418919fSjohnjiang 	strlcpy(pmd->remote_if_name, (char *)c->if_name,
3404418919fSjohnjiang 		sizeof(pmd->remote_if_name));
3414418919fSjohnjiang 	MIF_LOG(INFO, "Remote interface %s connected.", pmd->remote_if_name);
3424418919fSjohnjiang 
3434418919fSjohnjiang 	return 0;
3444418919fSjohnjiang }
3454418919fSjohnjiang 
3464418919fSjohnjiang static int
3474418919fSjohnjiang memif_msg_receive_connected(struct rte_eth_dev *dev, memif_msg_t *msg)
3484418919fSjohnjiang {
3494418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
3504418919fSjohnjiang 	memif_msg_connected_t *c = &msg->connected;
3514418919fSjohnjiang 	int ret;
3524418919fSjohnjiang 
3534418919fSjohnjiang 	ret = memif_connect(dev);
3544418919fSjohnjiang 	if (ret < 0)
3554418919fSjohnjiang 		return ret;
3564418919fSjohnjiang 
3574418919fSjohnjiang 	strlcpy(pmd->remote_if_name, (char *)c->if_name,
3584418919fSjohnjiang 		sizeof(pmd->remote_if_name));
3594418919fSjohnjiang 	MIF_LOG(INFO, "Remote interface %s connected.", pmd->remote_if_name);
3604418919fSjohnjiang 
3614418919fSjohnjiang 	return 0;
3624418919fSjohnjiang }
3634418919fSjohnjiang 
3644418919fSjohnjiang static int
3654418919fSjohnjiang memif_msg_receive_disconnect(struct rte_eth_dev *dev, memif_msg_t *msg)
3664418919fSjohnjiang {
3674418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
3684418919fSjohnjiang 	memif_msg_disconnect_t *d = &msg->disconnect;
3694418919fSjohnjiang 
3704418919fSjohnjiang 	memset(pmd->remote_disc_string, 0, sizeof(pmd->remote_disc_string));
3714418919fSjohnjiang 	strlcpy(pmd->remote_disc_string, (char *)d->string,
3724418919fSjohnjiang 		sizeof(pmd->remote_disc_string));
3734418919fSjohnjiang 
3744418919fSjohnjiang 	MIF_LOG(INFO, "Disconnect received: %s", pmd->remote_disc_string);
3754418919fSjohnjiang 
3764418919fSjohnjiang 	memset(pmd->local_disc_string, 0, 96);
3774418919fSjohnjiang 	memif_disconnect(dev);
3784418919fSjohnjiang 	return 0;
3794418919fSjohnjiang }
3804418919fSjohnjiang 
3814418919fSjohnjiang static int
3824418919fSjohnjiang memif_msg_enq_ack(struct rte_eth_dev *dev)
3834418919fSjohnjiang {
3844418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
3854418919fSjohnjiang 	struct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);
3864418919fSjohnjiang 	if (e == NULL)
3874418919fSjohnjiang 		return -1;
3884418919fSjohnjiang 
3894418919fSjohnjiang 	e->msg.type = MEMIF_MSG_TYPE_ACK;
3904418919fSjohnjiang 
3914418919fSjohnjiang 	return 0;
3924418919fSjohnjiang }
3934418919fSjohnjiang 
3944418919fSjohnjiang static int
3954418919fSjohnjiang memif_msg_enq_init(struct rte_eth_dev *dev)
3964418919fSjohnjiang {
3974418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
3984418919fSjohnjiang 	struct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);
3994418919fSjohnjiang 	memif_msg_init_t *i = &e->msg.init;
4004418919fSjohnjiang 
4014418919fSjohnjiang 	if (e == NULL)
4024418919fSjohnjiang 		return -1;
4034418919fSjohnjiang 
4044418919fSjohnjiang 	i = &e->msg.init;
4054418919fSjohnjiang 	e->msg.type = MEMIF_MSG_TYPE_INIT;
4064418919fSjohnjiang 	i->version = MEMIF_VERSION;
4074418919fSjohnjiang 	i->id = pmd->id;
4084418919fSjohnjiang 	i->mode = MEMIF_INTERFACE_MODE_ETHERNET;
4094418919fSjohnjiang 
4104418919fSjohnjiang 	strlcpy((char *)i->name, rte_version(), sizeof(i->name));
4114418919fSjohnjiang 
4124418919fSjohnjiang 	if (*pmd->secret != '\0')
4134418919fSjohnjiang 		strlcpy((char *)i->secret, pmd->secret, sizeof(i->secret));
4144418919fSjohnjiang 
4154418919fSjohnjiang 	return 0;
4164418919fSjohnjiang }
4174418919fSjohnjiang 
4184418919fSjohnjiang static int
4194418919fSjohnjiang memif_msg_enq_add_region(struct rte_eth_dev *dev, uint8_t idx)
4204418919fSjohnjiang {
4214418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
4224418919fSjohnjiang 	struct pmd_process_private *proc_private = dev->process_private;
4234418919fSjohnjiang 	struct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);
4244418919fSjohnjiang 	memif_msg_add_region_t *ar;
4254418919fSjohnjiang 	struct memif_region *mr = proc_private->regions[idx];
4264418919fSjohnjiang 
4274418919fSjohnjiang 	if (e == NULL)
4284418919fSjohnjiang 		return -1;
4294418919fSjohnjiang 
4304418919fSjohnjiang 	ar = &e->msg.add_region;
4314418919fSjohnjiang 	e->msg.type = MEMIF_MSG_TYPE_ADD_REGION;
4324418919fSjohnjiang 	e->fd = mr->fd;
4334418919fSjohnjiang 	ar->index = idx;
4344418919fSjohnjiang 	ar->size = mr->region_size;
4354418919fSjohnjiang 
4364418919fSjohnjiang 	return 0;
4374418919fSjohnjiang }
4384418919fSjohnjiang 
4394418919fSjohnjiang static int
4404418919fSjohnjiang memif_msg_enq_add_ring(struct rte_eth_dev *dev, uint8_t idx,
4414418919fSjohnjiang 		       memif_ring_type_t type)
4424418919fSjohnjiang {
4434418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
4444418919fSjohnjiang 	struct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);
4454418919fSjohnjiang 	struct memif_queue *mq;
4464418919fSjohnjiang 	memif_msg_add_ring_t *ar;
4474418919fSjohnjiang 
4484418919fSjohnjiang 	if (e == NULL)
4494418919fSjohnjiang 		return -1;
4504418919fSjohnjiang 
4514418919fSjohnjiang 	ar = &e->msg.add_ring;
4524418919fSjohnjiang 	mq = (type == MEMIF_RING_S2M) ? dev->data->tx_queues[idx] :
4534418919fSjohnjiang 	    dev->data->rx_queues[idx];
4544418919fSjohnjiang 
4554418919fSjohnjiang 	e->msg.type = MEMIF_MSG_TYPE_ADD_RING;
4564418919fSjohnjiang 	e->fd = mq->intr_handle.fd;
4574418919fSjohnjiang 	ar->index = idx;
4584418919fSjohnjiang 	ar->offset = mq->ring_offset;
4594418919fSjohnjiang 	ar->region = mq->region;
4604418919fSjohnjiang 	ar->log2_ring_size = mq->log2_ring_size;
4614418919fSjohnjiang 	ar->flags = (type == MEMIF_RING_S2M) ? MEMIF_MSG_ADD_RING_FLAG_S2M : 0;
4624418919fSjohnjiang 	ar->private_hdr_size = 0;
4634418919fSjohnjiang 
4644418919fSjohnjiang 	return 0;
4654418919fSjohnjiang }
4664418919fSjohnjiang 
4674418919fSjohnjiang static int
4684418919fSjohnjiang memif_msg_enq_connect(struct rte_eth_dev *dev)
4694418919fSjohnjiang {
4704418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
4714418919fSjohnjiang 	struct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);
4724418919fSjohnjiang 	memif_msg_connect_t *c;
4734418919fSjohnjiang 
4744418919fSjohnjiang 	if (e == NULL)
4754418919fSjohnjiang 		return -1;
4764418919fSjohnjiang 
4774418919fSjohnjiang 	c = &e->msg.connect;
4784418919fSjohnjiang 	e->msg.type = MEMIF_MSG_TYPE_CONNECT;
4794418919fSjohnjiang 	strlcpy((char *)c->if_name, dev->data->name, sizeof(c->if_name));
4804418919fSjohnjiang 
4814418919fSjohnjiang 	return 0;
4824418919fSjohnjiang }
4834418919fSjohnjiang 
4844418919fSjohnjiang static int
4854418919fSjohnjiang memif_msg_enq_connected(struct rte_eth_dev *dev)
4864418919fSjohnjiang {
4874418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
4884418919fSjohnjiang 	struct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);
4894418919fSjohnjiang 	memif_msg_connected_t *c;
4904418919fSjohnjiang 
4914418919fSjohnjiang 	if (e == NULL)
4924418919fSjohnjiang 		return -1;
4934418919fSjohnjiang 
4944418919fSjohnjiang 	c = &e->msg.connected;
4954418919fSjohnjiang 	e->msg.type = MEMIF_MSG_TYPE_CONNECTED;
4964418919fSjohnjiang 	strlcpy((char *)c->if_name, dev->data->name, sizeof(c->if_name));
4974418919fSjohnjiang 
4984418919fSjohnjiang 	return 0;
4994418919fSjohnjiang }
5004418919fSjohnjiang 
5014418919fSjohnjiang static void
5024418919fSjohnjiang memif_intr_unregister_handler(struct rte_intr_handle *intr_handle, void *arg)
5034418919fSjohnjiang {
5044418919fSjohnjiang 	struct memif_msg_queue_elt *elt;
5054418919fSjohnjiang 	struct memif_control_channel *cc = arg;
5064418919fSjohnjiang 
5074418919fSjohnjiang 	/* close control channel fd */
5084418919fSjohnjiang 	close(intr_handle->fd);
5094418919fSjohnjiang 	/* clear message queue */
5104418919fSjohnjiang 	while ((elt = TAILQ_FIRST(&cc->msg_queue)) != NULL) {
5114418919fSjohnjiang 		TAILQ_REMOVE(&cc->msg_queue, elt, next);
5124418919fSjohnjiang 		rte_free(elt);
5134418919fSjohnjiang 	}
5144418919fSjohnjiang 	/* free control channel */
5154418919fSjohnjiang 	rte_free(cc);
5164418919fSjohnjiang }
5174418919fSjohnjiang 
5184418919fSjohnjiang void
5194418919fSjohnjiang memif_disconnect(struct rte_eth_dev *dev)
5204418919fSjohnjiang {
5214418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
5224418919fSjohnjiang 	struct memif_msg_queue_elt *elt, *next;
5234418919fSjohnjiang 	struct memif_queue *mq;
5244418919fSjohnjiang 	struct rte_intr_handle *ih;
5254418919fSjohnjiang 	int i;
5264418919fSjohnjiang 	int ret;
5274418919fSjohnjiang 
5284418919fSjohnjiang 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
5294418919fSjohnjiang 	pmd->flags &= ~ETH_MEMIF_FLAG_CONNECTING;
5304418919fSjohnjiang 	pmd->flags &= ~ETH_MEMIF_FLAG_CONNECTED;
5314418919fSjohnjiang 
5324418919fSjohnjiang 	if (pmd->cc != NULL) {
5334418919fSjohnjiang 		/* Clear control message queue (except disconnect message if any). */
5344418919fSjohnjiang 		for (elt = TAILQ_FIRST(&pmd->cc->msg_queue); elt != NULL; elt = next) {
5354418919fSjohnjiang 			next = TAILQ_NEXT(elt, next);
5364418919fSjohnjiang 			if (elt->msg.type != MEMIF_MSG_TYPE_DISCONNECT) {
5374418919fSjohnjiang 				TAILQ_REMOVE(&pmd->cc->msg_queue, elt, next);
5384418919fSjohnjiang 				rte_free(elt);
5394418919fSjohnjiang 			}
5404418919fSjohnjiang 		}
5414418919fSjohnjiang 		/* send disconnect message (if there is any in queue) */
5424418919fSjohnjiang 		memif_msg_send_from_queue(pmd->cc);
5434418919fSjohnjiang 
5444418919fSjohnjiang 		/* at this point, there should be no more messages in queue */
5454418919fSjohnjiang 		if (TAILQ_FIRST(&pmd->cc->msg_queue) != NULL) {
5464418919fSjohnjiang 			MIF_LOG(WARNING,
5474418919fSjohnjiang 				"Unexpected message(s) in message queue.");
5484418919fSjohnjiang 		}
5494418919fSjohnjiang 
5504418919fSjohnjiang 		ih = &pmd->cc->intr_handle;
5514418919fSjohnjiang 		if (ih->fd > 0) {
5524418919fSjohnjiang 			ret = rte_intr_callback_unregister(ih,
5534418919fSjohnjiang 							memif_intr_handler,
5544418919fSjohnjiang 							pmd->cc);
5554418919fSjohnjiang 			/*
5564418919fSjohnjiang 			 * If callback is active (disconnecting based on
5574418919fSjohnjiang 			 * received control message).
5584418919fSjohnjiang 			 */
5594418919fSjohnjiang 			if (ret == -EAGAIN) {
5604418919fSjohnjiang 				ret = rte_intr_callback_unregister_pending(ih,
5614418919fSjohnjiang 							memif_intr_handler,
5624418919fSjohnjiang 							pmd->cc,
5634418919fSjohnjiang 							memif_intr_unregister_handler);
5644418919fSjohnjiang 			} else if (ret > 0) {
5654418919fSjohnjiang 				close(ih->fd);
5664418919fSjohnjiang 				rte_free(pmd->cc);
5674418919fSjohnjiang 			}
5684418919fSjohnjiang 			pmd->cc = NULL;
5694418919fSjohnjiang 			if (ret <= 0)
5704418919fSjohnjiang 				MIF_LOG(WARNING,
5714418919fSjohnjiang 					"Failed to unregister control channel callback.");
5724418919fSjohnjiang 		}
5734418919fSjohnjiang 	}
5744418919fSjohnjiang 
5754418919fSjohnjiang 	/* unconfig interrupts */
5764418919fSjohnjiang 	for (i = 0; i < pmd->cfg.num_s2m_rings; i++) {
5774418919fSjohnjiang 		if (pmd->role == MEMIF_ROLE_SLAVE) {
5784418919fSjohnjiang 			if (dev->data->tx_queues != NULL)
5794418919fSjohnjiang 				mq = dev->data->tx_queues[i];
5804418919fSjohnjiang 			else
5814418919fSjohnjiang 				continue;
5824418919fSjohnjiang 		} else {
5834418919fSjohnjiang 			if (dev->data->rx_queues != NULL)
5844418919fSjohnjiang 				mq = dev->data->rx_queues[i];
5854418919fSjohnjiang 			else
5864418919fSjohnjiang 				continue;
5874418919fSjohnjiang 		}
5884418919fSjohnjiang 		if (mq->intr_handle.fd > 0) {
5894418919fSjohnjiang 			close(mq->intr_handle.fd);
5904418919fSjohnjiang 			mq->intr_handle.fd = -1;
5914418919fSjohnjiang 		}
5924418919fSjohnjiang 	}
5934418919fSjohnjiang 	for (i = 0; i < pmd->cfg.num_m2s_rings; i++) {
5944418919fSjohnjiang 		if (pmd->role == MEMIF_ROLE_MASTER) {
5954418919fSjohnjiang 			if (dev->data->tx_queues != NULL)
5964418919fSjohnjiang 				mq = dev->data->tx_queues[i];
5974418919fSjohnjiang 			else
5984418919fSjohnjiang 				continue;
5994418919fSjohnjiang 		} else {
6004418919fSjohnjiang 			if (dev->data->rx_queues != NULL)
6014418919fSjohnjiang 				mq = dev->data->rx_queues[i];
6024418919fSjohnjiang 			else
6034418919fSjohnjiang 				continue;
6044418919fSjohnjiang 		}
6054418919fSjohnjiang 		if (mq->intr_handle.fd > 0) {
6064418919fSjohnjiang 			close(mq->intr_handle.fd);
6074418919fSjohnjiang 			mq->intr_handle.fd = -1;
6084418919fSjohnjiang 		}
6094418919fSjohnjiang 	}
6104418919fSjohnjiang 
6114418919fSjohnjiang 	memif_free_regions(dev);
6124418919fSjohnjiang 
6134418919fSjohnjiang 	/* reset connection configuration */
6144418919fSjohnjiang 	memset(&pmd->run, 0, sizeof(pmd->run));
6154418919fSjohnjiang 
6164418919fSjohnjiang 	MIF_LOG(DEBUG, "Disconnected.");
6174418919fSjohnjiang }
6184418919fSjohnjiang 
6194418919fSjohnjiang static int
6204418919fSjohnjiang memif_msg_receive(struct memif_control_channel *cc)
6214418919fSjohnjiang {
6224418919fSjohnjiang 	char ctl[CMSG_SPACE(sizeof(int)) +
6234418919fSjohnjiang 		 CMSG_SPACE(sizeof(struct ucred))] = { 0 };
6244418919fSjohnjiang 	struct msghdr mh = { 0 };
6254418919fSjohnjiang 	struct iovec iov[1];
6264418919fSjohnjiang 	memif_msg_t msg = { 0 };
6274418919fSjohnjiang 	ssize_t size;
6284418919fSjohnjiang 	int ret = 0;
6294418919fSjohnjiang 	struct ucred *cr __rte_unused;
6304418919fSjohnjiang 	cr = 0;
6314418919fSjohnjiang 	struct cmsghdr *cmsg;
6324418919fSjohnjiang 	int afd = -1;
6334418919fSjohnjiang 	int i;
6344418919fSjohnjiang 	struct pmd_internals *pmd;
6354418919fSjohnjiang 	struct pmd_process_private *proc_private;
6364418919fSjohnjiang 
6374418919fSjohnjiang 	iov[0].iov_base = (void *)&msg;
6384418919fSjohnjiang 	iov[0].iov_len = sizeof(memif_msg_t);
6394418919fSjohnjiang 	mh.msg_iov = iov;
6404418919fSjohnjiang 	mh.msg_iovlen = 1;
6414418919fSjohnjiang 	mh.msg_control = ctl;
6424418919fSjohnjiang 	mh.msg_controllen = sizeof(ctl);
6434418919fSjohnjiang 
6444418919fSjohnjiang 	size = recvmsg(cc->intr_handle.fd, &mh, 0);
6454418919fSjohnjiang 	if (size != sizeof(memif_msg_t)) {
6464418919fSjohnjiang 		MIF_LOG(DEBUG, "Invalid message size.");
6474418919fSjohnjiang 		memif_msg_enq_disconnect(cc, "Invalid message size", 0);
6484418919fSjohnjiang 		return -1;
6494418919fSjohnjiang 	}
6504418919fSjohnjiang 	MIF_LOG(DEBUG, "Received msg type: %u.", msg.type);
6514418919fSjohnjiang 
6524418919fSjohnjiang 	cmsg = CMSG_FIRSTHDR(&mh);
6534418919fSjohnjiang 	while (cmsg) {
6544418919fSjohnjiang 		if (cmsg->cmsg_level == SOL_SOCKET) {
6554418919fSjohnjiang 			if (cmsg->cmsg_type == SCM_CREDENTIALS)
6564418919fSjohnjiang 				cr = (struct ucred *)CMSG_DATA(cmsg);
6574418919fSjohnjiang 			else if (cmsg->cmsg_type == SCM_RIGHTS)
6584418919fSjohnjiang 				rte_memcpy(&afd, CMSG_DATA(cmsg), sizeof(int));
6594418919fSjohnjiang 		}
6604418919fSjohnjiang 		cmsg = CMSG_NXTHDR(&mh, cmsg);
6614418919fSjohnjiang 	}
6624418919fSjohnjiang 
6634418919fSjohnjiang 	if (cc->dev == NULL && msg.type != MEMIF_MSG_TYPE_INIT) {
6644418919fSjohnjiang 		MIF_LOG(DEBUG, "Unexpected message.");
6654418919fSjohnjiang 		memif_msg_enq_disconnect(cc, "Unexpected message", 0);
6664418919fSjohnjiang 		return -1;
6674418919fSjohnjiang 	}
6684418919fSjohnjiang 
6694418919fSjohnjiang 	/* get device from hash data */
6704418919fSjohnjiang 	switch (msg.type) {
6714418919fSjohnjiang 	case MEMIF_MSG_TYPE_ACK:
6724418919fSjohnjiang 		break;
6734418919fSjohnjiang 	case MEMIF_MSG_TYPE_HELLO:
6744418919fSjohnjiang 		ret = memif_msg_receive_hello(cc->dev, &msg);
6754418919fSjohnjiang 		if (ret < 0)
6764418919fSjohnjiang 			goto exit;
6774418919fSjohnjiang 		ret = memif_init_regions_and_queues(cc->dev);
6784418919fSjohnjiang 		if (ret < 0)
6794418919fSjohnjiang 			goto exit;
6804418919fSjohnjiang 		ret = memif_msg_enq_init(cc->dev);
6814418919fSjohnjiang 		if (ret < 0)
6824418919fSjohnjiang 			goto exit;
6834418919fSjohnjiang 		pmd = cc->dev->data->dev_private;
6844418919fSjohnjiang 		proc_private = cc->dev->process_private;
6854418919fSjohnjiang 		for (i = 0; i < proc_private->regions_num; i++) {
6864418919fSjohnjiang 			ret = memif_msg_enq_add_region(cc->dev, i);
6874418919fSjohnjiang 			if (ret < 0)
6884418919fSjohnjiang 				goto exit;
6894418919fSjohnjiang 		}
6904418919fSjohnjiang 		for (i = 0; i < pmd->run.num_s2m_rings; i++) {
6914418919fSjohnjiang 			ret = memif_msg_enq_add_ring(cc->dev, i,
6924418919fSjohnjiang 						     MEMIF_RING_S2M);
6934418919fSjohnjiang 			if (ret < 0)
6944418919fSjohnjiang 				goto exit;
6954418919fSjohnjiang 		}
6964418919fSjohnjiang 		for (i = 0; i < pmd->run.num_m2s_rings; i++) {
6974418919fSjohnjiang 			ret = memif_msg_enq_add_ring(cc->dev, i,
6984418919fSjohnjiang 						     MEMIF_RING_M2S);
6994418919fSjohnjiang 			if (ret < 0)
7004418919fSjohnjiang 				goto exit;
7014418919fSjohnjiang 		}
7024418919fSjohnjiang 		ret = memif_msg_enq_connect(cc->dev);
7034418919fSjohnjiang 		if (ret < 0)
7044418919fSjohnjiang 			goto exit;
7054418919fSjohnjiang 		break;
7064418919fSjohnjiang 	case MEMIF_MSG_TYPE_INIT:
7074418919fSjohnjiang 		/*
7084418919fSjohnjiang 		 * This cc does not have an interface asociated with it.
7094418919fSjohnjiang 		 * If suitable interface is found it will be assigned here.
7104418919fSjohnjiang 		 */
7114418919fSjohnjiang 		ret = memif_msg_receive_init(cc, &msg);
7124418919fSjohnjiang 		if (ret < 0)
7134418919fSjohnjiang 			goto exit;
7144418919fSjohnjiang 		ret = memif_msg_enq_ack(cc->dev);
7154418919fSjohnjiang 		if (ret < 0)
7164418919fSjohnjiang 			goto exit;
7174418919fSjohnjiang 		break;
7184418919fSjohnjiang 	case MEMIF_MSG_TYPE_ADD_REGION:
7194418919fSjohnjiang 		ret = memif_msg_receive_add_region(cc->dev, &msg, afd);
7204418919fSjohnjiang 		if (ret < 0)
7214418919fSjohnjiang 			goto exit;
7224418919fSjohnjiang 		ret = memif_msg_enq_ack(cc->dev);
7234418919fSjohnjiang 		if (ret < 0)
7244418919fSjohnjiang 			goto exit;
7254418919fSjohnjiang 		break;
7264418919fSjohnjiang 	case MEMIF_MSG_TYPE_ADD_RING:
7274418919fSjohnjiang 		ret = memif_msg_receive_add_ring(cc->dev, &msg, afd);
7284418919fSjohnjiang 		if (ret < 0)
7294418919fSjohnjiang 			goto exit;
7304418919fSjohnjiang 		ret = memif_msg_enq_ack(cc->dev);
7314418919fSjohnjiang 		if (ret < 0)
7324418919fSjohnjiang 			goto exit;
7334418919fSjohnjiang 		break;
7344418919fSjohnjiang 	case MEMIF_MSG_TYPE_CONNECT:
7354418919fSjohnjiang 		ret = memif_msg_receive_connect(cc->dev, &msg);
7364418919fSjohnjiang 		if (ret < 0)
7374418919fSjohnjiang 			goto exit;
7384418919fSjohnjiang 		ret = memif_msg_enq_connected(cc->dev);
7394418919fSjohnjiang 		if (ret < 0)
7404418919fSjohnjiang 			goto exit;
7414418919fSjohnjiang 		break;
7424418919fSjohnjiang 	case MEMIF_MSG_TYPE_CONNECTED:
7434418919fSjohnjiang 		ret = memif_msg_receive_connected(cc->dev, &msg);
7444418919fSjohnjiang 		break;
7454418919fSjohnjiang 	case MEMIF_MSG_TYPE_DISCONNECT:
7464418919fSjohnjiang 		ret = memif_msg_receive_disconnect(cc->dev, &msg);
7474418919fSjohnjiang 		if (ret < 0)
7484418919fSjohnjiang 			goto exit;
7494418919fSjohnjiang 		break;
7504418919fSjohnjiang 	default:
7514418919fSjohnjiang 		memif_msg_enq_disconnect(cc, "Unknown message type", 0);
7524418919fSjohnjiang 		ret = -1;
7534418919fSjohnjiang 		goto exit;
7544418919fSjohnjiang 	}
7554418919fSjohnjiang 
7564418919fSjohnjiang  exit:
7574418919fSjohnjiang 	return ret;
7584418919fSjohnjiang }
7594418919fSjohnjiang 
7604418919fSjohnjiang static void
7614418919fSjohnjiang memif_intr_handler(void *arg)
7624418919fSjohnjiang {
7634418919fSjohnjiang 	struct memif_control_channel *cc = arg;
7644418919fSjohnjiang 	int ret;
7654418919fSjohnjiang 
7664418919fSjohnjiang 	ret = memif_msg_receive(cc);
7674418919fSjohnjiang 	/* if driver failed to assign device */
7684418919fSjohnjiang 	if (cc->dev == NULL) {
769*0c6bd470Sfengbojiang 		memif_msg_send_from_queue(cc);
7704418919fSjohnjiang 		ret = rte_intr_callback_unregister_pending(&cc->intr_handle,
7714418919fSjohnjiang 							   memif_intr_handler,
7724418919fSjohnjiang 							   cc,
7734418919fSjohnjiang 							   memif_intr_unregister_handler);
7744418919fSjohnjiang 		if (ret < 0)
7754418919fSjohnjiang 			MIF_LOG(WARNING,
7764418919fSjohnjiang 				"Failed to unregister control channel callback.");
7774418919fSjohnjiang 		return;
7784418919fSjohnjiang 	}
7794418919fSjohnjiang 	/* if memif_msg_receive failed */
7804418919fSjohnjiang 	if (ret < 0)
7814418919fSjohnjiang 		goto disconnect;
7824418919fSjohnjiang 
7834418919fSjohnjiang 	ret = memif_msg_send_from_queue(cc);
7844418919fSjohnjiang 	if (ret < 0)
7854418919fSjohnjiang 		goto disconnect;
7864418919fSjohnjiang 
7874418919fSjohnjiang 	return;
7884418919fSjohnjiang 
7894418919fSjohnjiang  disconnect:
7904418919fSjohnjiang 	if (cc->dev == NULL) {
7914418919fSjohnjiang 		MIF_LOG(WARNING, "eth dev not allocated");
7924418919fSjohnjiang 		return;
7934418919fSjohnjiang 	}
7944418919fSjohnjiang 	memif_disconnect(cc->dev);
7954418919fSjohnjiang }
7964418919fSjohnjiang 
7974418919fSjohnjiang static void
7984418919fSjohnjiang memif_listener_handler(void *arg)
7994418919fSjohnjiang {
8004418919fSjohnjiang 	struct memif_socket *socket = arg;
8014418919fSjohnjiang 	int sockfd;
8024418919fSjohnjiang 	int addr_len;
8034418919fSjohnjiang 	struct sockaddr_un client;
8044418919fSjohnjiang 	struct memif_control_channel *cc;
8054418919fSjohnjiang 	int ret;
8064418919fSjohnjiang 
8074418919fSjohnjiang 	addr_len = sizeof(client);
8084418919fSjohnjiang 	sockfd = accept(socket->intr_handle.fd, (struct sockaddr *)&client,
8094418919fSjohnjiang 			(socklen_t *)&addr_len);
8104418919fSjohnjiang 	if (sockfd < 0) {
8114418919fSjohnjiang 		MIF_LOG(ERR,
8124418919fSjohnjiang 			"Failed to accept connection request on socket fd %d",
8134418919fSjohnjiang 			socket->intr_handle.fd);
8144418919fSjohnjiang 		return;
8154418919fSjohnjiang 	}
8164418919fSjohnjiang 
8174418919fSjohnjiang 	MIF_LOG(DEBUG, "%s: Connection request accepted.", socket->filename);
8184418919fSjohnjiang 
8194418919fSjohnjiang 	cc = rte_zmalloc("memif-cc", sizeof(struct memif_control_channel), 0);
8204418919fSjohnjiang 	if (cc == NULL) {
8214418919fSjohnjiang 		MIF_LOG(ERR, "Failed to allocate control channel.");
8224418919fSjohnjiang 		goto error;
8234418919fSjohnjiang 	}
8244418919fSjohnjiang 
8254418919fSjohnjiang 	cc->intr_handle.fd = sockfd;
8264418919fSjohnjiang 	cc->intr_handle.type = RTE_INTR_HANDLE_EXT;
8274418919fSjohnjiang 	cc->socket = socket;
8284418919fSjohnjiang 	cc->dev = NULL;
8294418919fSjohnjiang 	TAILQ_INIT(&cc->msg_queue);
8304418919fSjohnjiang 
8314418919fSjohnjiang 	ret = rte_intr_callback_register(&cc->intr_handle, memif_intr_handler, cc);
8324418919fSjohnjiang 	if (ret < 0) {
8334418919fSjohnjiang 		MIF_LOG(ERR, "Failed to register control channel callback.");
8344418919fSjohnjiang 		goto error;
8354418919fSjohnjiang 	}
8364418919fSjohnjiang 
8374418919fSjohnjiang 	ret = memif_msg_enq_hello(cc);
8384418919fSjohnjiang 	if (ret < 0) {
8394418919fSjohnjiang 		MIF_LOG(ERR, "Failed to enqueue hello message.");
8404418919fSjohnjiang 		goto error;
8414418919fSjohnjiang 	}
8424418919fSjohnjiang 	ret = memif_msg_send_from_queue(cc);
8434418919fSjohnjiang 	if (ret < 0)
8444418919fSjohnjiang 		goto error;
8454418919fSjohnjiang 
8464418919fSjohnjiang 	return;
8474418919fSjohnjiang 
8484418919fSjohnjiang  error:
8494418919fSjohnjiang 	if (sockfd >= 0) {
8504418919fSjohnjiang 		close(sockfd);
8514418919fSjohnjiang 		sockfd = -1;
8524418919fSjohnjiang 	}
8534418919fSjohnjiang 	if (cc != NULL)
8544418919fSjohnjiang 		rte_free(cc);
8554418919fSjohnjiang }
8564418919fSjohnjiang 
8574418919fSjohnjiang static struct memif_socket *
8584418919fSjohnjiang memif_socket_create(char *key, uint8_t listener)
8594418919fSjohnjiang {
8604418919fSjohnjiang 	struct memif_socket *sock;
8614418919fSjohnjiang 	struct sockaddr_un un;
8624418919fSjohnjiang 	int sockfd;
8634418919fSjohnjiang 	int ret;
8644418919fSjohnjiang 	int on = 1;
8654418919fSjohnjiang 
8664418919fSjohnjiang 	sock = rte_zmalloc("memif-socket", sizeof(struct memif_socket), 0);
8674418919fSjohnjiang 	if (sock == NULL) {
8684418919fSjohnjiang 		MIF_LOG(ERR, "Failed to allocate memory for memif socket");
8694418919fSjohnjiang 		return NULL;
8704418919fSjohnjiang 	}
8714418919fSjohnjiang 
8724418919fSjohnjiang 	sock->listener = listener;
8734418919fSjohnjiang 	strlcpy(sock->filename, key, MEMIF_SOCKET_UN_SIZE);
8744418919fSjohnjiang 	TAILQ_INIT(&sock->dev_queue);
8754418919fSjohnjiang 
8764418919fSjohnjiang 	if (listener != 0) {
8774418919fSjohnjiang 		sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
8784418919fSjohnjiang 		if (sockfd < 0)
8794418919fSjohnjiang 			goto error;
8804418919fSjohnjiang 
8814418919fSjohnjiang 		un.sun_family = AF_UNIX;
8824418919fSjohnjiang 		strlcpy(un.sun_path, sock->filename, MEMIF_SOCKET_UN_SIZE);
8834418919fSjohnjiang 
8844418919fSjohnjiang 		ret = setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &on,
8854418919fSjohnjiang 				 sizeof(on));
8864418919fSjohnjiang 		if (ret < 0)
8874418919fSjohnjiang 			goto error;
8884418919fSjohnjiang 
8894418919fSjohnjiang 		ret = bind(sockfd, (struct sockaddr *)&un, sizeof(un));
8904418919fSjohnjiang 		if (ret < 0)
8914418919fSjohnjiang 			goto error;
8924418919fSjohnjiang 
8934418919fSjohnjiang 		ret = listen(sockfd, 1);
8944418919fSjohnjiang 		if (ret < 0)
8954418919fSjohnjiang 			goto error;
8964418919fSjohnjiang 
8974418919fSjohnjiang 		MIF_LOG(DEBUG, "Memif listener socket %s created.", sock->filename);
8984418919fSjohnjiang 
8994418919fSjohnjiang 		sock->intr_handle.fd = sockfd;
9004418919fSjohnjiang 		sock->intr_handle.type = RTE_INTR_HANDLE_EXT;
9014418919fSjohnjiang 		ret = rte_intr_callback_register(&sock->intr_handle,
9024418919fSjohnjiang 						 memif_listener_handler, sock);
9034418919fSjohnjiang 		if (ret < 0) {
9044418919fSjohnjiang 			MIF_LOG(ERR, "Failed to register interrupt "
9054418919fSjohnjiang 				"callback for listener socket");
9064418919fSjohnjiang 			return NULL;
9074418919fSjohnjiang 		}
9084418919fSjohnjiang 	}
9094418919fSjohnjiang 
9104418919fSjohnjiang 	return sock;
9114418919fSjohnjiang 
9124418919fSjohnjiang  error:
9134418919fSjohnjiang 	MIF_LOG(ERR, "Failed to setup socket %s: %s", key, strerror(errno));
9144418919fSjohnjiang 	if (sock != NULL)
9154418919fSjohnjiang 		rte_free(sock);
9164418919fSjohnjiang 	if (sockfd >= 0)
9174418919fSjohnjiang 		close(sockfd);
9184418919fSjohnjiang 	return NULL;
9194418919fSjohnjiang }
9204418919fSjohnjiang 
9214418919fSjohnjiang static struct rte_hash *
9224418919fSjohnjiang memif_create_socket_hash(void)
9234418919fSjohnjiang {
9244418919fSjohnjiang 	struct rte_hash_parameters params = { 0 };
9254418919fSjohnjiang 
9264418919fSjohnjiang 	params.name = MEMIF_SOCKET_HASH_NAME;
9274418919fSjohnjiang 	params.entries = 256;
9284418919fSjohnjiang 	params.key_len = MEMIF_SOCKET_UN_SIZE;
9294418919fSjohnjiang 	params.hash_func = rte_jhash;
9304418919fSjohnjiang 	params.hash_func_init_val = 0;
9314418919fSjohnjiang 	return rte_hash_create(&params);
9324418919fSjohnjiang }
9334418919fSjohnjiang 
9344418919fSjohnjiang int
9354418919fSjohnjiang memif_socket_init(struct rte_eth_dev *dev, const char *socket_filename)
9364418919fSjohnjiang {
9374418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
9384418919fSjohnjiang 	struct memif_socket *socket = NULL;
9394418919fSjohnjiang 	struct memif_socket_dev_list_elt *elt;
9404418919fSjohnjiang 	struct pmd_internals *tmp_pmd;
9414418919fSjohnjiang 	struct rte_hash *hash;
9424418919fSjohnjiang 	int ret;
9434418919fSjohnjiang 	char key[MEMIF_SOCKET_UN_SIZE];
9444418919fSjohnjiang 
9454418919fSjohnjiang 	hash = rte_hash_find_existing(MEMIF_SOCKET_HASH_NAME);
9464418919fSjohnjiang 	if (hash == NULL) {
9474418919fSjohnjiang 		hash = memif_create_socket_hash();
9484418919fSjohnjiang 		if (hash == NULL) {
9494418919fSjohnjiang 			MIF_LOG(ERR, "Failed to create memif socket hash.");
9504418919fSjohnjiang 			return -1;
9514418919fSjohnjiang 		}
9524418919fSjohnjiang 	}
9534418919fSjohnjiang 
9544418919fSjohnjiang 	memset(key, 0, MEMIF_SOCKET_UN_SIZE);
9554418919fSjohnjiang 	strlcpy(key, socket_filename, MEMIF_SOCKET_UN_SIZE);
9564418919fSjohnjiang 	ret = rte_hash_lookup_data(hash, key, (void **)&socket);
9574418919fSjohnjiang 	if (ret < 0) {
9584418919fSjohnjiang 		socket = memif_socket_create(key,
9594418919fSjohnjiang 					     (pmd->role == MEMIF_ROLE_SLAVE) ? 0 : 1);
9604418919fSjohnjiang 		if (socket == NULL)
9614418919fSjohnjiang 			return -1;
9624418919fSjohnjiang 		ret = rte_hash_add_key_data(hash, key, socket);
9634418919fSjohnjiang 		if (ret < 0) {
9644418919fSjohnjiang 			MIF_LOG(ERR, "Failed to add socket to socket hash.");
9654418919fSjohnjiang 			return ret;
9664418919fSjohnjiang 		}
9674418919fSjohnjiang 	}
9684418919fSjohnjiang 	pmd->socket_filename = socket->filename;
9694418919fSjohnjiang 
9704418919fSjohnjiang 	if (socket->listener != 0 && pmd->role == MEMIF_ROLE_SLAVE) {
9714418919fSjohnjiang 		MIF_LOG(ERR, "Socket is a listener.");
9724418919fSjohnjiang 		return -1;
9734418919fSjohnjiang 	} else if ((socket->listener == 0) && (pmd->role == MEMIF_ROLE_MASTER)) {
9744418919fSjohnjiang 		MIF_LOG(ERR, "Socket is not a listener.");
9754418919fSjohnjiang 		return -1;
9764418919fSjohnjiang 	}
9774418919fSjohnjiang 
9784418919fSjohnjiang 	TAILQ_FOREACH(elt, &socket->dev_queue, next) {
9794418919fSjohnjiang 		tmp_pmd = elt->dev->data->dev_private;
9804418919fSjohnjiang 		if (tmp_pmd->id == pmd->id) {
9814418919fSjohnjiang 			MIF_LOG(ERR, "Memif device with id %d already "
9824418919fSjohnjiang 				"exists on socket %s",
9834418919fSjohnjiang 				pmd->id, socket->filename);
9844418919fSjohnjiang 			return -1;
9854418919fSjohnjiang 		}
9864418919fSjohnjiang 	}
9874418919fSjohnjiang 
9884418919fSjohnjiang 	elt = rte_malloc("pmd-queue", sizeof(struct memif_socket_dev_list_elt), 0);
9894418919fSjohnjiang 	if (elt == NULL) {
9904418919fSjohnjiang 		MIF_LOG(ERR, "Failed to add device to socket device list.");
9914418919fSjohnjiang 		return -1;
9924418919fSjohnjiang 	}
9934418919fSjohnjiang 	elt->dev = dev;
9944418919fSjohnjiang 	TAILQ_INSERT_TAIL(&socket->dev_queue, elt, next);
9954418919fSjohnjiang 
9964418919fSjohnjiang 	return 0;
9974418919fSjohnjiang }
9984418919fSjohnjiang 
9994418919fSjohnjiang void
10004418919fSjohnjiang memif_socket_remove_device(struct rte_eth_dev *dev)
10014418919fSjohnjiang {
10024418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
10034418919fSjohnjiang 	struct memif_socket *socket = NULL;
10044418919fSjohnjiang 	struct memif_socket_dev_list_elt *elt, *next;
10054418919fSjohnjiang 	struct rte_hash *hash;
10064418919fSjohnjiang 	int ret;
10074418919fSjohnjiang 
10084418919fSjohnjiang 	hash = rte_hash_find_existing(MEMIF_SOCKET_HASH_NAME);
10094418919fSjohnjiang 	if (hash == NULL)
10104418919fSjohnjiang 		return;
10114418919fSjohnjiang 
10124418919fSjohnjiang 	if (pmd->socket_filename == NULL)
10134418919fSjohnjiang 		return;
10144418919fSjohnjiang 
10154418919fSjohnjiang 	if (rte_hash_lookup_data(hash, pmd->socket_filename, (void **)&socket) < 0)
10164418919fSjohnjiang 		return;
10174418919fSjohnjiang 
10184418919fSjohnjiang 	for (elt = TAILQ_FIRST(&socket->dev_queue); elt != NULL; elt = next) {
10194418919fSjohnjiang 		next = TAILQ_NEXT(elt, next);
10204418919fSjohnjiang 		if (elt->dev == dev) {
10214418919fSjohnjiang 			TAILQ_REMOVE(&socket->dev_queue, elt, next);
10224418919fSjohnjiang 			rte_free(elt);
10234418919fSjohnjiang 			pmd->socket_filename = NULL;
10244418919fSjohnjiang 		}
10254418919fSjohnjiang 	}
10264418919fSjohnjiang 
10274418919fSjohnjiang 	/* remove socket, if this was the last device using it */
10284418919fSjohnjiang 	if (TAILQ_EMPTY(&socket->dev_queue)) {
10294418919fSjohnjiang 		rte_hash_del_key(hash, socket->filename);
10304418919fSjohnjiang 		if (socket->listener) {
10314418919fSjohnjiang 			/* remove listener socket file,
10324418919fSjohnjiang 			 * so we can create new one later.
10334418919fSjohnjiang 			 */
10344418919fSjohnjiang 			ret = remove(socket->filename);
10354418919fSjohnjiang 			if (ret < 0)
10364418919fSjohnjiang 				MIF_LOG(ERR, "Failed to remove socket file: %s",
10374418919fSjohnjiang 					socket->filename);
10384418919fSjohnjiang 		}
10394418919fSjohnjiang 		rte_free(socket);
10404418919fSjohnjiang 	}
10414418919fSjohnjiang }
10424418919fSjohnjiang 
10434418919fSjohnjiang int
10444418919fSjohnjiang memif_connect_master(struct rte_eth_dev *dev)
10454418919fSjohnjiang {
10464418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
10474418919fSjohnjiang 
10484418919fSjohnjiang 	memset(pmd->local_disc_string, 0, ETH_MEMIF_DISC_STRING_SIZE);
10494418919fSjohnjiang 	memset(pmd->remote_disc_string, 0, ETH_MEMIF_DISC_STRING_SIZE);
10504418919fSjohnjiang 	pmd->flags &= ~ETH_MEMIF_FLAG_DISABLED;
10514418919fSjohnjiang 	return 0;
10524418919fSjohnjiang }
10534418919fSjohnjiang 
10544418919fSjohnjiang int
10554418919fSjohnjiang memif_connect_slave(struct rte_eth_dev *dev)
10564418919fSjohnjiang {
10574418919fSjohnjiang 	int sockfd;
10584418919fSjohnjiang 	int ret;
10594418919fSjohnjiang 	struct sockaddr_un sun;
10604418919fSjohnjiang 	struct pmd_internals *pmd = dev->data->dev_private;
10614418919fSjohnjiang 
10624418919fSjohnjiang 	memset(pmd->local_disc_string, 0, ETH_MEMIF_DISC_STRING_SIZE);
10634418919fSjohnjiang 	memset(pmd->remote_disc_string, 0, ETH_MEMIF_DISC_STRING_SIZE);
10644418919fSjohnjiang 	pmd->flags &= ~ETH_MEMIF_FLAG_DISABLED;
10654418919fSjohnjiang 
10664418919fSjohnjiang 	sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
10674418919fSjohnjiang 	if (sockfd < 0) {
10684418919fSjohnjiang 		MIF_LOG(ERR, "Failed to open socket.");
10694418919fSjohnjiang 		return -1;
10704418919fSjohnjiang 	}
10714418919fSjohnjiang 
10724418919fSjohnjiang 	sun.sun_family = AF_UNIX;
10734418919fSjohnjiang 
10744418919fSjohnjiang 	memcpy(sun.sun_path, pmd->socket_filename, sizeof(sun.sun_path) - 1);
10754418919fSjohnjiang 
10764418919fSjohnjiang 	ret = connect(sockfd, (struct sockaddr *)&sun,
10774418919fSjohnjiang 		      sizeof(struct sockaddr_un));
10784418919fSjohnjiang 	if (ret < 0) {
10794418919fSjohnjiang 		MIF_LOG(ERR, "Failed to connect socket: %s.", pmd->socket_filename);
10804418919fSjohnjiang 		goto error;
10814418919fSjohnjiang 	}
10824418919fSjohnjiang 
10834418919fSjohnjiang 	MIF_LOG(DEBUG, "Memif socket: %s connected.", pmd->socket_filename);
10844418919fSjohnjiang 
10854418919fSjohnjiang 	pmd->cc = rte_zmalloc("memif-cc",
10864418919fSjohnjiang 			      sizeof(struct memif_control_channel), 0);
10874418919fSjohnjiang 	if (pmd->cc == NULL) {
10884418919fSjohnjiang 		MIF_LOG(ERR, "Failed to allocate control channel.");
10894418919fSjohnjiang 		goto error;
10904418919fSjohnjiang 	}
10914418919fSjohnjiang 
10924418919fSjohnjiang 	pmd->cc->intr_handle.fd = sockfd;
10934418919fSjohnjiang 	pmd->cc->intr_handle.type = RTE_INTR_HANDLE_EXT;
10944418919fSjohnjiang 	pmd->cc->socket = NULL;
10954418919fSjohnjiang 	pmd->cc->dev = dev;
10964418919fSjohnjiang 	TAILQ_INIT(&pmd->cc->msg_queue);
10974418919fSjohnjiang 
10984418919fSjohnjiang 	ret = rte_intr_callback_register(&pmd->cc->intr_handle,
10994418919fSjohnjiang 					 memif_intr_handler, pmd->cc);
11004418919fSjohnjiang 	if (ret < 0) {
11014418919fSjohnjiang 		MIF_LOG(ERR, "Failed to register interrupt callback for control fd");
11024418919fSjohnjiang 		goto error;
11034418919fSjohnjiang 	}
11044418919fSjohnjiang 
11054418919fSjohnjiang 	return 0;
11064418919fSjohnjiang 
11074418919fSjohnjiang  error:
11084418919fSjohnjiang 	if (sockfd >= 0) {
11094418919fSjohnjiang 		close(sockfd);
11104418919fSjohnjiang 		sockfd = -1;
11114418919fSjohnjiang 	}
11124418919fSjohnjiang 	if (pmd->cc != NULL) {
11134418919fSjohnjiang 		rte_free(pmd->cc);
11144418919fSjohnjiang 		pmd->cc = NULL;
11154418919fSjohnjiang 	}
11164418919fSjohnjiang 	return -1;
11174418919fSjohnjiang }
1118