#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>
-#ifdef RTE_LIBRTE_VHOST_NUMA
-#include <numaif.h>
-#endif
#include <rte_mbuf.h>
#include <rte_ethdev.h>
#include <rte_memcpy.h>
#include <rte_vdev.h>
#include <rte_kvargs.h>
-#include <rte_virtio_net.h>
+#include <rte_vhost.h>
#include <rte_spinlock.h>
#include "rte_eth_vhost.h"
+enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM};
+
#define ETH_VHOST_IFACE_ARG "iface"
#define ETH_VHOST_QUEUES_ARG "queues"
#define ETH_VHOST_CLIENT_ARG "client"
#define ETH_VHOST_DEQUEUE_ZERO_COPY "dequeue-zero-copy"
-
-static const char *drivername = "VHOST PMD";
+#define VHOST_MAX_PKT_BURST 32
static const char *valid_arguments[] = {
ETH_VHOST_IFACE_ARG,
static pthread_mutex_t internal_list_lock = PTHREAD_MUTEX_INITIALIZER;
-static rte_atomic16_t nb_started_ports;
-static pthread_t session_th;
-
static struct rte_eth_link pmd_link = {
.link_speed = 10000,
.link_duplex = ETH_LINK_FULL_DUPLEX,
{
struct vhost_queue *r = q;
uint16_t i, nb_rx = 0;
+ uint16_t nb_receive = nb_bufs;
if (unlikely(rte_atomic32_read(&r->allow_queuing) == 0))
return 0;
goto out;
/* Dequeue packets from guest TX queue */
- nb_rx = rte_vhost_dequeue_burst(r->vid,
- r->virtqueue_id, r->mb_pool, bufs, nb_bufs);
+ while (nb_receive) {
+ uint16_t nb_pkts;
+ uint16_t num = (uint16_t)RTE_MIN(nb_receive,
+ VHOST_MAX_PKT_BURST);
+
+ nb_pkts = rte_vhost_dequeue_burst(r->vid, r->virtqueue_id,
+ r->mb_pool, &bufs[nb_rx],
+ num);
+
+ nb_rx += nb_pkts;
+ nb_receive -= nb_pkts;
+ if (nb_pkts < num)
+ break;
+ }
r->stats.pkts += nb_rx;
{
struct vhost_queue *r = q;
uint16_t i, nb_tx = 0;
+ uint16_t nb_send = nb_bufs;
if (unlikely(rte_atomic32_read(&r->allow_queuing) == 0))
return 0;
goto out;
/* Enqueue packets to guest RX queue */
- nb_tx = rte_vhost_enqueue_burst(r->vid,
- r->virtqueue_id, bufs, nb_bufs);
+ while (nb_send) {
+ uint16_t nb_pkts;
+ uint16_t num = (uint16_t)RTE_MIN(nb_send,
+ VHOST_MAX_PKT_BURST);
+
+ nb_pkts = rte_vhost_enqueue_burst(r->vid, r->virtqueue_id,
+ &bufs[nb_tx], num);
+
+ nb_tx += nb_pkts;
+ nb_send -= nb_pkts;
+ if (nb_pkts < num)
+ break;
+ }
r->stats.pkts += nb_tx;
r->stats.missed_pkts += nb_bufs - nb_tx;
vq->port = eth_dev->data->port_id;
}
- for (i = 0; i < rte_vhost_get_queue_num(vid) * VIRTIO_QNUM; i++)
+ for (i = 0; i < rte_vhost_get_vring_num(vid); i++)
rte_vhost_enable_guest_notification(vid, i, 0);
+ rte_vhost_get_mtu(vid, ð_dev->data->mtu);
+
eth_dev->data->dev_link.link_status = ETH_LINK_UP;
rte_atomic32_set(&internal->dev_attached, 1);
return 0;
}
+static struct vhost_device_ops vhost_ops = {
+ .new_device = new_device,
+ .destroy_device = destroy_device,
+ .vring_state_changed = vring_state_changed,
+};
+
int
rte_eth_vhost_get_queue_event(uint8_t port_id,
struct rte_eth_vhost_queue_event *event)
return vid;
}
-static void *
-vhost_driver_session(void *param __rte_unused)
-{
- static struct virtio_net_device_ops vhost_ops;
-
- /* set vhost arguments */
- vhost_ops.new_device = new_device;
- vhost_ops.destroy_device = destroy_device;
- vhost_ops.vring_state_changed = vring_state_changed;
- if (rte_vhost_driver_callback_register(&vhost_ops) < 0)
- RTE_LOG(ERR, PMD, "Can't register callbacks\n");
-
- /* start event handling */
- rte_vhost_driver_session_start();
-
- return NULL;
-}
-
-static int
-vhost_driver_session_start(void)
-{
- int ret;
-
- ret = pthread_create(&session_th,
- NULL, vhost_driver_session, NULL);
- if (ret)
- RTE_LOG(ERR, PMD, "Can't create a thread\n");
-
- return ret;
-}
-
-static void
-vhost_driver_session_stop(void)
-{
- int ret;
-
- ret = pthread_cancel(session_th);
- if (ret)
- RTE_LOG(ERR, PMD, "Can't cancel the thread\n");
-
- ret = pthread_join(session_th, NULL);
- if (ret)
- RTE_LOG(ERR, PMD, "Can't join the thread\n");
-}
-
static int
eth_dev_start(struct rte_eth_dev *dev)
{
update_queuing_status(dev);
}
+static void
+eth_dev_close(struct rte_eth_dev *dev)
+{
+ struct pmd_internal *internal;
+ struct internal_list *list;
+
+ internal = dev->data->dev_private;
+ if (!internal)
+ return;
+
+ rte_vhost_driver_unregister(internal->iface_name);
+
+ list = find_internal_resource(internal->iface_name);
+ if (!list)
+ return;
+
+ pthread_mutex_lock(&internal_list_lock);
+ TAILQ_REMOVE(&internal_list, list, next);
+ pthread_mutex_unlock(&internal_list_lock);
+ rte_free(list);
+
+ free(internal->dev_name);
+ free(internal->iface_name);
+ rte_free(internal);
+}
+
static int
eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
uint16_t nb_rx_desc __rte_unused,
return;
}
- dev_info->driver_name = drivername;
dev_info->max_mac_addrs = 1;
dev_info->max_rx_pktlen = (uint32_t)-1;
dev_info->max_rx_queues = internal->max_queues;
}
static int
-eth_link_update(struct rte_eth_dev *dev __rte_unused,
- int wait_to_complete __rte_unused)
+eth_tx_done_cleanup(void *txq __rte_unused, uint32_t free_cnt __rte_unused)
{
+ /*
+ * vHost does not hang onto mbuf. eth_vhost_tx() copies packet data
+ * and releases mbuf, so nothing to cleanup.
+ */
return 0;
}
-/**
- * Disable features in feature_mask. Returns 0 on success.
- */
-int
-rte_eth_vhost_feature_disable(uint64_t feature_mask)
-{
- return rte_vhost_feature_disable(feature_mask);
-}
-
-/**
- * Enable features in feature_mask. Returns 0 on success.
- */
-int
-rte_eth_vhost_feature_enable(uint64_t feature_mask)
-{
- return rte_vhost_feature_enable(feature_mask);
-}
-
-/* Returns currently supported vhost features */
-uint64_t
-rte_eth_vhost_feature_get(void)
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+ int wait_to_complete __rte_unused)
{
- return rte_vhost_feature_get();
+ return 0;
}
static const struct eth_dev_ops ops = {
.dev_start = eth_dev_start,
.dev_stop = eth_dev_stop,
+ .dev_close = eth_dev_close,
.dev_configure = eth_dev_configure,
.dev_infos_get = eth_dev_info,
.rx_queue_setup = eth_rx_queue_setup,
.tx_queue_setup = eth_tx_queue_setup,
.rx_queue_release = eth_queue_release,
.tx_queue_release = eth_queue_release,
+ .tx_done_cleanup = eth_tx_done_cleanup,
.link_update = eth_link_update,
.stats_get = eth_stats_get,
.stats_reset = eth_stats_reset,
.xstats_get_names = vhost_dev_xstats_get_names,
};
+static struct rte_vdev_driver pmd_vhost_drv;
+
static int
eth_dev_vhost_create(const char *name, char *iface_name, int16_t queues,
const unsigned numa_node, uint64_t flags)
data->dev_flags =
RTE_ETH_DEV_DETACHABLE | RTE_ETH_DEV_INTR_LSC;
data->kdrv = RTE_KDRV_NONE;
- data->drv_name = internal->dev_name;
+ data->drv_name = pmd_vhost_drv.driver.name;
data->numa_node = numa_node;
/* finally assign rx and tx ops */
if (rte_vhost_driver_register(iface_name, flags))
goto error;
- /* We need only one message handling thread */
- if (rte_atomic16_add_return(&nb_started_ports, 1) == 1) {
- if (vhost_driver_session_start())
- goto error;
+ if (rte_vhost_driver_callback_register(iface_name, &vhost_ops) < 0) {
+ RTE_LOG(ERR, PMD, "Can't register callbacks\n");
+ goto error;
+ }
+
+ if (rte_vhost_driver_start(iface_name) < 0) {
+ RTE_LOG(ERR, PMD, "Failed to start driver for %s\n",
+ iface_name);
+ goto error;
}
return data->port_id;
}
static int
-rte_pmd_vhost_probe(const char *name, const char *params)
+rte_pmd_vhost_probe(struct rte_vdev_device *dev)
{
+ const char *name;
struct rte_kvargs *kvlist = NULL;
int ret = 0;
char *iface_name;
int client_mode = 0;
int dequeue_zero_copy = 0;
+ name = rte_vdev_device_name(dev);
RTE_LOG(INFO, PMD, "Initializing pmd_vhost for %s\n", name);
- kvlist = rte_kvargs_parse(params, valid_arguments);
+ kvlist = rte_kvargs_parse(rte_vdev_device_args(dev), valid_arguments);
if (kvlist == NULL)
return -1;
}
static int
-rte_pmd_vhost_remove(const char *name)
+rte_pmd_vhost_remove(struct rte_vdev_device *dev)
{
+ const char *name;
struct rte_eth_dev *eth_dev = NULL;
- struct pmd_internal *internal;
- struct internal_list *list;
unsigned int i;
+ name = rte_vdev_device_name(dev);
RTE_LOG(INFO, PMD, "Un-Initializing pmd_vhost for %s\n", name);
/* find an ethdev entry */
if (eth_dev == NULL)
return -ENODEV;
- internal = eth_dev->data->dev_private;
- if (internal == NULL)
- return -ENODEV;
-
- list = find_internal_resource(internal->iface_name);
- if (list == NULL)
- return -ENODEV;
-
- pthread_mutex_lock(&internal_list_lock);
- TAILQ_REMOVE(&internal_list, list, next);
- pthread_mutex_unlock(&internal_list_lock);
- rte_free(list);
-
eth_dev_stop(eth_dev);
- rte_vhost_driver_unregister(internal->iface_name);
-
- if (rte_atomic16_sub_return(&nb_started_ports, 1) == 0)
- vhost_driver_session_stop();
+ eth_dev_close(eth_dev);
rte_free(vring_states[eth_dev->data->port_id]);
vring_states[eth_dev->data->port_id] = NULL;
- free(internal->dev_name);
- free(internal->iface_name);
-
for (i = 0; i < eth_dev->data->nb_rx_queues; i++)
rte_free(eth_dev->data->rx_queues[i]);
for (i = 0; i < eth_dev->data->nb_tx_queues; i++)
rte_free(eth_dev->data->mac_addrs);
rte_free(eth_dev->data);
- rte_free(internal);
rte_eth_dev_release_port(eth_dev);