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
memif_msg_send(int fd,memif_msg_t * msg,int afd)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
memif_msg_send_from_queue(struct memif_control_channel * cc)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 *
memif_msg_enq(struct memif_control_channel * cc)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
memif_msg_enq_disconnect(struct memif_control_channel * cc,const char * reason,int err_code)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
memif_msg_enq_hello(struct memif_control_channel * cc)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;
146*2d9fd380Sjfb8856606 h->max_c2s_ring = ETH_MEMIF_MAX_NUM_Q_PAIRS;
147*2d9fd380Sjfb8856606 h->max_s2c_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
memif_msg_receive_hello(struct rte_eth_dev * dev,memif_msg_t * msg)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 */
168*2d9fd380Sjfb8856606 pmd->run.num_c2s_rings = RTE_MIN(h->max_c2s_ring + 1,
169*2d9fd380Sjfb8856606 pmd->cfg.num_c2s_rings);
170*2d9fd380Sjfb8856606 pmd->run.num_s2c_rings = RTE_MIN(h->max_s2c_ring + 1,
171*2d9fd380Sjfb8856606 pmd->cfg.num_s2c_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
memif_msg_receive_init(struct memif_control_channel * cc,memif_msg_t * msg)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) &&
206*2d9fd380Sjfb8856606 (pmd->id == i->id) && (pmd->role == MEMIF_ROLE_SERVER)) {
2070c6bd470Sfengbojiang if (pmd->flags & (ETH_MEMIF_FLAG_CONNECTING |
2080c6bd470Sfengbojiang ETH_MEMIF_FLAG_CONNECTED)) {
2090c6bd470Sfengbojiang memif_msg_enq_disconnect(cc,
2100c6bd470Sfengbojiang "Already connected", 0);
2110c6bd470Sfengbojiang return -1;
2120c6bd470Sfengbojiang }
2130c6bd470Sfengbojiang
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
memif_msg_receive_add_region(struct rte_eth_dev * dev,memif_msg_t * msg,int fd)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
memif_msg_receive_add_ring(struct rte_eth_dev * dev,memif_msg_t * msg,int fd)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 */
303*2d9fd380Sjfb8856606 if (ar->flags & MEMIF_MSG_ADD_RING_FLAG_C2S) {
304*2d9fd380Sjfb8856606 if (ar->index >= pmd->cfg.num_c2s_rings) {
3054418919fSjohnjiang memif_msg_enq_disconnect(pmd->cc, "Invalid ring index", 0);
3064418919fSjohnjiang return -1;
3074418919fSjohnjiang }
308*2d9fd380Sjfb8856606 pmd->run.num_c2s_rings++;
3094418919fSjohnjiang } else {
310*2d9fd380Sjfb8856606 if (ar->index >= pmd->cfg.num_s2c_rings) {
3114418919fSjohnjiang memif_msg_enq_disconnect(pmd->cc, "Invalid ring index", 0);
3124418919fSjohnjiang return -1;
3134418919fSjohnjiang }
314*2d9fd380Sjfb8856606 pmd->run.num_s2c_rings++;
3154418919fSjohnjiang }
3164418919fSjohnjiang
317*2d9fd380Sjfb8856606 mq = (ar->flags & MEMIF_MSG_ADD_RING_FLAG_C2S) ?
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
memif_msg_receive_connect(struct rte_eth_dev * dev,memif_msg_t * msg)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
memif_msg_receive_connected(struct rte_eth_dev * dev,memif_msg_t * msg)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
memif_msg_receive_disconnect(struct rte_eth_dev * dev,memif_msg_t * msg)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
memif_msg_enq_ack(struct rte_eth_dev * dev)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
memif_msg_enq_init(struct rte_eth_dev * dev)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
memif_msg_enq_add_region(struct rte_eth_dev * dev,uint8_t idx)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
memif_msg_enq_add_ring(struct rte_eth_dev * dev,uint8_t idx,memif_ring_type_t type)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;
452*2d9fd380Sjfb8856606 mq = (type == MEMIF_RING_C2S) ? 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;
461*2d9fd380Sjfb8856606 ar->flags = (type == MEMIF_RING_C2S) ? MEMIF_MSG_ADD_RING_FLAG_C2S : 0;
4624418919fSjohnjiang ar->private_hdr_size = 0;
4634418919fSjohnjiang
4644418919fSjohnjiang return 0;
4654418919fSjohnjiang }
4664418919fSjohnjiang
4674418919fSjohnjiang static int
memif_msg_enq_connect(struct rte_eth_dev * dev)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
memif_msg_enq_connected(struct rte_eth_dev * dev)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
memif_intr_unregister_handler(struct rte_intr_handle * intr_handle,void * arg)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
memif_disconnect(struct rte_eth_dev * dev)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
532*2d9fd380Sjfb8856606 rte_spinlock_lock(&pmd->cc_lock);
5334418919fSjohnjiang if (pmd->cc != NULL) {
5344418919fSjohnjiang /* Clear control message queue (except disconnect message if any). */
5354418919fSjohnjiang for (elt = TAILQ_FIRST(&pmd->cc->msg_queue); elt != NULL; elt = next) {
5364418919fSjohnjiang next = TAILQ_NEXT(elt, next);
5374418919fSjohnjiang if (elt->msg.type != MEMIF_MSG_TYPE_DISCONNECT) {
5384418919fSjohnjiang TAILQ_REMOVE(&pmd->cc->msg_queue, elt, next);
5394418919fSjohnjiang rte_free(elt);
5404418919fSjohnjiang }
5414418919fSjohnjiang }
5424418919fSjohnjiang /* send disconnect message (if there is any in queue) */
5434418919fSjohnjiang memif_msg_send_from_queue(pmd->cc);
5444418919fSjohnjiang
5454418919fSjohnjiang /* at this point, there should be no more messages in queue */
5464418919fSjohnjiang if (TAILQ_FIRST(&pmd->cc->msg_queue) != NULL) {
5474418919fSjohnjiang MIF_LOG(WARNING,
5484418919fSjohnjiang "Unexpected message(s) in message queue.");
5494418919fSjohnjiang }
5504418919fSjohnjiang
5514418919fSjohnjiang ih = &pmd->cc->intr_handle;
5524418919fSjohnjiang if (ih->fd > 0) {
5534418919fSjohnjiang ret = rte_intr_callback_unregister(ih,
5544418919fSjohnjiang memif_intr_handler,
5554418919fSjohnjiang pmd->cc);
5564418919fSjohnjiang /*
5574418919fSjohnjiang * If callback is active (disconnecting based on
5584418919fSjohnjiang * received control message).
5594418919fSjohnjiang */
5604418919fSjohnjiang if (ret == -EAGAIN) {
5614418919fSjohnjiang ret = rte_intr_callback_unregister_pending(ih,
5624418919fSjohnjiang memif_intr_handler,
5634418919fSjohnjiang pmd->cc,
5644418919fSjohnjiang memif_intr_unregister_handler);
5654418919fSjohnjiang } else if (ret > 0) {
5664418919fSjohnjiang close(ih->fd);
5674418919fSjohnjiang rte_free(pmd->cc);
5684418919fSjohnjiang }
5694418919fSjohnjiang pmd->cc = NULL;
5704418919fSjohnjiang if (ret <= 0)
5714418919fSjohnjiang MIF_LOG(WARNING,
5724418919fSjohnjiang "Failed to unregister control channel callback.");
5734418919fSjohnjiang }
5744418919fSjohnjiang }
575*2d9fd380Sjfb8856606 rte_spinlock_unlock(&pmd->cc_lock);
5764418919fSjohnjiang
5774418919fSjohnjiang /* unconfig interrupts */
578*2d9fd380Sjfb8856606 for (i = 0; i < pmd->cfg.num_c2s_rings; i++) {
579*2d9fd380Sjfb8856606 if (pmd->role == MEMIF_ROLE_CLIENT) {
5804418919fSjohnjiang if (dev->data->tx_queues != NULL)
5814418919fSjohnjiang mq = dev->data->tx_queues[i];
5824418919fSjohnjiang else
5834418919fSjohnjiang continue;
5844418919fSjohnjiang } else {
5854418919fSjohnjiang if (dev->data->rx_queues != NULL)
5864418919fSjohnjiang mq = dev->data->rx_queues[i];
5874418919fSjohnjiang else
5884418919fSjohnjiang continue;
5894418919fSjohnjiang }
5904418919fSjohnjiang if (mq->intr_handle.fd > 0) {
5914418919fSjohnjiang close(mq->intr_handle.fd);
5924418919fSjohnjiang mq->intr_handle.fd = -1;
5934418919fSjohnjiang }
5944418919fSjohnjiang }
595*2d9fd380Sjfb8856606 for (i = 0; i < pmd->cfg.num_s2c_rings; i++) {
596*2d9fd380Sjfb8856606 if (pmd->role == MEMIF_ROLE_SERVER) {
5974418919fSjohnjiang if (dev->data->tx_queues != NULL)
5984418919fSjohnjiang mq = dev->data->tx_queues[i];
5994418919fSjohnjiang else
6004418919fSjohnjiang continue;
6014418919fSjohnjiang } else {
6024418919fSjohnjiang if (dev->data->rx_queues != NULL)
6034418919fSjohnjiang mq = dev->data->rx_queues[i];
6044418919fSjohnjiang else
6054418919fSjohnjiang continue;
6064418919fSjohnjiang }
6074418919fSjohnjiang if (mq->intr_handle.fd > 0) {
6084418919fSjohnjiang close(mq->intr_handle.fd);
6094418919fSjohnjiang mq->intr_handle.fd = -1;
6104418919fSjohnjiang }
6114418919fSjohnjiang }
6124418919fSjohnjiang
6134418919fSjohnjiang memif_free_regions(dev);
6144418919fSjohnjiang
6154418919fSjohnjiang /* reset connection configuration */
6164418919fSjohnjiang memset(&pmd->run, 0, sizeof(pmd->run));
6174418919fSjohnjiang
618*2d9fd380Sjfb8856606 MIF_LOG(DEBUG, "Disconnected, id: %d, role: %s.", pmd->id,
619*2d9fd380Sjfb8856606 (pmd->role == MEMIF_ROLE_SERVER) ? "server" : "client");
6204418919fSjohnjiang }
6214418919fSjohnjiang
6224418919fSjohnjiang static int
memif_msg_receive(struct memif_control_channel * cc)6234418919fSjohnjiang memif_msg_receive(struct memif_control_channel *cc)
6244418919fSjohnjiang {
6254418919fSjohnjiang char ctl[CMSG_SPACE(sizeof(int)) +
6264418919fSjohnjiang CMSG_SPACE(sizeof(struct ucred))] = { 0 };
6274418919fSjohnjiang struct msghdr mh = { 0 };
6284418919fSjohnjiang struct iovec iov[1];
6294418919fSjohnjiang memif_msg_t msg = { 0 };
6304418919fSjohnjiang ssize_t size;
6314418919fSjohnjiang int ret = 0;
6324418919fSjohnjiang struct ucred *cr __rte_unused;
6334418919fSjohnjiang cr = 0;
6344418919fSjohnjiang struct cmsghdr *cmsg;
6354418919fSjohnjiang int afd = -1;
6364418919fSjohnjiang int i;
6374418919fSjohnjiang struct pmd_internals *pmd;
6384418919fSjohnjiang struct pmd_process_private *proc_private;
6394418919fSjohnjiang
6404418919fSjohnjiang iov[0].iov_base = (void *)&msg;
6414418919fSjohnjiang iov[0].iov_len = sizeof(memif_msg_t);
6424418919fSjohnjiang mh.msg_iov = iov;
6434418919fSjohnjiang mh.msg_iovlen = 1;
6444418919fSjohnjiang mh.msg_control = ctl;
6454418919fSjohnjiang mh.msg_controllen = sizeof(ctl);
6464418919fSjohnjiang
6474418919fSjohnjiang size = recvmsg(cc->intr_handle.fd, &mh, 0);
6484418919fSjohnjiang if (size != sizeof(memif_msg_t)) {
649*2d9fd380Sjfb8856606 MIF_LOG(DEBUG, "Invalid message size = %zd", size);
650*2d9fd380Sjfb8856606 if (size > 0)
651*2d9fd380Sjfb8856606 /* 0 means end-of-file, negative size means error,
652*2d9fd380Sjfb8856606 * don't send further disconnect message in such cases.
653*2d9fd380Sjfb8856606 */
6544418919fSjohnjiang memif_msg_enq_disconnect(cc, "Invalid message size", 0);
6554418919fSjohnjiang return -1;
6564418919fSjohnjiang }
6574418919fSjohnjiang MIF_LOG(DEBUG, "Received msg type: %u.", msg.type);
6584418919fSjohnjiang
6594418919fSjohnjiang cmsg = CMSG_FIRSTHDR(&mh);
6604418919fSjohnjiang while (cmsg) {
6614418919fSjohnjiang if (cmsg->cmsg_level == SOL_SOCKET) {
6624418919fSjohnjiang if (cmsg->cmsg_type == SCM_CREDENTIALS)
6634418919fSjohnjiang cr = (struct ucred *)CMSG_DATA(cmsg);
6644418919fSjohnjiang else if (cmsg->cmsg_type == SCM_RIGHTS)
6654418919fSjohnjiang rte_memcpy(&afd, CMSG_DATA(cmsg), sizeof(int));
6664418919fSjohnjiang }
6674418919fSjohnjiang cmsg = CMSG_NXTHDR(&mh, cmsg);
6684418919fSjohnjiang }
6694418919fSjohnjiang
6704418919fSjohnjiang if (cc->dev == NULL && msg.type != MEMIF_MSG_TYPE_INIT) {
6714418919fSjohnjiang MIF_LOG(DEBUG, "Unexpected message.");
6724418919fSjohnjiang memif_msg_enq_disconnect(cc, "Unexpected message", 0);
6734418919fSjohnjiang return -1;
6744418919fSjohnjiang }
6754418919fSjohnjiang
6764418919fSjohnjiang /* get device from hash data */
6774418919fSjohnjiang switch (msg.type) {
6784418919fSjohnjiang case MEMIF_MSG_TYPE_ACK:
6794418919fSjohnjiang break;
6804418919fSjohnjiang case MEMIF_MSG_TYPE_HELLO:
6814418919fSjohnjiang ret = memif_msg_receive_hello(cc->dev, &msg);
6824418919fSjohnjiang if (ret < 0)
6834418919fSjohnjiang goto exit;
6844418919fSjohnjiang ret = memif_init_regions_and_queues(cc->dev);
6854418919fSjohnjiang if (ret < 0)
6864418919fSjohnjiang goto exit;
6874418919fSjohnjiang ret = memif_msg_enq_init(cc->dev);
6884418919fSjohnjiang if (ret < 0)
6894418919fSjohnjiang goto exit;
6904418919fSjohnjiang pmd = cc->dev->data->dev_private;
6914418919fSjohnjiang proc_private = cc->dev->process_private;
6924418919fSjohnjiang for (i = 0; i < proc_private->regions_num; i++) {
6934418919fSjohnjiang ret = memif_msg_enq_add_region(cc->dev, i);
6944418919fSjohnjiang if (ret < 0)
6954418919fSjohnjiang goto exit;
6964418919fSjohnjiang }
697*2d9fd380Sjfb8856606 for (i = 0; i < pmd->run.num_c2s_rings; i++) {
6984418919fSjohnjiang ret = memif_msg_enq_add_ring(cc->dev, i,
699*2d9fd380Sjfb8856606 MEMIF_RING_C2S);
7004418919fSjohnjiang if (ret < 0)
7014418919fSjohnjiang goto exit;
7024418919fSjohnjiang }
703*2d9fd380Sjfb8856606 for (i = 0; i < pmd->run.num_s2c_rings; i++) {
7044418919fSjohnjiang ret = memif_msg_enq_add_ring(cc->dev, i,
705*2d9fd380Sjfb8856606 MEMIF_RING_S2C);
7064418919fSjohnjiang if (ret < 0)
7074418919fSjohnjiang goto exit;
7084418919fSjohnjiang }
7094418919fSjohnjiang ret = memif_msg_enq_connect(cc->dev);
7104418919fSjohnjiang if (ret < 0)
7114418919fSjohnjiang goto exit;
7124418919fSjohnjiang break;
7134418919fSjohnjiang case MEMIF_MSG_TYPE_INIT:
7144418919fSjohnjiang /*
7154418919fSjohnjiang * This cc does not have an interface asociated with it.
7164418919fSjohnjiang * If suitable interface is found it will be assigned here.
7174418919fSjohnjiang */
7184418919fSjohnjiang ret = memif_msg_receive_init(cc, &msg);
7194418919fSjohnjiang if (ret < 0)
7204418919fSjohnjiang goto exit;
7214418919fSjohnjiang ret = memif_msg_enq_ack(cc->dev);
7224418919fSjohnjiang if (ret < 0)
7234418919fSjohnjiang goto exit;
7244418919fSjohnjiang break;
7254418919fSjohnjiang case MEMIF_MSG_TYPE_ADD_REGION:
7264418919fSjohnjiang ret = memif_msg_receive_add_region(cc->dev, &msg, afd);
7274418919fSjohnjiang if (ret < 0)
7284418919fSjohnjiang goto exit;
7294418919fSjohnjiang ret = memif_msg_enq_ack(cc->dev);
7304418919fSjohnjiang if (ret < 0)
7314418919fSjohnjiang goto exit;
7324418919fSjohnjiang break;
7334418919fSjohnjiang case MEMIF_MSG_TYPE_ADD_RING:
7344418919fSjohnjiang ret = memif_msg_receive_add_ring(cc->dev, &msg, afd);
7354418919fSjohnjiang if (ret < 0)
7364418919fSjohnjiang goto exit;
7374418919fSjohnjiang ret = memif_msg_enq_ack(cc->dev);
7384418919fSjohnjiang if (ret < 0)
7394418919fSjohnjiang goto exit;
7404418919fSjohnjiang break;
7414418919fSjohnjiang case MEMIF_MSG_TYPE_CONNECT:
7424418919fSjohnjiang ret = memif_msg_receive_connect(cc->dev, &msg);
7434418919fSjohnjiang if (ret < 0)
7444418919fSjohnjiang goto exit;
7454418919fSjohnjiang ret = memif_msg_enq_connected(cc->dev);
7464418919fSjohnjiang if (ret < 0)
7474418919fSjohnjiang goto exit;
7484418919fSjohnjiang break;
7494418919fSjohnjiang case MEMIF_MSG_TYPE_CONNECTED:
7504418919fSjohnjiang ret = memif_msg_receive_connected(cc->dev, &msg);
7514418919fSjohnjiang break;
7524418919fSjohnjiang case MEMIF_MSG_TYPE_DISCONNECT:
7534418919fSjohnjiang ret = memif_msg_receive_disconnect(cc->dev, &msg);
7544418919fSjohnjiang if (ret < 0)
7554418919fSjohnjiang goto exit;
7564418919fSjohnjiang break;
7574418919fSjohnjiang default:
7584418919fSjohnjiang memif_msg_enq_disconnect(cc, "Unknown message type", 0);
7594418919fSjohnjiang ret = -1;
7604418919fSjohnjiang goto exit;
7614418919fSjohnjiang }
7624418919fSjohnjiang
7634418919fSjohnjiang exit:
7644418919fSjohnjiang return ret;
7654418919fSjohnjiang }
7664418919fSjohnjiang
7674418919fSjohnjiang static void
memif_intr_handler(void * arg)7684418919fSjohnjiang memif_intr_handler(void *arg)
7694418919fSjohnjiang {
7704418919fSjohnjiang struct memif_control_channel *cc = arg;
7714418919fSjohnjiang int ret;
7724418919fSjohnjiang
7734418919fSjohnjiang ret = memif_msg_receive(cc);
7744418919fSjohnjiang /* if driver failed to assign device */
7754418919fSjohnjiang if (cc->dev == NULL) {
7760c6bd470Sfengbojiang memif_msg_send_from_queue(cc);
7774418919fSjohnjiang ret = rte_intr_callback_unregister_pending(&cc->intr_handle,
7784418919fSjohnjiang memif_intr_handler,
7794418919fSjohnjiang cc,
7804418919fSjohnjiang memif_intr_unregister_handler);
7814418919fSjohnjiang if (ret < 0)
7824418919fSjohnjiang MIF_LOG(WARNING,
7834418919fSjohnjiang "Failed to unregister control channel callback.");
7844418919fSjohnjiang return;
7854418919fSjohnjiang }
7864418919fSjohnjiang /* if memif_msg_receive failed */
7874418919fSjohnjiang if (ret < 0)
7884418919fSjohnjiang goto disconnect;
7894418919fSjohnjiang
7904418919fSjohnjiang ret = memif_msg_send_from_queue(cc);
7914418919fSjohnjiang if (ret < 0)
7924418919fSjohnjiang goto disconnect;
7934418919fSjohnjiang
7944418919fSjohnjiang return;
7954418919fSjohnjiang
7964418919fSjohnjiang disconnect:
7974418919fSjohnjiang if (cc->dev == NULL) {
7984418919fSjohnjiang MIF_LOG(WARNING, "eth dev not allocated");
7994418919fSjohnjiang return;
8004418919fSjohnjiang }
8014418919fSjohnjiang memif_disconnect(cc->dev);
8024418919fSjohnjiang }
8034418919fSjohnjiang
8044418919fSjohnjiang static void
memif_listener_handler(void * arg)8054418919fSjohnjiang memif_listener_handler(void *arg)
8064418919fSjohnjiang {
8074418919fSjohnjiang struct memif_socket *socket = arg;
8084418919fSjohnjiang int sockfd;
8094418919fSjohnjiang int addr_len;
8104418919fSjohnjiang struct sockaddr_un client;
8114418919fSjohnjiang struct memif_control_channel *cc;
8124418919fSjohnjiang int ret;
8134418919fSjohnjiang
8144418919fSjohnjiang addr_len = sizeof(client);
8154418919fSjohnjiang sockfd = accept(socket->intr_handle.fd, (struct sockaddr *)&client,
8164418919fSjohnjiang (socklen_t *)&addr_len);
8174418919fSjohnjiang if (sockfd < 0) {
8184418919fSjohnjiang MIF_LOG(ERR,
8194418919fSjohnjiang "Failed to accept connection request on socket fd %d",
8204418919fSjohnjiang socket->intr_handle.fd);
8214418919fSjohnjiang return;
8224418919fSjohnjiang }
8234418919fSjohnjiang
8244418919fSjohnjiang MIF_LOG(DEBUG, "%s: Connection request accepted.", socket->filename);
8254418919fSjohnjiang
8264418919fSjohnjiang cc = rte_zmalloc("memif-cc", sizeof(struct memif_control_channel), 0);
8274418919fSjohnjiang if (cc == NULL) {
8284418919fSjohnjiang MIF_LOG(ERR, "Failed to allocate control channel.");
8294418919fSjohnjiang goto error;
8304418919fSjohnjiang }
8314418919fSjohnjiang
8324418919fSjohnjiang cc->intr_handle.fd = sockfd;
8334418919fSjohnjiang cc->intr_handle.type = RTE_INTR_HANDLE_EXT;
8344418919fSjohnjiang cc->socket = socket;
8354418919fSjohnjiang cc->dev = NULL;
8364418919fSjohnjiang TAILQ_INIT(&cc->msg_queue);
8374418919fSjohnjiang
8384418919fSjohnjiang ret = rte_intr_callback_register(&cc->intr_handle, memif_intr_handler, cc);
8394418919fSjohnjiang if (ret < 0) {
8404418919fSjohnjiang MIF_LOG(ERR, "Failed to register control channel callback.");
8414418919fSjohnjiang goto error;
8424418919fSjohnjiang }
8434418919fSjohnjiang
8444418919fSjohnjiang ret = memif_msg_enq_hello(cc);
8454418919fSjohnjiang if (ret < 0) {
8464418919fSjohnjiang MIF_LOG(ERR, "Failed to enqueue hello message.");
8474418919fSjohnjiang goto error;
8484418919fSjohnjiang }
8494418919fSjohnjiang ret = memif_msg_send_from_queue(cc);
8504418919fSjohnjiang if (ret < 0)
8514418919fSjohnjiang goto error;
8524418919fSjohnjiang
8534418919fSjohnjiang return;
8544418919fSjohnjiang
8554418919fSjohnjiang error:
8564418919fSjohnjiang if (sockfd >= 0) {
8574418919fSjohnjiang close(sockfd);
8584418919fSjohnjiang sockfd = -1;
8594418919fSjohnjiang }
8604418919fSjohnjiang if (cc != NULL)
8614418919fSjohnjiang rte_free(cc);
8624418919fSjohnjiang }
8634418919fSjohnjiang
8644418919fSjohnjiang static struct memif_socket *
memif_socket_create(char * key,uint8_t listener,bool is_abstract)865*2d9fd380Sjfb8856606 memif_socket_create(char *key, uint8_t listener, bool is_abstract)
8664418919fSjohnjiang {
8674418919fSjohnjiang struct memif_socket *sock;
868*2d9fd380Sjfb8856606 struct sockaddr_un un = { 0 };
8694418919fSjohnjiang int sockfd;
8704418919fSjohnjiang int ret;
8714418919fSjohnjiang int on = 1;
8724418919fSjohnjiang
8734418919fSjohnjiang sock = rte_zmalloc("memif-socket", sizeof(struct memif_socket), 0);
8744418919fSjohnjiang if (sock == NULL) {
8754418919fSjohnjiang MIF_LOG(ERR, "Failed to allocate memory for memif socket");
8764418919fSjohnjiang return NULL;
8774418919fSjohnjiang }
8784418919fSjohnjiang
8794418919fSjohnjiang sock->listener = listener;
8804418919fSjohnjiang strlcpy(sock->filename, key, MEMIF_SOCKET_UN_SIZE);
8814418919fSjohnjiang TAILQ_INIT(&sock->dev_queue);
8824418919fSjohnjiang
8834418919fSjohnjiang if (listener != 0) {
8844418919fSjohnjiang sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
8854418919fSjohnjiang if (sockfd < 0)
8864418919fSjohnjiang goto error;
8874418919fSjohnjiang
8884418919fSjohnjiang un.sun_family = AF_UNIX;
889*2d9fd380Sjfb8856606 if (is_abstract) {
890*2d9fd380Sjfb8856606 /* abstract address */
891*2d9fd380Sjfb8856606 un.sun_path[0] = '\0';
892*2d9fd380Sjfb8856606 strlcpy(un.sun_path + 1, sock->filename, MEMIF_SOCKET_UN_SIZE - 1);
893*2d9fd380Sjfb8856606 } else {
8944418919fSjohnjiang strlcpy(un.sun_path, sock->filename, MEMIF_SOCKET_UN_SIZE);
895*2d9fd380Sjfb8856606 }
8964418919fSjohnjiang
8974418919fSjohnjiang ret = setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &on,
8984418919fSjohnjiang sizeof(on));
8994418919fSjohnjiang if (ret < 0)
9004418919fSjohnjiang goto error;
9014418919fSjohnjiang
9024418919fSjohnjiang ret = bind(sockfd, (struct sockaddr *)&un, sizeof(un));
9034418919fSjohnjiang if (ret < 0)
9044418919fSjohnjiang goto error;
9054418919fSjohnjiang
9064418919fSjohnjiang ret = listen(sockfd, 1);
9074418919fSjohnjiang if (ret < 0)
9084418919fSjohnjiang goto error;
9094418919fSjohnjiang
9104418919fSjohnjiang MIF_LOG(DEBUG, "Memif listener socket %s created.", sock->filename);
9114418919fSjohnjiang
9124418919fSjohnjiang sock->intr_handle.fd = sockfd;
9134418919fSjohnjiang sock->intr_handle.type = RTE_INTR_HANDLE_EXT;
9144418919fSjohnjiang ret = rte_intr_callback_register(&sock->intr_handle,
9154418919fSjohnjiang memif_listener_handler, sock);
9164418919fSjohnjiang if (ret < 0) {
9174418919fSjohnjiang MIF_LOG(ERR, "Failed to register interrupt "
9184418919fSjohnjiang "callback for listener socket");
9194418919fSjohnjiang return NULL;
9204418919fSjohnjiang }
9214418919fSjohnjiang }
9224418919fSjohnjiang
9234418919fSjohnjiang return sock;
9244418919fSjohnjiang
9254418919fSjohnjiang error:
9264418919fSjohnjiang MIF_LOG(ERR, "Failed to setup socket %s: %s", key, strerror(errno));
9274418919fSjohnjiang if (sock != NULL)
9284418919fSjohnjiang rte_free(sock);
9294418919fSjohnjiang if (sockfd >= 0)
9304418919fSjohnjiang close(sockfd);
9314418919fSjohnjiang return NULL;
9324418919fSjohnjiang }
9334418919fSjohnjiang
9344418919fSjohnjiang static struct rte_hash *
memif_create_socket_hash(void)9354418919fSjohnjiang memif_create_socket_hash(void)
9364418919fSjohnjiang {
9374418919fSjohnjiang struct rte_hash_parameters params = { 0 };
9384418919fSjohnjiang
9394418919fSjohnjiang params.name = MEMIF_SOCKET_HASH_NAME;
9404418919fSjohnjiang params.entries = 256;
9414418919fSjohnjiang params.key_len = MEMIF_SOCKET_UN_SIZE;
9424418919fSjohnjiang params.hash_func = rte_jhash;
9434418919fSjohnjiang params.hash_func_init_val = 0;
9444418919fSjohnjiang return rte_hash_create(¶ms);
9454418919fSjohnjiang }
9464418919fSjohnjiang
9474418919fSjohnjiang int
memif_socket_init(struct rte_eth_dev * dev,const char * socket_filename)9484418919fSjohnjiang memif_socket_init(struct rte_eth_dev *dev, const char *socket_filename)
9494418919fSjohnjiang {
9504418919fSjohnjiang struct pmd_internals *pmd = dev->data->dev_private;
9514418919fSjohnjiang struct memif_socket *socket = NULL;
9524418919fSjohnjiang struct memif_socket_dev_list_elt *elt;
9534418919fSjohnjiang struct pmd_internals *tmp_pmd;
9544418919fSjohnjiang struct rte_hash *hash;
9554418919fSjohnjiang int ret;
9564418919fSjohnjiang char key[MEMIF_SOCKET_UN_SIZE];
9574418919fSjohnjiang
9584418919fSjohnjiang hash = rte_hash_find_existing(MEMIF_SOCKET_HASH_NAME);
9594418919fSjohnjiang if (hash == NULL) {
9604418919fSjohnjiang hash = memif_create_socket_hash();
9614418919fSjohnjiang if (hash == NULL) {
9624418919fSjohnjiang MIF_LOG(ERR, "Failed to create memif socket hash.");
9634418919fSjohnjiang return -1;
9644418919fSjohnjiang }
9654418919fSjohnjiang }
9664418919fSjohnjiang
9674418919fSjohnjiang memset(key, 0, MEMIF_SOCKET_UN_SIZE);
9684418919fSjohnjiang strlcpy(key, socket_filename, MEMIF_SOCKET_UN_SIZE);
9694418919fSjohnjiang ret = rte_hash_lookup_data(hash, key, (void **)&socket);
9704418919fSjohnjiang if (ret < 0) {
9714418919fSjohnjiang socket = memif_socket_create(key,
972*2d9fd380Sjfb8856606 (pmd->role == MEMIF_ROLE_CLIENT) ? 0 : 1,
973*2d9fd380Sjfb8856606 pmd->flags & ETH_MEMIF_FLAG_SOCKET_ABSTRACT);
9744418919fSjohnjiang if (socket == NULL)
9754418919fSjohnjiang return -1;
9764418919fSjohnjiang ret = rte_hash_add_key_data(hash, key, socket);
9774418919fSjohnjiang if (ret < 0) {
9784418919fSjohnjiang MIF_LOG(ERR, "Failed to add socket to socket hash.");
9794418919fSjohnjiang return ret;
9804418919fSjohnjiang }
9814418919fSjohnjiang }
9824418919fSjohnjiang pmd->socket_filename = socket->filename;
9834418919fSjohnjiang
9844418919fSjohnjiang TAILQ_FOREACH(elt, &socket->dev_queue, next) {
9854418919fSjohnjiang tmp_pmd = elt->dev->data->dev_private;
986*2d9fd380Sjfb8856606 if (tmp_pmd->id == pmd->id && tmp_pmd->role == pmd->role) {
987*2d9fd380Sjfb8856606 MIF_LOG(ERR, "Two interfaces with the same id (%d) can "
988*2d9fd380Sjfb8856606 "not have the same role.", pmd->id);
9894418919fSjohnjiang return -1;
9904418919fSjohnjiang }
9914418919fSjohnjiang }
9924418919fSjohnjiang
9934418919fSjohnjiang elt = rte_malloc("pmd-queue", sizeof(struct memif_socket_dev_list_elt), 0);
9944418919fSjohnjiang if (elt == NULL) {
9954418919fSjohnjiang MIF_LOG(ERR, "Failed to add device to socket device list.");
9964418919fSjohnjiang return -1;
9974418919fSjohnjiang }
9984418919fSjohnjiang elt->dev = dev;
9994418919fSjohnjiang TAILQ_INSERT_TAIL(&socket->dev_queue, elt, next);
10004418919fSjohnjiang
10014418919fSjohnjiang return 0;
10024418919fSjohnjiang }
10034418919fSjohnjiang
10044418919fSjohnjiang void
memif_socket_remove_device(struct rte_eth_dev * dev)10054418919fSjohnjiang memif_socket_remove_device(struct rte_eth_dev *dev)
10064418919fSjohnjiang {
10074418919fSjohnjiang struct pmd_internals *pmd = dev->data->dev_private;
10084418919fSjohnjiang struct memif_socket *socket = NULL;
10094418919fSjohnjiang struct memif_socket_dev_list_elt *elt, *next;
10104418919fSjohnjiang struct rte_hash *hash;
10114418919fSjohnjiang int ret;
10124418919fSjohnjiang
10134418919fSjohnjiang hash = rte_hash_find_existing(MEMIF_SOCKET_HASH_NAME);
10144418919fSjohnjiang if (hash == NULL)
10154418919fSjohnjiang return;
10164418919fSjohnjiang
10174418919fSjohnjiang if (pmd->socket_filename == NULL)
10184418919fSjohnjiang return;
10194418919fSjohnjiang
10204418919fSjohnjiang if (rte_hash_lookup_data(hash, pmd->socket_filename, (void **)&socket) < 0)
10214418919fSjohnjiang return;
10224418919fSjohnjiang
10234418919fSjohnjiang for (elt = TAILQ_FIRST(&socket->dev_queue); elt != NULL; elt = next) {
10244418919fSjohnjiang next = TAILQ_NEXT(elt, next);
10254418919fSjohnjiang if (elt->dev == dev) {
10264418919fSjohnjiang TAILQ_REMOVE(&socket->dev_queue, elt, next);
10274418919fSjohnjiang rte_free(elt);
10284418919fSjohnjiang pmd->socket_filename = NULL;
10294418919fSjohnjiang }
10304418919fSjohnjiang }
10314418919fSjohnjiang
10324418919fSjohnjiang /* remove socket, if this was the last device using it */
10334418919fSjohnjiang if (TAILQ_EMPTY(&socket->dev_queue)) {
10344418919fSjohnjiang rte_hash_del_key(hash, socket->filename);
1035*2d9fd380Sjfb8856606 if (socket->listener && !(pmd->flags & ETH_MEMIF_FLAG_SOCKET_ABSTRACT)) {
10364418919fSjohnjiang /* remove listener socket file,
10374418919fSjohnjiang * so we can create new one later.
10384418919fSjohnjiang */
10394418919fSjohnjiang ret = remove(socket->filename);
10404418919fSjohnjiang if (ret < 0)
10414418919fSjohnjiang MIF_LOG(ERR, "Failed to remove socket file: %s",
10424418919fSjohnjiang socket->filename);
10434418919fSjohnjiang }
10444418919fSjohnjiang rte_free(socket);
10454418919fSjohnjiang }
10464418919fSjohnjiang }
10474418919fSjohnjiang
10484418919fSjohnjiang int
memif_connect_server(struct rte_eth_dev * dev)1049*2d9fd380Sjfb8856606 memif_connect_server(struct rte_eth_dev *dev)
10504418919fSjohnjiang {
10514418919fSjohnjiang struct pmd_internals *pmd = dev->data->dev_private;
10524418919fSjohnjiang
10534418919fSjohnjiang memset(pmd->local_disc_string, 0, ETH_MEMIF_DISC_STRING_SIZE);
10544418919fSjohnjiang memset(pmd->remote_disc_string, 0, ETH_MEMIF_DISC_STRING_SIZE);
10554418919fSjohnjiang pmd->flags &= ~ETH_MEMIF_FLAG_DISABLED;
10564418919fSjohnjiang return 0;
10574418919fSjohnjiang }
10584418919fSjohnjiang
10594418919fSjohnjiang int
memif_connect_client(struct rte_eth_dev * dev)1060*2d9fd380Sjfb8856606 memif_connect_client(struct rte_eth_dev *dev)
10614418919fSjohnjiang {
10624418919fSjohnjiang int sockfd;
10634418919fSjohnjiang int ret;
1064*2d9fd380Sjfb8856606 struct sockaddr_un sun = { 0 };
10654418919fSjohnjiang struct pmd_internals *pmd = dev->data->dev_private;
10664418919fSjohnjiang
10674418919fSjohnjiang memset(pmd->local_disc_string, 0, ETH_MEMIF_DISC_STRING_SIZE);
10684418919fSjohnjiang memset(pmd->remote_disc_string, 0, ETH_MEMIF_DISC_STRING_SIZE);
10694418919fSjohnjiang pmd->flags &= ~ETH_MEMIF_FLAG_DISABLED;
10704418919fSjohnjiang
10714418919fSjohnjiang sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
10724418919fSjohnjiang if (sockfd < 0) {
10734418919fSjohnjiang MIF_LOG(ERR, "Failed to open socket.");
10744418919fSjohnjiang return -1;
10754418919fSjohnjiang }
10764418919fSjohnjiang
10774418919fSjohnjiang sun.sun_family = AF_UNIX;
1078*2d9fd380Sjfb8856606 if (pmd->flags & ETH_MEMIF_FLAG_SOCKET_ABSTRACT) {
1079*2d9fd380Sjfb8856606 /* abstract address */
1080*2d9fd380Sjfb8856606 sun.sun_path[0] = '\0';
1081*2d9fd380Sjfb8856606 strlcpy(sun.sun_path + 1, pmd->socket_filename, MEMIF_SOCKET_UN_SIZE - 1);
1082*2d9fd380Sjfb8856606 } else {
1083*2d9fd380Sjfb8856606 strlcpy(sun.sun_path, pmd->socket_filename, MEMIF_SOCKET_UN_SIZE);
1084*2d9fd380Sjfb8856606 }
10854418919fSjohnjiang
10864418919fSjohnjiang ret = connect(sockfd, (struct sockaddr *)&sun,
10874418919fSjohnjiang sizeof(struct sockaddr_un));
10884418919fSjohnjiang if (ret < 0) {
10894418919fSjohnjiang MIF_LOG(ERR, "Failed to connect socket: %s.", pmd->socket_filename);
10904418919fSjohnjiang goto error;
10914418919fSjohnjiang }
10924418919fSjohnjiang
10934418919fSjohnjiang MIF_LOG(DEBUG, "Memif socket: %s connected.", pmd->socket_filename);
10944418919fSjohnjiang
10954418919fSjohnjiang pmd->cc = rte_zmalloc("memif-cc",
10964418919fSjohnjiang sizeof(struct memif_control_channel), 0);
10974418919fSjohnjiang if (pmd->cc == NULL) {
10984418919fSjohnjiang MIF_LOG(ERR, "Failed to allocate control channel.");
10994418919fSjohnjiang goto error;
11004418919fSjohnjiang }
11014418919fSjohnjiang
11024418919fSjohnjiang pmd->cc->intr_handle.fd = sockfd;
11034418919fSjohnjiang pmd->cc->intr_handle.type = RTE_INTR_HANDLE_EXT;
11044418919fSjohnjiang pmd->cc->socket = NULL;
11054418919fSjohnjiang pmd->cc->dev = dev;
11064418919fSjohnjiang TAILQ_INIT(&pmd->cc->msg_queue);
11074418919fSjohnjiang
11084418919fSjohnjiang ret = rte_intr_callback_register(&pmd->cc->intr_handle,
11094418919fSjohnjiang memif_intr_handler, pmd->cc);
11104418919fSjohnjiang if (ret < 0) {
11114418919fSjohnjiang MIF_LOG(ERR, "Failed to register interrupt callback for control fd");
11124418919fSjohnjiang goto error;
11134418919fSjohnjiang }
11144418919fSjohnjiang
11154418919fSjohnjiang return 0;
11164418919fSjohnjiang
11174418919fSjohnjiang error:
11184418919fSjohnjiang if (sockfd >= 0) {
11194418919fSjohnjiang close(sockfd);
11204418919fSjohnjiang sockfd = -1;
11214418919fSjohnjiang }
11224418919fSjohnjiang if (pmd->cc != NULL) {
11234418919fSjohnjiang rte_free(pmd->cc);
11244418919fSjohnjiang pmd->cc = NULL;
11254418919fSjohnjiang }
11264418919fSjohnjiang return -1;
11274418919fSjohnjiang }
1128