Пример #1
0
USocket *usock_accept(int fd, void *cred_p, int clen)
{
	USocket *usock = NULL;
	struct sockaddr_in addr;
	socklen_t alen = sizeof(addr);
	char buf[clen];
	Uint32 val, n;

	while (1) {
		n = recvfrom(fd, buf, clen, 0, (Sockaddr *)&addr, &alen);
		if (n < 0) {
			perror("recvform");
			break;
		}
		else if (n == clen && memcmp(cred_p, buf, clen) == 0) {
			usock = create_usock(fd, &addr, cred_p, clen);
			break;
		}
	}

	if (usock == NULL)
		return NULL;

	n = send_accept_msg(fd, &val);
	if (n == sizeof(val) || val == UMSG_REPLY_ACCEPT) {
		usock->status |= USOCK_CONNECT;
		sem_post(&usock->sem);
		return usock;
	}

	sem_post(&usock->sem);
	usock_close(usock);
	return NULL;
}
Пример #2
0
USocket *
usock_connect(int fd, struct sockaddr_in *addr_p, void *cred_p, Uint32 clen)
{
	USocket *usock;
	Uint32 val;
	int n;

	if (!(usock = create_usock(fd, addr_p, cred_p, clen)))
		return NULL;

	n = send_connect_msg(fd, cred_p, clen, &val);
	if (n != sizeof(val) || val != UMSG_ACCEPT)
		goto reterr;

	val = htonl(UMSG_REPLY_ACCEPT);
	if (write(fd, &val, sizeof(val)) == sizeof(val)) {
		usock->status |= USOCK_CONNECT;
		sem_post(&usock->sem);
		return usock;
	}

reterr:
	sem_post(&usock->sem);
	usock_close(usock);
	return NULL;
}
static void
usock_close(struct vr_usocket *usockp)
{
    int i;
    struct vr_usocket *parent;

    RTE_SET_USED(parent);

    if (!usockp)
        return;

    RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d\n", __func__, pthread_self(), usockp->usock_fd);
    usock_unbind(usockp);
    usock_deinit_poll(usockp);

    for (i = 0; i < usockp->usock_cfds; i++) {
        usock_close(usockp->usock_children[i]);
    }

    RTE_LOG(DEBUG, USOCK, "%s: closing FD %d\n", __func__, usockp->usock_fd);
    close(usockp->usock_fd);

    if (!usockp->usock_mbuf_pool && usockp->usock_rx_buf) {
        vr_free(usockp->usock_rx_buf, VR_USOCK_BUF_OBJECT);
        usockp->usock_rx_buf = NULL;
    }

    if (usockp->usock_iovec) {
        vr_free(usockp->usock_iovec, VR_USOCK_IOVEC_OBJECT);
        usockp->usock_iovec = NULL;
    }

    if (usockp->usock_mbuf_pool) {
        /* no api to destroy a pool */
    }

    if (usockp->usock_proto == PACKET) {
        RTE_LOG(DEBUG, USOCK, "%s[%lx]: unlinking %s\n", __func__,
            pthread_self(), VR_PACKET_UNIX_FILE);
        unlink(VR_PACKET_UNIX_FILE);
    }

    usockp->usock_io_in_progress = 0;

    vr_free(usockp, VR_USOCK_OBJECT);

    return;
}
void
vr_usocket_close(void *sock)
{
    struct vr_usocket *usockp = (struct vr_usocket *)sock;

    if (usockp == NULL)
        return;

    RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d\n", __func__, pthread_self(),
                usockp->usock_fd);
    if (usockp->usock_io_in_progress) {
        usockp->usock_should_close = 1;
        return;
    }

    usock_close(usockp);
    return;
}
static int
vr_usocket_read(struct vr_usocket *usockp)
{
    int ret;

    if (!usockp || usockp->usock_fd < 0)
        return -1;

    switch (usockp->usock_state) {
    case LISTENING:
    case LIMITED:
        ret = vr_usocket_accept(usockp);
        if (ret < 0)
            return ret;

        break;

    case READING_HEADER:
    case READING_DATA:
    case READING_FAULTY_DATA:
        ret = __usock_read(usockp);
        if (ret < 0) {
            RTE_LOG(DEBUG, USOCK, "%s[%lx]: read error FD %d\n", __func__, pthread_self(),
                        usockp->usock_fd);
            usock_close(usockp);
            return ret;
        }

        if (usockp->usock_read_offset == usockp->usock_read_len) {
            usock_read_done(usockp);
            /* we have the complete message */
            usock_read_init(usockp);
        }

        break;

    default:
        return -1;
    }

    return ret;
}
static int
usock_write(struct vr_usocket *usockp)
{
    int ret;

    if (!usockp || usockp->usock_fd < 0)
        return 0;

    ret = __usock_write(usockp);
    if (ret < 0) {
        usock_close(usockp);
        return ret;
    }

    if (usockp->usock_proto == NETLINK) {
        if (usockp->usock_write_offset == usockp->usock_write_len) {
            usock_netlink_write_responses(usockp);
        }
    }

    return 0;
}
static struct vr_usocket *
usock_alloc(unsigned short proto, unsigned short type)
{
    int sock_fd = -1, domain, ret;
    /* socket TX buffer size = (hold flow table entries * size of jumbo frame) */
    int setsocksndbuff = vr_flow_hold_limit * VR_DPDK_MAX_PACKET_SZ;
    int getsocksndbuff;
    socklen_t getsocksndbufflen = sizeof(getsocksndbuff);
    int error = 0, flags;
    unsigned int buf_len;
    struct vr_usocket *usockp = NULL, *child;
    bool is_socket = true;
    unsigned short sock_type;

    RTE_SET_USED(child);

    RTE_LOG(DEBUG, USOCK, "%s[%lx]: proto %u type %u\n", __func__,
                pthread_self(), proto, type);
    switch (type) {
    case TCP:
        domain = AF_INET;
        sock_type = SOCK_STREAM;
        break;

    case UNIX:
    case RAW:
        domain = AF_UNIX;
        sock_type = SOCK_DGRAM;
        break;

    default:
        return NULL;
    }

    if (proto == EVENT) {
        is_socket = false;
        sock_fd = eventfd(0, 0);
        RTE_LOG(DEBUG, USOCK, "%s[%lx]: new event FD %d\n", __func__,
                pthread_self(), sock_fd);
        if (sock_fd < 0)
            return NULL;
    }

    if (is_socket) {
        sock_fd = socket(domain, sock_type, 0);
        RTE_LOG(INFO, USOCK, "%s[%lx]: new socket FD %d\n", __func__,
                pthread_self(), sock_fd);
        if (sock_fd < 0)
            return NULL;

        /* set socket send buffer size */
        ret = setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &setsocksndbuff,
                         sizeof(setsocksndbuff));
        if (ret == 0) {
            /* check if setting buffer succeeded */
            ret = getsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &getsocksndbuff,
                             &getsocksndbufflen);
            if (ret == 0) {
                if (getsocksndbuff >= setsocksndbuff) {
                    RTE_LOG(INFO, USOCK, "%s[%lx]: setting socket FD %d send buff size.\n"
                            "Buffer size set to %d (requested %d)\n", __func__,
                            pthread_self(), sock_fd, getsocksndbuff, setsocksndbuff);
                } else { /* set other than requested */
                    RTE_LOG(ERR, USOCK, "%s[%lx]: setting socket FD %d send buff size failed.\n"
                            "Buffer size set to %d (requested %d)\n", __func__,
                            pthread_self(), sock_fd, getsocksndbuff, setsocksndbuff);
                }
            } else { /* requesting buffer size failed */
                RTE_LOG(ERR, USOCK, "%s[%lx]: getting socket FD %d send buff size failed (%d)\n",
                         __func__, pthread_self(), sock_fd, errno);
            }
        } else { /* setting buffer size failed */
            RTE_LOG(ERR, USOCK, "%s[%lx]: setting socket FD %d send buff size %d failed (%d)\n",
                     __func__, pthread_self(), sock_fd, setsocksndbuff, errno);
        }
    }

    usockp = vr_zalloc(sizeof(*usockp), VR_USOCK_OBJECT);
    if (!usockp)
        goto error_exit;

    usockp->usock_type = type;
    usockp->usock_proto = proto;
    usockp->usock_fd = sock_fd;
    usockp->usock_state = INITED;

    if (is_socket) {
        error = vr_usocket_bind(usockp);
        if (error < 0)
            goto error_exit;

        if (usockp->usock_proto == PACKET) {
            error = vr_usocket_connect(usockp);
            if (error < 0)
                goto error_exit;
        }
    }

    switch (proto) {
    case NETLINK:
        usockp->usock_max_cfds = USOCK_MAX_CHILD_FDS;
        buf_len = 0;
        break;

    case PACKET:
        usockp->usock_max_cfds = USOCK_MAX_CHILD_FDS;
        buf_len = 0;
        break;

    case EVENT:
        /* TODO: we don't need the buf since we use stack to send an event */
        buf_len = USOCK_EVENT_BUF_LEN;
        break;

    default:
        buf_len = 0;
        break;
    }

    if (buf_len) {
        usockp->usock_rx_buf = vr_zalloc(buf_len, VR_USOCK_BUF_OBJECT);
        if (!usockp->usock_rx_buf)
            goto error_exit;

        usockp->usock_buf_len = buf_len;
        usock_read_init(usockp);
    }

    if (proto == PACKET) {
        usockp->usock_mbuf_pool = rte_mempool_lookup("packet_mbuf_pool");
        if (!usockp->usock_mbuf_pool) {
            usockp->usock_mbuf_pool = rte_mempool_create("packet_mbuf_pool",
                    PKT0_MBUF_POOL_SIZE, PKT0_MBUF_PACKET_SIZE,
                    PKT0_MBUF_POOL_CACHE_SZ, sizeof(struct rte_pktmbuf_pool_private),
                    vr_dpdk_pktmbuf_pool_init, NULL, vr_dpdk_pktmbuf_init, NULL,
                    rte_socket_id(), 0);
            if (!usockp->usock_mbuf_pool)
                goto error_exit;
        }

        usockp->usock_iovec = vr_zalloc(sizeof(struct iovec) *
                PKT0_MAX_IOV_LEN, VR_USOCK_IOVEC_OBJECT);
        if (!usockp->usock_iovec)
            goto error_exit;

        usock_read_init(usockp);
    }

    RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d F_GETFL\n", __func__, pthread_self(),
                usockp->usock_fd);
    flags = fcntl(usockp->usock_fd, F_GETFL);
    if (flags == -1)
        goto error_exit;

    RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d F_SETFL\n", __func__, pthread_self(),
                usockp->usock_fd);
    error = fcntl(usockp->usock_fd, F_SETFL, flags | O_NONBLOCK);
    if (error == -1)
        goto error_exit;

    usockp->usock_poll_block = 1;

    return usockp;

