Beispiel #1
0
static int
test_misc(void)
{
	char memdump[] = "memdump_test";
	if (rte_bsf32(129))
		FAIL("rte_bsf32");

	rte_memdump(stdout, "test", memdump, sizeof(memdump));
	rte_hexdump(stdout, "test", memdump, sizeof(memdump));

	rte_pause();

	return 0;
}
static int
usock_mbuf_write(struct vr_usocket *usockp, struct rte_mbuf *mbuf)
{
    unsigned int i, pkt_len;
    struct msghdr mhdr;
    struct rte_mbuf *m;
    struct iovec *iov;

    if (!mbuf)
        return 0;

    pkt_len = rte_pktmbuf_pkt_len(mbuf);
    if (!pkt_len)
        return 0;

    iov = usockp->usock_iovec;

    m = mbuf;
    for (i = 0; (m && (i < PKT0_MAX_IOV_LEN)); i++) {
        iov->iov_base = rte_pktmbuf_mtod(m, unsigned char *);
        iov->iov_len = rte_pktmbuf_data_len(m);
        m = m->next;
        iov++;
    }

    if ((i == PKT0_MAX_IOV_LEN) && m)
        usockp->usock_pkt_truncated++;

    mhdr.msg_name = NULL;
    mhdr.msg_namelen = 0;
    mhdr.msg_iov = usockp->usock_iovec;
    mhdr.msg_iovlen = i;
    mhdr.msg_control = NULL;
    mhdr.msg_controllen = 0;
    mhdr.msg_flags = 0;

#ifdef VR_DPDK_USOCK_DUMP
    RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d sending message\n", __func__,
            pthread_self(), usockp->usock_fd);
    rte_hexdump(stdout, "usock message dump:", &mhdr, sizeof(mhdr));
#endif
    return sendmsg(usockp->usock_fd, &mhdr, MSG_DONTWAIT);
}
static int
vr_usocket_connect(struct vr_usocket *usockp)
{
    struct sockaddr_un sun;

    RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d\n", __func__, pthread_self(),
                usockp->usock_fd);
    if (usockp->usock_proto != PACKET)
        return -EINVAL;

    sun.sun_family = AF_UNIX;
    memset(sun.sun_path, 0, sizeof(sun.sun_path));
    strncpy(sun.sun_path, VR_PACKET_AGENT_UNIX_FILE, sizeof(sun.sun_path) - 1);

#ifdef VR_DPDK_USOCK_DUMP
    RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d retry connecting\n", __func__,
            pthread_self(), usockp->usock_fd);
    rte_hexdump(stdout, "usock address dump:", &sun, sizeof(sun));
#endif
    return vr_dpdk_retry_connect(usockp->usock_fd, (struct sockaddr *)&sun,
                                        sizeof(sun));
}
static int
__usock_read(struct vr_usocket *usockp)
{
    int ret;
    unsigned int offset = usockp->usock_read_offset;
    unsigned int len = usockp->usock_read_len;
    unsigned int toread = len - offset;

    struct nlmsghdr *nlh;
    unsigned int proto = usockp->usock_proto;
    char *buf = usockp->usock_rx_buf;

    if (toread > usockp->usock_buf_len) {
        toread = usockp->usock_buf_len - offset;
    }

retry_read:
    if (usockp->usock_owner != pthread_self()) {
        if (usockp->usock_owner)
            RTE_LOG(WARNING, USOCK, "WARNING: thread %lx is trying to read"
                " usocket FD %d owned by thread %lx\n",
                pthread_self(), usockp->usock_fd, usockp->usock_owner);
        usockp->usock_owner = pthread_self();
    }
    ret = read(usockp->usock_fd, buf + offset, toread);
#ifdef VR_DPDK_USOCK_DUMP
    if (ret > 0) {
        RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d read %d bytes\n", __func__,
            pthread_self(), usockp->usock_fd, ret);
        rte_hexdump(stdout, "usock buffer dump:", buf + offset, ret);
    } else if (ret < 0) {
        RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d read returned error %d: %s (%d)\n", __func__,
            pthread_self(), usockp->usock_fd, ret, rte_strerror(errno), errno);
    }
