[dpdk-dev] vhost: add support for dynamic vhost PMD creation

Message ID 1462471869-4378-1-git-send-email-ferruh.yigit@intel.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Ferruh Yigit May 5, 2016, 6:11 p.m. UTC
  Add rte_eth_from_vhost() API to create vhost PMD dynamically from
applications.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---
 drivers/net/vhost/rte_eth_vhost.c           | 117 ++++++++++++++++++++++++++++
 drivers/net/vhost/rte_eth_vhost.h           |  19 +++++
 drivers/net/vhost/rte_pmd_vhost_version.map |   7 ++
 3 files changed, 143 insertions(+)
  

Comments

Yuanhan Liu May 9, 2016, 9:31 p.m. UTC | #1
On Thu, May 05, 2016 at 07:11:09PM +0100, Ferruh Yigit wrote:
> Add rte_eth_from_vhost() API to create vhost PMD dynamically from
> applications.

This sounds a good idea to me. It could be better if you name a good
usage of it though.

> 
> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> ---
>  drivers/net/vhost/rte_eth_vhost.c           | 117 ++++++++++++++++++++++++++++
>  drivers/net/vhost/rte_eth_vhost.h           |  19 +++++
>  drivers/net/vhost/rte_pmd_vhost_version.map |   7 ++
>  3 files changed, 143 insertions(+)
> 
> diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
> index 310cbef..c860ab8 100644
> --- a/drivers/net/vhost/rte_eth_vhost.c
> +++ b/drivers/net/vhost/rte_eth_vhost.c
> @@ -796,6 +796,123 @@ error:
>  	return -1;
>  }
>  
> +static int
> +rte_eth_from_vhost_create(const char *name, char *iface_name,

It's not a public function, so don't name it with prefix "rte_".

> +		const unsigned int numa_node, struct rte_mempool *mb_pool)
> +{
> +	struct rte_eth_dev_data *data = NULL;
> +	struct rte_eth_dev *eth_dev = NULL;
> +	struct pmd_internal *internal = NULL;
> +	struct internal_list *list;
> +	int nb_queues = 1;
> +	uint16_t nb_rx_queues = nb_queues;
> +	uint16_t nb_tx_queues = nb_queues;
> +	struct vhost_queue *vq;
> +	int i;
> +
> +	int port_id = eth_dev_vhost_create(name, iface_name, nb_queues,
> +			numa_node);
> +
> +	if (port_id < 0)
> +		return -1;
> +
> +	eth_dev = &rte_eth_devices[port_id];
> +	data = eth_dev->data;
> +	internal = data->dev_private;
> +	list = find_internal_resource(internal->iface_name);
> +
> +	data->rx_queues = rte_zmalloc_socket(name,
> +			sizeof(void *) * nb_rx_queues, 0, numa_node);
> +	if (data->rx_queues == NULL)
> +		goto error;
> +
> +	data->tx_queues = rte_zmalloc_socket(name,
> +			sizeof(void *) * nb_tx_queues, 0, numa_node);
> +	if (data->tx_queues == NULL)
> +		goto error;
> +
> +	for (i = 0; i < nb_rx_queues; i++) {
> +		vq = rte_zmalloc_socket(NULL, sizeof(struct vhost_queue),
> +				RTE_CACHE_LINE_SIZE, numa_node);
> +		if (vq == NULL) {
> +			RTE_LOG(ERR, PMD,
> +				"Failed to allocate memory for rx queue\n");
> +			goto error;
> +		}
> +		vq->mb_pool = mb_pool;
> +		vq->virtqueue_id = i * VIRTIO_QNUM + VIRTIO_TXQ;
> +		data->rx_queues[i] = vq;
> +	}

I would invoke eth_rx_queue_setup() here, to remove the duplicated
effort of queue allocation and initiation.

> +
> +	for (i = 0; i < nb_tx_queues; i++) {
> +		vq = rte_zmalloc_socket(NULL, sizeof(struct vhost_queue),
> +				RTE_CACHE_LINE_SIZE, numa_node);
> +		if (vq == NULL) {
> +			RTE_LOG(ERR, PMD,
> +				"Failed to allocate memory for tx queue\n");
> +			goto error;
> +		}
> +		vq->mb_pool = mb_pool;

Tx queue doesn't need a mbuf pool. And, ditto, call eth_tx_queue_setup()
instead.


> +int
> +rte_eth_from_vhost(const char *name, char *iface_name,
> +		const unsigned int numa_node, struct rte_mempool *mb_pool)

That would make this API be very limited. Assume we want to extend
vhost pmd in future, we could easily do that by adding few more
vdev options: you could reference my patch[0] to add client and
reconnect option. But here you hardcode all stuff that are needed
so far to create a vhost-pmd eth device; adding something new
would imply an API breakage in future.

So, let the vdev options as the argument of this API? That could
be friendly for future extension without breaking the API.

[0]: http://dpdk.org/dev/patchwork/patch/12608/

> +/**
> + * API to create vhost PMD
> + *
> + * @param name
> + *  Vhost device name
> + * @param iface_name
> + *  Vhost interface name
> + * @param numa_node
> + *  Socket id
> + * @param mb_pool
> + *  Memory pool
> + *
> + * @return
> + *  - On success, port_id.
> + *  - On failure, a negative value.
> + */

Hmmm, too simple.

	--yliu
  
Ferruh Yigit May 10, 2016, 5:11 p.m. UTC | #2
On 5/9/2016 10:31 PM, Yuanhan Liu wrote:
> On Thu, May 05, 2016 at 07:11:09PM +0100, Ferruh Yigit wrote:
>> Add rte_eth_from_vhost() API to create vhost PMD dynamically from
>> applications.
> 
> This sounds a good idea to me. It could be better if you name a good
> usage of it though.
> 
>>
>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>> ---
>>  drivers/net/vhost/rte_eth_vhost.c           | 117 ++++++++++++++++++++++++++++
>>  drivers/net/vhost/rte_eth_vhost.h           |  19 +++++
>>  drivers/net/vhost/rte_pmd_vhost_version.map |   7 ++
>>  3 files changed, 143 insertions(+)
>>
>> diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
>> index 310cbef..c860ab8 100644
>> --- a/drivers/net/vhost/rte_eth_vhost.c
>> +++ b/drivers/net/vhost/rte_eth_vhost.c
>> @@ -796,6 +796,123 @@ error:
>>  	return -1;
>>  }
>>  
>> +static int
>> +rte_eth_from_vhost_create(const char *name, char *iface_name,
> 
> It's not a public function, so don't name it with prefix "rte_".
> 
>> +		const unsigned int numa_node, struct rte_mempool *mb_pool)
>> +{
>> +	struct rte_eth_dev_data *data = NULL;
>> +	struct rte_eth_dev *eth_dev = NULL;
>> +	struct pmd_internal *internal = NULL;
>> +	struct internal_list *list;
>> +	int nb_queues = 1;
>> +	uint16_t nb_rx_queues = nb_queues;
>> +	uint16_t nb_tx_queues = nb_queues;
>> +	struct vhost_queue *vq;
>> +	int i;
>> +
>> +	int port_id = eth_dev_vhost_create(name, iface_name, nb_queues,
>> +			numa_node);
>> +
>> +	if (port_id < 0)
>> +		return -1;
>> +
>> +	eth_dev = &rte_eth_devices[port_id];
>> +	data = eth_dev->data;
>> +	internal = data->dev_private;
>> +	list = find_internal_resource(internal->iface_name);
>> +
>> +	data->rx_queues = rte_zmalloc_socket(name,
>> +			sizeof(void *) * nb_rx_queues, 0, numa_node);
>> +	if (data->rx_queues == NULL)
>> +		goto error;
>> +
>> +	data->tx_queues = rte_zmalloc_socket(name,
>> +			sizeof(void *) * nb_tx_queues, 0, numa_node);
>> +	if (data->tx_queues == NULL)
>> +		goto error;
>> +
>> +	for (i = 0; i < nb_rx_queues; i++) {
>> +		vq = rte_zmalloc_socket(NULL, sizeof(struct vhost_queue),
>> +				RTE_CACHE_LINE_SIZE, numa_node);
>> +		if (vq == NULL) {
>> +			RTE_LOG(ERR, PMD,
>> +				"Failed to allocate memory for rx queue\n");
>> +			goto error;
>> +		}
>> +		vq->mb_pool = mb_pool;
>> +		vq->virtqueue_id = i * VIRTIO_QNUM + VIRTIO_TXQ;
>> +		data->rx_queues[i] = vq;
>> +	}
> 
> I would invoke eth_rx_queue_setup() here, to remove the duplicated
> effort of queue allocation and initiation.
> 
>> +
>> +	for (i = 0; i < nb_tx_queues; i++) {
>> +		vq = rte_zmalloc_socket(NULL, sizeof(struct vhost_queue),
>> +				RTE_CACHE_LINE_SIZE, numa_node);
>> +		if (vq == NULL) {
>> +			RTE_LOG(ERR, PMD,
>> +				"Failed to allocate memory for tx queue\n");
>> +			goto error;
>> +		}
>> +		vq->mb_pool = mb_pool;
> 
> Tx queue doesn't need a mbuf pool. And, ditto, call eth_tx_queue_setup()
> instead.
> 
> 
>> +int
>> +rte_eth_from_vhost(const char *name, char *iface_name,
>> +		const unsigned int numa_node, struct rte_mempool *mb_pool)
> 
> That would make this API be very limited. Assume we want to extend
> vhost pmd in future, we could easily do that by adding few more
> vdev options: you could reference my patch[0] to add client and
> reconnect option. But here you hardcode all stuff that are needed
> so far to create a vhost-pmd eth device; adding something new
> would imply an API breakage in future.
> 
> So, let the vdev options as the argument of this API? That could
> be friendly for future extension without breaking the API.
> 
> [0]: http://dpdk.org/dev/patchwork/patch/12608/
> 
>> +/**
>> + * API to create vhost PMD
>> + *
>> + * @param name
>> + *  Vhost device name
>> + * @param iface_name
>> + *  Vhost interface name
>> + * @param numa_node
>> + *  Socket id
>> + * @param mb_pool
>> + *  Memory pool
>> + *
>> + * @return
>> + *  - On success, port_id.
>> + *  - On failure, a negative value.
>> + */
> 
> Hmmm, too simple.
> 
> 	--yliu
> 

Hi Yuanhan,

Thank you for the review, I will send new version of the patch with
above issues addressed.

Thanks,
ferruh
  

Patch

diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
index 310cbef..c860ab8 100644
--- a/drivers/net/vhost/rte_eth_vhost.c
+++ b/drivers/net/vhost/rte_eth_vhost.c
@@ -796,6 +796,123 @@  error:
 	return -1;
 }
 
+static int
+rte_eth_from_vhost_create(const char *name, char *iface_name,
+		const unsigned int numa_node, struct rte_mempool *mb_pool)
+{
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	struct pmd_internal *internal = NULL;
+	struct internal_list *list;
+	int nb_queues = 1;
+	uint16_t nb_rx_queues = nb_queues;
+	uint16_t nb_tx_queues = nb_queues;
+	struct vhost_queue *vq;
+	int i;
+
+	int port_id = eth_dev_vhost_create(name, iface_name, nb_queues,
+			numa_node);
+
+	if (port_id < 0)
+		return -1;
+
+	eth_dev = &rte_eth_devices[port_id];
+	data = eth_dev->data;
+	internal = data->dev_private;
+	list = find_internal_resource(internal->iface_name);
+
+	data->rx_queues = rte_zmalloc_socket(name,
+			sizeof(void *) * nb_rx_queues, 0, numa_node);
+	if (data->rx_queues == NULL)
+		goto error;
+
+	data->tx_queues = rte_zmalloc_socket(name,
+			sizeof(void *) * nb_tx_queues, 0, numa_node);
+	if (data->tx_queues == NULL)
+		goto error;
+
+	for (i = 0; i < nb_rx_queues; i++) {
+		vq = rte_zmalloc_socket(NULL, sizeof(struct vhost_queue),
+				RTE_CACHE_LINE_SIZE, numa_node);
+		if (vq == NULL) {
+			RTE_LOG(ERR, PMD,
+				"Failed to allocate memory for rx queue\n");
+			goto error;
+		}
+		vq->mb_pool = mb_pool;
+		vq->virtqueue_id = i * VIRTIO_QNUM + VIRTIO_TXQ;
+		data->rx_queues[i] = vq;
+	}
+
+	for (i = 0; i < nb_tx_queues; i++) {
+		vq = rte_zmalloc_socket(NULL, sizeof(struct vhost_queue),
+				RTE_CACHE_LINE_SIZE, numa_node);
+		if (vq == NULL) {
+			RTE_LOG(ERR, PMD,
+				"Failed to allocate memory for tx queue\n");
+			goto error;
+		}
+		vq->mb_pool = mb_pool;
+		vq->virtqueue_id = i * VIRTIO_QNUM + VIRTIO_RXQ;
+		data->tx_queues[i] = vq;
+	}
+
+	return port_id;
+
+error:
+	pthread_mutex_lock(&internal_list_lock);
+	TAILQ_REMOVE(&internal_list, list, next);
+	pthread_mutex_unlock(&internal_list_lock);
+
+	if (internal)
+		free(internal->dev_name);
+	free(vring_states[port_id]);
+	free(data->mac_addrs);
+	rte_eth_dev_release_port(eth_dev);
+	if (data->rx_queues) {
+		for (i = 0; i < nb_rx_queues; i++) {
+			vq = data->rx_queues[i];
+			free(vq);
+		}
+		rte_free(data->rx_queues);
+	}
+	if (data->tx_queues) {
+		for (i = 0; i < nb_tx_queues; i++) {
+			vq = data->tx_queues[i];
+			free(vq);
+		}
+		rte_free(data->tx_queues);
+	}
+	rte_free(internal);
+	rte_free(list);
+	rte_free(data);
+
+	return -1;
+}
+
+int
+rte_eth_from_vhost(const char *name, char *iface_name,
+		const unsigned int numa_node, struct rte_mempool *mb_pool)
+{
+	int port_id;
+	int ret;
+
+	port_id = rte_eth_from_vhost_create(name, iface_name, numa_node,
+			mb_pool);
+	if (port_id < 0)
+		return port_id;
+
+	ret = rte_vhost_driver_register(iface_name);
+	if (ret < 0)
+		return ret;
+
+	ret = vhost_driver_session_start();
+	if (ret < 0)
+		return ret;
+
+	return port_id;
+}
+
 static inline int
 open_iface(const char *key __rte_unused, const char *value, void *extra_args)
 {
diff --git a/drivers/net/vhost/rte_eth_vhost.h b/drivers/net/vhost/rte_eth_vhost.h
index ff5d877..624978c 100644
--- a/drivers/net/vhost/rte_eth_vhost.h
+++ b/drivers/net/vhost/rte_eth_vhost.h
@@ -102,6 +102,25 @@  struct rte_eth_vhost_queue_event {
 int rte_eth_vhost_get_queue_event(uint8_t port_id,
 		struct rte_eth_vhost_queue_event *event);
 
+/**
+ * API to create vhost PMD
+ *
+ * @param name
+ *  Vhost device name
+ * @param iface_name
+ *  Vhost interface name
+ * @param numa_node
+ *  Socket id
+ * @param mb_pool
+ *  Memory pool
+ *
+ * @return
+ *  - On success, port_id.
+ *  - On failure, a negative value.
+ */
+int rte_eth_from_vhost(const char *name, char *iface_name,
+		const unsigned int numa_node, struct rte_mempool *mb_pool);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/drivers/net/vhost/rte_pmd_vhost_version.map b/drivers/net/vhost/rte_pmd_vhost_version.map
index 65bf3a8..bb2fe29 100644
--- a/drivers/net/vhost/rte_pmd_vhost_version.map
+++ b/drivers/net/vhost/rte_pmd_vhost_version.map
@@ -8,3 +8,10 @@  DPDK_16.04 {
 
 	local: *;
 };
+
+DPDK_16.07 {
+	global:
+
+	rte_eth_from_vhost;
+
+} DPDK_16.04;