error_exit:

    error = errno;
    if (sock_fd >= 0) {
        close(sock_fd);
        sock_fd = -1;
    }

    usock_close(usockp);
    usockp = NULL;
    errno = error;

    return usockp;
}
/*
 * start io on socket
 */
int
vr_usocket_io(void *transport)
{
    int ret, i, processed;
    int timeout;
    struct pollfd *pfd;
    struct vr_usocket *usockp = (struct vr_usocket *)transport;
    unsigned lcore_id = rte_lcore_id();
    struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];

    if (!usockp)
        return -1;

    RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d\n", __func__, pthread_self(),
                usockp->usock_fd);
    if ((ret = usock_init_poll(usockp)))
        goto return_from_io;

    pfd = &usockp->usock_pfds[0];
    pfd->fd = usockp->usock_fd;
    pfd->events = POLLIN;

    usockp->usock_io_in_progress = 1;

    timeout = usockp->usock_poll_block ? INFINITE_TIMEOUT : 0;
    while (1) {
        if (usockp->usock_should_close) {
            usock_close(usockp);
            return -1;
        }

        /*
         * Handle an IPC commands for IO_LCORE_ID up
         * and just check the stop flag for the rest.
         */
        if (lcore_id >= VR_DPDK_IO_LCORE_ID) {
            if (unlikely(vr_dpdk_lcore_cmd_handle(lcore)))
                break;
        } else {
            if (unlikely(vr_dpdk_is_stop_flag_set()))
                break;
        }

        rcu_thread_offline();
        ret = poll(usockp->usock_pfds, usockp->usock_max_cfds,
                timeout);
        if (ret < 0) {
            usock_set_error(usockp, ret);
            /* all other errors are fatal */
            if (errno != EINTR)
                goto return_from_io;
        }

        rcu_thread_online();

        processed = 0;
        pfd = usockp->usock_pfds;
        for (i = 0; (i < usockp->usock_max_cfds) && (processed < ret);
                i++, pfd++) {
            if ((pfd->fd >= 0)) {
                if (pfd->revents & POLLIN) {
                    if (i == 0) {
                        ret = vr_usocket_read(usockp);
                        if (ret < 0)
                            return ret;
                    } else {
                        vr_usocket_read(usockp->usock_children[i]);
                    }
                }

                if (pfd->revents & POLLOUT) {
                    usock_write(usockp->usock_children[i]);
                }

                if (pfd->revents & POLLHUP) {
                    if (i) {
                        usock_close(usockp->usock_children[i]);
                    } else {
                        break;
                    }
                }

                if (pfd->revents)
                    processed++;
            }
        }

        if (!timeout)
            return 0;
    }

return_from_io:
    usockp->usock_io_in_progress = 0;
    usock_deinit_poll(usockp);

    return ret;
}