#endif
    if (ret <= 0) {
        if (!ret)
            return -1;

        if (errno == EINTR)
            goto retry_read;

        if ((errno == EAGAIN) ||
                (errno == EWOULDBLOCK))
            return 0;

        RTE_LOG(ERR, USOCK, "Error reading FD %d: %s (%d)\n",
                usockp->usock_fd, rte_strerror(errno), errno);
        return ret;
    }

    offset += ret;
    usockp->usock_read_offset = offset;

    if (proto == NETLINK) {
        if (usockp->usock_state == READING_HEADER) {
            if (usockp->usock_read_offset == usockp->usock_read_len) {
                usockp->usock_state = READING_DATA;
                nlh = (struct nlmsghdr *)(usockp->usock_rx_buf);
                usockp->usock_read_len = nlh->nlmsg_len;
            }
        }

        if (usockp->usock_buf_len < usockp->usock_read_len) {
            usockp->usock_rx_buf = vr_malloc(usockp->usock_read_len,
                    VR_USOCK_BUF_OBJECT);
            if (!usockp->usock_rx_buf) {
                /* bad, but let's recover */
                usockp->usock_rx_buf = buf;
                usockp->usock_read_len -= usockp->usock_read_offset;
                usockp->usock_read_offset = 0;
                usockp->usock_state = READING_FAULTY_DATA;
            } else {
                memcpy(usockp->usock_rx_buf, buf, usockp->usock_read_offset);
                vr_free(buf, VR_USOCK_BUF_OBJECT);
                usockp->usock_buf_len = usockp->usock_read_len;
                buf = usockp->usock_rx_buf;
            }
        }
    } else if (proto == PACKET) {
        usockp->usock_read_len = ret;
    }

    return ret;
}
static int
__usock_write(struct vr_usocket *usockp)
{
    int ret;
    unsigned int len;
    unsigned char *buf;
    struct vr_usocket *parent = NULL;

    if (usockp->usock_proto != EVENT) {
        parent = usockp->usock_parent;
        if (!parent)
            return -1;
    }

    buf = usockp->usock_tx_buf;
    if (!buf || !usockp->usock_write_len)
        return 0;

    len = usockp->usock_write_len;

    buf += usockp->usock_write_offset;
    len -= usockp->usock_write_offset;

retry_write:
#ifdef VR_DPDK_USOCK_DUMP
    RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d writing %d bytes\n",
                __func__, pthread_self(), usockp->usock_fd, len);
    rte_hexdump(stdout, "usock buffer dump:", buf, len);
#endif
    if (usockp->usock_owner != pthread_self()) {
        if (usockp->usock_owner)
            RTE_LOG(WARNING, USOCK, "WARNING: thread %lx (lcore %u) is trying to write %u bytes"
                " to usocket FD %d owned by thread %lx\n",
                pthread_self(), rte_lcore_id(), len, usockp->usock_fd, usockp->usock_owner);
        usockp->usock_owner = pthread_self();
    }
    ret = write(usockp->usock_fd, buf, len);
    if (ret > 0) {
        usockp->usock_write_offset += ret;
        if (usockp->usock_write_offset == usockp->usock_write_len) {
            /* remove from output poll */
            if (parent)
                parent->usock_pfds[usockp->usock_child_index].events = POLLIN;
            usockp->usock_tx_buf = NULL;
        } else {
            if (parent)
                parent->usock_pfds[usockp->usock_child_index].events = POLLOUT;
        }
    } else if (ret < 0) {
        RTE_LOG(DEBUG, VROUTER, "%s[%lx]: write error FD %d\n", __func__, pthread_self(),
                usockp->usock_fd);
        usock_set_error(usockp, ret);

        if (errno == EINTR)
            goto retry_write;

        if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
            if (parent) {
                parent->usock_pfds[usockp->usock_child_index].events = POLLOUT;
                return 0;
            }
        }
        usockp->usock_tx_buf = NULL;
    }

    return ret;
}
static int
vr_usocket_bind(struct vr_usocket *usockp)
{
    int error = 0;
    struct sockaddr_in sin;
    struct sockaddr_un sun;
    struct sockaddr *addr = NULL;
    socklen_t addrlen = 0;
    int optval;
    bool server;

    optval = 1;
    RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d setting option\n", __func__,
            pthread_self(), usockp->usock_fd);
    if (setsockopt(usockp->usock_fd, SOL_SOCKET, SO_REUSEADDR, &optval,
                sizeof(optval)))
        return -errno;

    switch (usockp->usock_type) {
    case TCP:
        sin.sin_family = AF_INET;
        sin.sin_port = rte_cpu_to_be_16(VR_NETLINK_TCP_PORT);
        sin.sin_addr.s_addr = INADDR_ANY;
        addr = (struct sockaddr *)&sin;
        addrlen = sizeof(sin);
        server = true;

        break;

    case UNIX:
        sun.sun_family = AF_UNIX;
        memset(sun.sun_path, 0, sizeof(sun.sun_path));
        strncpy(sun.sun_path, VR_NETLINK_UNIX_FILE, sizeof(sun.sun_path) - 1);
        addr = (struct sockaddr *)&sun;
        addrlen = sizeof(sun);
        server = true;
        mkdir(VR_SOCKET_DIR, VR_SOCKET_DIR_MODE);
        unlink(sun.sun_path);

        break;

    case RAW:
        sun.sun_family = AF_UNIX;
        memset(sun.sun_path, 0, sizeof(sun.sun_path));
        strncpy(sun.sun_path, VR_PACKET_UNIX_FILE, sizeof(sun.sun_path) - 1);
        addr = (struct sockaddr *)&sun;
        addrlen = sizeof(sun);
        server = false;
        mkdir(VR_SOCKET_DIR, VR_SOCKET_DIR_MODE);
        unlink(sun.sun_path);

        break;

    default:
        return -EINVAL;
    }

