net/virtio-user: add multiple queues in device emulation

The main purpose of this patch is to enable multi-queue. But
multi-queue requires ctrl-queue so that driver can send how many
queues will be enabled through ctrl-queue messages.

So we partially implement ctrl-queue to handle control command
with class of VIRTIO_NET_CTRL_MQ and with cmd of
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET to handle mq support. This patch
provides a function, virtio_user_handle_cq(), for driver to handle
ctrl-queue messages.

Besides, multi-queue requires VIRTIO_NET_F_MQ and VIRTIO_NET_F_CTRL_VQ
are enabled when we do feature negotiation.

Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
This commit is contained in:
Jianfeng Tan 2016-06-15 17:38:36 +08:00 committed by Yuanhan Liu
parent 0b6df936c8
commit f9b9d1a557
2 changed files with 116 additions and 9 deletions

View File

@ -131,11 +131,14 @@ virtio_user_start_device(struct virtio_user_dev *dev)
}
}
/* After setup all virtqueues, we need to set_features so that
* these features can be set into each virtqueue in vhost side.
* And before that, make sure VIRTIO_NET_F_MAC is stripped.
/* After setup all virtqueues, we need to set_features so that these
* features can be set into each virtqueue in vhost side. And before
* that, make sure VHOST_USER_F_PROTOCOL_FEATURES is added if mq is
* enabled, and VIRTIO_NET_F_MAC is stripped.
*/
features = dev->features;
if (dev->max_queue_pairs > 1)
features |= VHOST_USER_MQ;
features &= ~(1ull << VIRTIO_NET_F_MAC);
ret = vhost_user_sock(dev->vhostfd, VHOST_USER_SET_FEATURES, &features);
if (ret < 0)
@ -185,8 +188,6 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues,
dev->mac_specified = 0;
parse_mac(dev, mac);
dev->vhostfd = -1;
/* TODO: cq */
RTE_SET_USED(cq);
dev->vhostfd = vhost_user_setup(dev->path);
if (dev->vhostfd < 0) {
@ -205,9 +206,31 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues,
}
if (dev->mac_specified)
dev->features |= (1ull << VIRTIO_NET_F_MAC);
/* disable it until we support CQ */
dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_VQ);
dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_RX);
if (!cq) {
dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_VQ);
/* Also disable features depends on VIRTIO_NET_F_CTRL_VQ */
dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_RX);
dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_VLAN);
dev->features &= ~(1ull << VIRTIO_NET_F_GUEST_ANNOUNCE);
dev->features &= ~(1ull << VIRTIO_NET_F_MQ);
dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_MAC_ADDR);
} else {
/* vhost user backend does not need to know ctrl-q, so
* actually we need add this bit into features. However,
* DPDK vhost-user does send features with this bit, so we
* check it instead of OR it for now.
*/
if (!(dev->features & (1ull << VIRTIO_NET_F_CTRL_VQ)))
PMD_INIT_LOG(INFO, "vhost does not support ctrl-q");
}
if (dev->max_queue_pairs > 1) {
if (!(dev->features & VHOST_USER_MQ)) {
PMD_INIT_LOG(ERR, "MQ not supported by the backend");
return -1;
}
}
return 0;
}
@ -224,3 +247,87 @@ virtio_user_dev_uninit(struct virtio_user_dev *dev)
close(dev->vhostfd);
}
static uint8_t
virtio_user_handle_mq(struct virtio_user_dev *dev, uint16_t q_pairs)
{
uint16_t i;
uint8_t ret = 0;
if (q_pairs > dev->max_queue_pairs) {
PMD_INIT_LOG(ERR, "multi-q config %u, but only %u supported",
q_pairs, dev->max_queue_pairs);
return -1;
}
for (i = 0; i < q_pairs; ++i)
ret |= vhost_user_enable_queue_pair(dev->vhostfd, i, 1);
for (i = q_pairs; i < dev->max_queue_pairs; ++i)
ret |= vhost_user_enable_queue_pair(dev->vhostfd, i, 0);
dev->queue_pairs = q_pairs;
return ret;
}
static uint32_t
virtio_user_handle_ctrl_msg(struct virtio_user_dev *dev, struct vring *vring,
uint16_t idx_hdr)
{
struct virtio_net_ctrl_hdr *hdr;
virtio_net_ctrl_ack status = ~0;
uint16_t i, idx_data, idx_status;
uint32_t n_descs = 0;
/* locate desc for header, data, and status */
idx_data = vring->desc[idx_hdr].next;
n_descs++;
i = idx_data;
while (vring->desc[i].flags == VRING_DESC_F_NEXT) {
i = vring->desc[i].next;
n_descs++;
}
/* locate desc for status */
idx_status = i;
n_descs++;
hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr;
if (hdr->class == VIRTIO_NET_CTRL_MQ &&
hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
uint16_t queues;
queues = *(uint16_t *)(uintptr_t)vring->desc[idx_data].addr;
status = virtio_user_handle_mq(dev, queues);
}
/* Update status */
*(virtio_net_ctrl_ack *)(uintptr_t)vring->desc[idx_status].addr = status;
return n_descs;
}
void
virtio_user_handle_cq(struct virtio_user_dev *dev, uint16_t queue_idx)
{
uint16_t avail_idx, desc_idx;
struct vring_used_elem *uep;
uint32_t n_descs;
struct vring *vring = &dev->vrings[queue_idx];
/* Consume avail ring, using used ring idx as first one */
while (vring->used->idx != vring->avail->idx) {
avail_idx = (vring->used->idx) & (vring->num - 1);
desc_idx = vring->avail->ring[avail_idx];
n_descs = virtio_user_handle_ctrl_msg(dev, vring, desc_idx);
/* Update used ring */
uep = &vring->used->ring[avail_idx];
uep->id = avail_idx;
uep->len = n_descs;
vring->used->idx++;
}
}

View File

@ -58,5 +58,5 @@ int virtio_user_stop_device(struct virtio_user_dev *dev);
int virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues,
int cq, int queue_size, const char *mac);
void virtio_user_dev_uninit(struct virtio_user_dev *dev);
void virtio_user_handle_cq(struct virtio_user_dev *dev, uint16_t queue_idx);
#endif