#ifdef VR_DPDK_USOCK_DUMP
    RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d binding\n", __func__, pthread_self(),
            usockp->usock_fd);
    rte_hexdump(stdout, "usock address dump:", addr, addrlen);
#endif
    error = bind(usockp->usock_fd, addr, addrlen);
    if (error < 0)
        return error;

    if (server) {
        RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d listening\n", __func__,
                pthread_self(),  usockp->usock_fd);
        error = listen(usockp->usock_fd, 1);
        if (error < 0)
            return error;
        usockp->usock_state = LISTENING;
    }

    return 0;
}
/*
 * vr_uvh_cl_msg_handler - handler for messages from user space vhost
 * clients. Calls the appropriate handler based on the message type.
 *
 * Returns 0 on success, -1 on error.
 *
 * TODO: upon error, this function currently makes the process exit.
 * Instead, it should close the socket and continue serving other clients.
 */
static int
vr_uvh_cl_msg_handler(int fd, void *arg)
{
    vr_uvh_client_t *vru_cl = (vr_uvh_client_t *) arg;
    struct msghdr mhdr;
    struct iovec iov;
    int i, err, ret = 0, read_len = 0;
    struct cmsghdr *cmsg;

    memset(&mhdr, 0, sizeof(mhdr));

    if (vru_cl->vruc_msg_bytes_read == 0) {
        mhdr.msg_control = &vru_cl->vruc_cmsg;
        mhdr.msg_controllen = sizeof(vru_cl->vruc_cmsg);

        iov.iov_base = (void *) &vru_cl->vruc_msg;
        iov.iov_len = VHOST_USER_HSIZE;

        mhdr.msg_iov = &iov;
        mhdr.msg_iovlen = 1;

        ret = recvmsg(fd, &mhdr, MSG_DONTWAIT);
        if (ret < 0) {
            if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                ret = 0;
                goto cleanup;
            }

            vr_uvhost_log("Receive returned %d in vhost server for client %s\n",
                          ret, vru_cl->vruc_path);
            ret = -1;
            goto cleanup;
        } else if (ret > 0) {
            if (mhdr.msg_flags & MSG_CTRUNC) {
                vr_uvhost_log("Truncated control message from vhost client %s\n",
                             vru_cl->vruc_path);
                ret = -1;
                goto cleanup;
            }

            cmsg = CMSG_FIRSTHDR(&mhdr);
            if (cmsg && (cmsg->cmsg_len > 0) &&
                   (cmsg->cmsg_level == SOL_SOCKET) &&
                   (cmsg->cmsg_type == SCM_RIGHTS)) {
                   vru_cl->vruc_num_fds_sent = (cmsg->cmsg_len - CMSG_LEN(0))/
                                                   sizeof(int);
                   if (vru_cl->vruc_num_fds_sent > VHOST_MEMORY_MAX_NREGIONS) {
                        vr_uvhost_log("Too many FDs sent for client %s: %d\n",
                                vru_cl->vruc_path,  vru_cl->vruc_num_fds_sent);
                       vru_cl->vruc_num_fds_sent = VHOST_MEMORY_MAX_NREGIONS;
                   }

                   memcpy(vru_cl->vruc_fds_sent, CMSG_DATA(cmsg),
                          vru_cl->vruc_num_fds_sent*sizeof(int));
            }

            vru_cl->vruc_msg_bytes_read = ret;
            if (ret < VHOST_USER_HSIZE) {
                ret = 0;
                goto cleanup;
            }

            read_len = vru_cl->vruc_msg.size;
        } else {
            /*
             * recvmsg returned 0, so return error.
             */
            vr_uvhost_log("Receive returned %d in vhost server for client %s\n",
                          ret, vru_cl->vruc_path);
            ret = -1;
            goto cleanup;
        }
    } else if (vru_cl->vruc_msg_bytes_read < VHOST_USER_HSIZE) {
        read_len = VHOST_USER_HSIZE - vru_cl->vruc_msg_bytes_read;
    } else {
        read_len = vru_cl->vruc_msg.size -
                       (vru_cl->vruc_msg_bytes_read - VHOST_USER_HSIZE);
    }

    if (read_len) {
        if (vru_cl->vruc_owner != pthread_self()) {
            if (vru_cl->vruc_owner)
                RTE_LOG(WARNING, UVHOST, "WARNING: thread %lx is trying to read"
                    " uvhost client FD %d owned by thread %lx\n",
                    pthread_self(), fd, vru_cl->vruc_owner);
            vru_cl->vruc_owner = pthread_self();
        }
        ret = read(fd, (((char *)&vru_cl->vruc_msg) + vru_cl->vruc_msg_bytes_read),
                   read_len);
#ifdef VR_DPDK_RX_PKT_DUMP
        if (ret > 0) {
            RTE_LOG(DEBUG, UVHOST, "%s[%lx]: FD %d read %d bytes\n", __func__,
                pthread_self(), fd, ret);
            rte_hexdump(stdout, "uvhost full message dump:",
                (((char *)&vru_cl->vruc_msg)),
                    ret + vru_cl->vruc_msg_bytes_read);
        } else if (ret < 0) {
            RTE_LOG(DEBUG, UVHOST, "%s[%lx]: FD %d read returned error %d: %s (%d)\n", __func__,
                pthread_self(), fd, ret, rte_strerror(errno), errno);
        }
#endif
        if (ret < 0) {
            if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                ret = 0;
                goto cleanup;
            }

            vr_uvhost_log(
                "Error: read returned %d, %d %d %d in vhost server for client %s\n",
                ret, errno, read_len,
                vru_cl->vruc_msg_bytes_read, vru_cl->vruc_path);
            ret = -1;
            goto cleanup;
        } else if (ret == 0) {
             vr_uvhost_log("Read returned %d in vhost server for client %s\n",
                           ret, vru_cl->vruc_path);
            ret = -1;
            goto cleanup;
        }

        vru_cl->vruc_msg_bytes_read += ret;
        if (vru_cl->vruc_msg_bytes_read < VHOST_USER_HSIZE) {
            ret = 0;
            goto cleanup;
        }

        if (vru_cl->vruc_msg_bytes_read <
                (vru_cl->vruc_msg.size + VHOST_USER_HSIZE)) {
            ret = 0;
            goto cleanup;
        }
    }

    ret = vr_uvh_cl_call_handler(vru_cl);
    if (ret < 0) {
        vr_uvhost_log("Error handling message %d client %s\n",
                      vru_cl->vruc_msg.request, vru_cl->vruc_path);
        ret = -1;
        goto cleanup;
    }

    ret = vr_uvh_cl_send_reply(fd, vru_cl);
    if (ret < 0) {
        vr_uvhost_log("Error sending reply for message %d client %s\n",
                      vru_cl->vruc_msg.request, vru_cl->vruc_path);
        ret = -1;
        goto cleanup;
    }

cleanup:
    err = errno;
    /* close all the FDs received */
    for (i = 0; i < vru_cl->vruc_num_fds_sent; i++) {
        if (vru_cl->vruc_fds_sent[i] > 0)
            close(vru_cl->vruc_fds_sent[i]);
    }
    if (ret == -1) {
        /* set VQ_NOT_READY state to vif's queues. */
        for (i = 0; i < VR_DPDK_VIRTIO_MAX_QUEUES; i++) {
            vr_dpdk_virtio_rxqs[vru_cl->vruc_idx][i].vdv_ready_state = VQ_NOT_READY;
            vr_dpdk_virtio_txqs[vru_cl->vruc_idx][i].vdv_ready_state = VQ_NOT_READY;
        }
        rte_wmb();
        synchronize_rcu();
        /*
        * Unmaps qemu's FDs.
        */
        vr_dpdk_virtio_uvh_vif_munmap(&vr_dpdk_virtio_uvh_vif_mmap[vru_cl->vruc_idx]);
    }
    /* clear state for next message from this client. */
    vru_cl->vruc_msg_bytes_read = 0;
    memset(&vru_cl->vruc_msg, 0, sizeof(vru_cl->vruc_msg));
    memset(vru_cl->vruc_cmsg, 0, sizeof(vru_cl->vruc_cmsg));
    memset(vru_cl->vruc_fds_sent, 0, sizeof(vru_cl->vruc_fds_sent));
    vru_cl->vruc_num_fds_sent = 0;
    errno = err;
    return ret;
}