Skip to contentSkip to conversation

virtio patches

RFC In review Stephen Hemminger 2 participants 19 messages Aug 26, 2014 – Aug 27, 2014 7 messages not in the archive

lore
Share & tools
lore
#0 lore raw

cover virtio patches

These are untested patches to merge functionality from Brocade/vyatta DPDK virtio driver back into the Intel DPDK 1.7 driver. Use them and merge them if you want. But test first, these are compile tested only.

#1 lore raw

RFC 1/10 virtio: rearrange resource initialization

For clarity make the setup of PCI resources for Linux into a function rather than block of code #ifdef'd in middle of dev_init.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |   76 +++++++++++++++++++---------------
 1 file changed, 43 insertions(+), 33 deletions(-)
lib/librte_pmd_virtio/virtio_ethdev.c +43 -33
@@ -706,6 +706,41 @@ virtio_has_msix(const struct rte_pci_add
 
 	return (d != NULL);
 }
+
+/* Extract I/O port numbers from sysfs */
+static int virtio_resource_init(struct rte_pci_device *pci_dev)
+{
+	char dirname[PATH_MAX];
+	char filename[PATH_MAX];
+	unsigned long start, size;
+
+	if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname)) < 0)
+		return -1;
+
+	/* get portio size */
+	snprintf(filename, sizeof(filename),
+		     "%s/portio/port0/size", dirname);
+	if (parse_sysfs_value(filename, &size) < 0) {
+		PMD_INIT_LOG(ERR, "%s(): cannot parse size",
+			     __func__);
+		return -1;
+	}
+
+	/* get portio start */
+	snprintf(filename, sizeof(filename),
+		 "%s/portio/port0/start", dirname);
+	if (parse_sysfs_value(filename, &start) < 0) {
+		PMD_INIT_LOG(ERR, "%s(): cannot parse portio start",
+			     __func__);
+		return -1;
+	}
+	pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start;
+	pci_dev->mem_resource[0].len =  (uint64_t)size;
+	PMD_INIT_LOG(DEBUG,
+		     "PCI Port IO found start=0x%lx with size=0x%lx",
+		     start, size);
+	return 0;
+}
 #else
 static int
 virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
@@ -713,6 +748,12 @@ virtio_has_msix(const struct rte_pci_add
 	/* nic_uio does not enable interrupts, return 0 (false). */
 	return 0;
 }
+
+static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
+{
+	/* no setup required */
+	return 0;
+}
 #endif
 
 /*
@@ -749,40 +790,9 @@ eth_virtio_dev_init(__rte_unused struct
 		return 0;
 
 	pci_dev = eth_dev->pci_dev;
+	if (virtio_resource_init(pci_dev) < 0)
+		return -1;
 
-#ifdef RTE_EXEC_ENV_LINUXAPP
-	{
-		char dirname[PATH_MAX];
-		char filename[PATH_MAX];
-		unsigned long start, size;
-
-		if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname)) < 0)
-			return -1;
-
-		/* get portio size */
-		snprintf(filename, sizeof(filename),
-			     "%s/portio/port0/size", dirname);
-		if (parse_sysfs_value(filename, &size) < 0) {
-			PMD_INIT_LOG(ERR, "%s(): cannot parse size",
-				     __func__);
-			return -1;
-		}
-
-		/* get portio start */
-		snprintf(filename, sizeof(filename),
-			     "%s/portio/port0/start", dirname);
-		if (parse_sysfs_value(filename, &start) < 0) {
-			PMD_INIT_LOG(ERR, "%s(): cannot parse portio start",
-				     __func__);
-			return -1;
-		}
-		pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start;
-		pci_dev->mem_resource[0].len =  (uint64_t)size;
-		PMD_INIT_LOG(DEBUG,
-			     "PCI Port IO found start=0x%lx with size=0x%lx",
-			     start, size);
-	}
-#endif
 	hw->use_msix = virtio_has_msix(&pci_dev->addr);
 	hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr;
 

A message that is not in the archive (sent off-list or not yet received): 20140826020837.898427212-OTpzqLSitTUnbdJkjeBofR2eb7JE58TQ@public.gmane.org

Acked-by Changchun Ouyang
#3 lore raw

Re: [RFC 01/10] virtio: rearrange resource initialization

Quoted 119 lines

-----Original Message-----
From: Stephen Hemminger [mailto:[email protected]]
Sent: Tuesday, August 26, 2014 10:08 AM
To: Ouyang, Changchun
Cc: [email protected]
Subject: [RFC 01/10] virtio: rearrange resource initialization

For clarity make the setup of PCI resources for Linux into a function rather than block of code #ifdef'd in middle of dev_init.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |   76 +++++++++++++++++++----------
-----
 1 file changed, 43 insertions(+), 33 deletions(-)

--- a/lib/librte_pmd_virtio/virtio_ethdev.c 2014-08-25
19:00:03.622515574 -0700
+++ b/lib/librte_pmd_virtio/virtio_ethdev.c 2014-08-25
19:00:03.622515574 -0700

lib/librte_pmd_virtio/virtio_ethdev.c +35 -0
@@ -706,6 +706,41 @@ virtio_has_msix(const struct rte_pci_add
 
 	return (d != NULL);
 }
+
+/* Extract I/O port numbers from sysfs */ static int
+virtio_resource_init(struct rte_pci_device *pci_dev) {
+	char dirname[PATH_MAX];
+	char filename[PATH_MAX];
+	unsigned long start, size;
+
+	if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname)) < 0)
+		return -1;
+
+	/* get portio size */
+	snprintf(filename, sizeof(filename),
+		     "%s/portio/port0/size", dirname);
+	if (parse_sysfs_value(filename, &size) < 0) {
+		PMD_INIT_LOG(ERR, "%s(): cannot parse size",
+			     __func__);
+		return -1;
+	}
+
+	/* get portio start */
+	snprintf(filename, sizeof(filename),
+		 "%s/portio/port0/start", dirname);
+	if (parse_sysfs_value(filename, &start) < 0) {
+		PMD_INIT_LOG(ERR, "%s(): cannot parse portio start",
+			     __func__);
+		return -1;
+	}
+	pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start;
+	pci_dev->mem_resource[0].len =  (uint64_t)size;
+	PMD_INIT_LOG(DEBUG,
+		     "PCI Port IO found start=0x%lx with size=0x%lx",
+		     start, size);
+	return 0;
+}
 #else
 static int
 virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) @@ -713,6
+748,12 @@ virtio_has_msix(const struct rte_pci_add
lib/librte_pmd_virtio/virtio_ethdev.c +8 -33
 	/* nic_uio does not enable interrupts, return 0 (false). */
 	return 0;
 }
+
+static int virtio_resource_init(struct rte_pci_device *pci_dev
+__rte_unused) {
+	/* no setup required */
+	return 0;
+}
 #endif
 
 /*
@@ -749,40 +790,9 @@ eth_virtio_dev_init(__rte_unused struct
 		return 0;
 
 	pci_dev = eth_dev->pci_dev;
+	if (virtio_resource_init(pci_dev) < 0)
+		return -1;
 
-#ifdef RTE_EXEC_ENV_LINUXAPP
-	{
-		char dirname[PATH_MAX];
-		char filename[PATH_MAX];
-		unsigned long start, size;
-
-		if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname))
 < 0)
-			return -1;
-
-		/* get portio size */
-		snprintf(filename, sizeof(filename),
-			     "%s/portio/port0/size", dirname);
-		if (parse_sysfs_value(filename, &size) < 0) {
-			PMD_INIT_LOG(ERR, "%s(): cannot parse size",
-				     __func__);
-			return -1;
-		}
-
-		/* get portio start */
-		snprintf(filename, sizeof(filename),
-			     "%s/portio/port0/start", dirname);
-		if (parse_sysfs_value(filename, &start) < 0) {
-			PMD_INIT_LOG(ERR, "%s(): cannot parse portio
 start",
-				     __func__);
-			return -1;
-		}
-		pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start;
-		pci_dev->mem_resource[0].len =  (uint64_t)size;
-		PMD_INIT_LOG(DEBUG,
-			     "PCI Port IO found start=0x%lx with size=0x%lx",
-			     start, size);
-	}
-#endif
 	hw->use_msix = virtio_has_msix(&pci_dev->addr);

hw->io_base = (uint32_t)(uintptr_t)pci_dev-

Quoted 1 line

mem_resource[0].addr;

#4 lore raw

RFC 2/10 virtio: use weak barriers

In reply to Stephen Hemminger

The DPDK driver only has to deal with the case of running on PCI and with SMP. In this case, the code can use the weaker barriers instead of using hard (fence) barriers. This will help performance. The rationale is explained in Linux kernel virtio_ring.h.

To make it clearer that this is a virtio thing and not some generic barrier, prefix the barrier calls with virtio_.

Add missing (and needed) barrier between updating ring data structure and notifying host.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |    2 +-
 lib/librte_pmd_virtio/virtio_rxtx.c   |    8 +++++---
 lib/librte_pmd_virtio/virtqueue.h     |   19 ++++++++++++++-----
 3 files changed, 20 insertions(+), 9 deletions(-)
lib/librte_pmd_virtio/virtio_rxtx.c +5 -3
@@ -454,7 +454,7 @@ virtio_recv_pkts(void *rx_queue, struct
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
-	rmb();
+	virtio_rmb();
 
 	num = (uint16_t)(likely(nb_used <= nb_pkts) ? nb_used : nb_pkts);
 	num = (uint16_t)(likely(num <= VIRTIO_MBUF_BURST_SZ) ? num : VIRTIO_MBUF_BURST_SZ);
@@ -514,6 +514,7 @@ virtio_recv_pkts(void *rx_queue, struct
 	}
 
 	if (likely(nb_enqueued)) {
+		virtio_wmb();
 		if (unlikely(virtqueue_kick_prepare(rxvq))) {
 			virtqueue_notify(rxvq);
 			PMD_RX_LOG(DEBUG, "Notified\n");
@@ -545,7 +546,7 @@ virtio_recv_mergeable_pkts(void *rx_queu
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
-	rmb();
+	virtio_rmb();
 
 	if (nb_used == 0)
 		return 0;
@@ -694,7 +695,7 @@ virtio_xmit_pkts(void *tx_queue, struct
 	PMD_TX_LOG(DEBUG, "%d packets to xmit", nb_pkts);
 	nb_used = VIRTQUEUE_NUSED(txvq);
 
-	rmb();
+	virtio_rmb();
 
 	num = (uint16_t)(likely(nb_used < VIRTIO_MBUF_BURST_SZ) ? nb_used : VIRTIO_MBUF_BURST_SZ);
 
@@ -729,6 +730,7 @@ virtio_xmit_pkts(void *tx_queue, struct
 		}
 	}
 	vq_update_avail_idx(txvq);
+	virtio_wmb();
 
 	txvq->packets += nb_tx;
 
lib/librte_pmd_virtio/virtqueue.h +14 -5
@@ -46,9 +46,18 @@
 #include "virtio_ring.h"
 #include "virtio_logs.h"
 
-#define mb()  rte_mb()
-#define wmb() rte_wmb()
-#define rmb() rte_rmb()
+/*
+ * Per virtio_config.h in Linux.
+ *     For virtio_pci on SMP, we don't need to order with respect to MMIO
+ *     accesses through relaxed memory I/O windows, so smp_mb() et al are
+ *     sufficient.
+ *
+ * This driver is for virtio_pci on SMP and therefore can assume
+ * weaker (compiler barriers)
+ */
+#define virtio_mb()	rte_mb()
+#define virtio_rmb()	rte_compiler_barrier()
+#define virtio_wmb()	rte_compiler_barrier()
 
 #ifdef RTE_PMD_PACKET_PREFETCH
 #define rte_packet_prefetch(p)  rte_prefetch1(p)
@@ -226,7 +235,7 @@ virtqueue_full(const struct virtqueue *v
 static inline void
 vq_update_avail_idx(struct virtqueue *vq)
 {
-	rte_compiler_barrier();
+	virtio_rmb();
 	vq->vq_ring.avail->idx = vq->vq_avail_idx;
 }
 
@@ -256,7 +265,7 @@ static inline void
 virtqueue_notify(struct virtqueue *vq)
 {
 	/*
-	 * Ensure updated avail->idx is visible to host. mb() necessary?
+	 * Ensure updated avail->idx is visible to host.
 	 * For virtio on IA, the notificaiton is through io port operation
 	 * which is a serialization instruction itself.
 	 */
lib/librte_pmd_virtio/virtio_ethdev.c +1 -1
@@ -171,7 +171,7 @@ virtio_send_command(struct virtqueue *vq
 		uint32_t idx, desc_idx, used_idx;
 		struct vring_used_elem *uep;
 
-		rmb();
+		virtio_rmb();
 
 		used_idx = (uint32_t)(vq->vq_used_cons_idx
 				& (vq->vq_nentries - 1));
#5 lore raw

RFC 3/10 virtio: allow starting with link down

In reply to Stephen Hemminger

Starting driver with link down should be ok, it is with every other driver. So just allow it.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |    6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
lib/librte_pmd_virtio/virtio_ethdev.c +2 -4
@@ -969,14 +969,12 @@ virtio_dev_start(struct rte_eth_dev *dev
 		vtpci_read_dev_config(hw,
 				offsetof(struct virtio_net_config, status),
 				&status, sizeof(status));
-		if ((status & VIRTIO_NET_S_LINK_UP) == 0) {
+		if ((status & VIRTIO_NET_S_LINK_UP) == 0)
 			PMD_INIT_LOG(ERR, "Port: %d Link is DOWN",
 				     dev->data->port_id);
-			return -EIO;
-		} else {
+		else
 			PMD_INIT_LOG(DEBUG, "Port: %d Link is UP",
 				     dev->data->port_id);
-		}
 	}
 	vtpci_reinit_complete(hw);
 
#6 lore raw

RFC 4/10 virtio: add support for Link State interrupt

In reply to Stephen Hemminger

Virtio has link state interrupt which can be used.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |   78 ++++++++++++++++++++++++++--------
 lib/librte_pmd_virtio/virtio_pci.c    |   22 +++++++++
 lib/librte_pmd_virtio/virtio_pci.h    |    4 +
 3 files changed, 86 insertions(+), 18 deletions(-)
lib/librte_pmd_virtio/virtio_ethdev.c +60 -18
@@ -757,6 +757,34 @@ static int virtio_resource_init(struct r
 #endif
 
 /*
+ * Process Virtio Config changed interrupt and call the callback
+ * if link state changed.
+ */
+static void
+virtio_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
+			 void *param)
+{
+	struct rte_eth_dev *dev = param;
+	struct virtio_hw *hw =
+		VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint8_t isr;
+
+	/* Read interrupt status which clears interrupt */
+	isr = vtpci_isr(hw);
+	PMD_DRV_LOG(INFO, "interrupt status = %#x", isr);
+
+	if (rte_intr_enable(&dev->pci_dev->intr_handle) < 0)
+		PMD_DRV_LOG(ERR, "interrupt enable failed");
+
+	if (isr & VIRTIO_PCI_ISR_CONFIG) {
+		if (virtio_dev_link_update(dev, 0) == 0)
+			_rte_eth_dev_callback_process(dev,
+						      RTE_ETH_EVENT_INTR_LSC);
+	}
+
+}
+
+/*
  * This function is based on probe() function in virtio_pci.c
  * It returns 0 on success.
  */
@@ -886,6 +914,10 @@ eth_virtio_dev_init(__rte_unused struct
 	PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x",
 			eth_dev->data->port_id, pci_dev->id.vendor_id,
 			pci_dev->id.device_id);
+
+	/* Setup interrupt callback  */
+	rte_intr_callback_register(&pci_dev->intr_handle,
+				   virtio_interrupt_handler, eth_dev);
 	return 0;
 }
 
@@ -893,7 +925,7 @@ static struct eth_driver rte_virtio_pmd
 	{
 		.name = "rte_virtio_pmd",
 		.id_table = pci_id_virtio_map,
-		.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	},
 	.eth_dev_init = eth_virtio_dev_init,
 	.dev_private_size = sizeof(struct virtio_adapter),
@@ -933,6 +965,9 @@ static int
 virtio_dev_configure(struct rte_eth_dev *dev)
 {
 	const struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
+	struct virtio_hw *hw =
+		VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret;
 
 	PMD_INIT_LOG(DEBUG, "configure");
 
@@ -941,7 +976,11 @@ virtio_dev_configure(struct rte_eth_dev
 		return (-EINVAL);
 	}
 
-	return 0;
+	ret = vtpci_irq_config(hw, 0);
+	if (ret != 0)
+		PMD_DRV_LOG(ERR, "failed to set config vector");
+
+	return ret;
 }
 
 
@@ -949,7 +988,6 @@ static int
 virtio_dev_start(struct rte_eth_dev *dev)
 {
 	uint16_t nb_queues, i;
-	uint16_t status;
 	struct virtio_hw *hw =
 		VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
@@ -964,18 +1002,22 @@ virtio_dev_start(struct rte_eth_dev *dev
 	/* Do final configuration before rx/tx engine starts */
 	virtio_dev_rxtx_start(dev);
 
-	/* Check VIRTIO_NET_F_STATUS for link status*/
-	if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) {
-		vtpci_read_dev_config(hw,
-				offsetof(struct virtio_net_config, status),
-				&status, sizeof(status));
-		if ((status & VIRTIO_NET_S_LINK_UP) == 0)
-			PMD_INIT_LOG(ERR, "Port: %d Link is DOWN",
-				     dev->data->port_id);
-		else
-			PMD_INIT_LOG(DEBUG, "Port: %d Link is UP",
-				     dev->data->port_id);
+	/* check if lsc interrupt feature is enabled */
+	if (dev->data->dev_conf.intr_conf.lsc) {
+		if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) {
+			PMD_DRV_LOG(ERR, "link status not supported by host");
+			return -ENOTSUP;
+		}
+
+		if (rte_intr_enable(&dev->pci_dev->intr_handle) < 0) {
+			PMD_DRV_LOG(ERR, "interrupt enable failed");
+			return -EIO;
+		}
 	}
+
+	/* Initialize Link state */
+	virtio_dev_link_update(dev, 0);
+
 	vtpci_reinit_complete(hw);
 
 	/*Notify the backend
@@ -1057,6 +1099,7 @@ virtio_dev_stop(struct rte_eth_dev *dev)
 		VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
 	/* reset the NIC */
+	vtpci_irq_config(hw, 0);
 	vtpci_reset(hw);
 	virtio_dev_free_mbufs(dev);
 }
@@ -1073,6 +1116,7 @@ virtio_dev_link_update(struct rte_eth_de
 	old = link;
 	link.link_duplex = FULL_DUPLEX;
 	link.link_speed  = SPEED_10G;
+
 	if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) {
 		PMD_INIT_LOG(DEBUG, "Get link status from hw");
 		vtpci_read_dev_config(hw,
@@ -1091,10 +1135,8 @@ virtio_dev_link_update(struct rte_eth_de
 		link.link_status = 1;   /* Link up */
 	}
 	virtio_dev_atomic_write_link_status(dev, &link);
-	if (old.link_status == link.link_status)
-		return -1;
-	/*changed*/
-	return 0;
+
+	return (old.link_status == link.link_status) ? -1 : 0;
 }
 
 static void
lib/librte_pmd_virtio/virtio_pci.c +22 -0
@@ -127,3 +127,25 @@ vtpci_set_status(struct virtio_hw *hw, u
 
 	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
 }
+
+uint8_t
+vtpci_isr(struct virtio_hw *hw)
+{
+
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+}
+
+
+/* Enable one vector (0) for Link State Intrerrupt */
+int
+vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
+{
+	VIRTIO_WRITE_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR, vec);
+	vec = VIRTIO_READ_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR);
+	if (vec == VIRTIO_MSI_NO_VECTOR) {
+		PMD_DRV_LOG(ERR, "failed to set config vector");
+		return -EBUSY;
+	}
+
+	return 0;
+}
lib/librte_pmd_virtio/virtio_pci.h +4 -0
@@ -263,4 +263,8 @@ void vtpci_write_dev_config(struct virti
 
 void vtpci_read_dev_config(struct virtio_hw *, uint64_t, void *, int);
 
+uint8_t vtpci_isr(struct virtio_hw *);
+
+int vtpci_irq_config(struct virtio_hw *, uint16_t);
+
 #endif /* _VIRTIO_PCI_H_ */
#7 lore raw

RFC 5/10 ether: add soft vlan encap/decap functions

In reply to Stephen Hemminger

It is helpful to allow device drivers that don't support hardware VLAN stripping to emulate this in software.

---
 lib/librte_ether/rte_ether.h |   69 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
lib/librte_ether/rte_ether.h +69 -0
@@ -48,6 +48,8 @@ extern "C" {
 
 #include <rte_memcpy.h>
 #include <rte_random.h>
+#include <rte_mbuf.h>
+#include <rte_byteorder.h>
 
 #define ETHER_ADDR_LEN  6 /**< Length of Ethernet address. */
 #define ETHER_TYPE_LEN  2 /**< Length of Ethernet type field. */
@@ -294,6 +296,73 @@ struct vlan_hdr {
 #define ETHER_TYPE_VLAN 0x8100 /**< IEEE 802.1Q VLAN tagging. */
 #define ETHER_TYPE_1588 0x88F7 /**< IEEE 802.1AS 1588 Precise Time Protocol. */
 
+/**
+ * Extract VLAN tag information into mbuf
+ *
+ * Software version of VLAN stripping
+ *
+ * @param m
+ *   The packet mbuf.
+ * @return
+ *   - 0: Success
+ *   - 1: not a vlan packet
+ */
+static inline int rte_vlan_strip(struct rte_mbuf *m)
+{
+	struct ether_hdr *eh
+		 = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	if (eh->ether_type != ETHER_TYPE_VLAN)
+		return -1;
+
+	struct vlan_hdr *vh = (struct vlan_hdr *)(eh + 1);
+	m->ol_flags |= PKT_RX_VLAN_PKT;
+	m->pkt.vlan_macip.f.vlan_tci = rte_be_to_cpu_16(vh->vlan_tci);
+
+	/* Copy ether header over rather than moving whole packet */
+	memmove(rte_pktmbuf_adj(m, sizeof(struct vlan_hdr)),
+		eh, 2 * ETHER_ADDR_LEN);
+
+	return 0;
+}
+
+/**
+ * Insert VLAN tag into mbuf.
+ *
+ * Software version of VLAN unstripping
+ *
+ * @param m
+ *   The packet mbuf.
+ * @return
+ *   - 0: On success
+ *   -EPERM: mbuf is is shared overwriting would be unsafe
+ *   -ENOSPC: not enough headroom in mbuf
+ */
+static inline int rte_vlan_insert(struct rte_mbuf *m)
+{
+	struct ether_hdr *oh, *nh;
+	struct vlan_hdr *vh;
+
+#ifdef RTE_MBUF_SCATTER_GATHER
+	/* Can't insert header if mbuf is shared */
+	if (rte_mbuf_refcnt_read(m) > 1)
+		return -EINVAL;
+#endif
+	oh = rte_pktmbuf_mtod(m, struct ether_hdr *);
+	nh = (struct ether_hdr *)
+		rte_pktmbuf_prepend(m, sizeof(struct vlan_hdr));
+	if (nh == NULL)
+		return -ENOSPC;
+
+	memmove(nh, oh, 2 * ETHER_ADDR_LEN);
+	nh->ether_type = ETHER_TYPE_VLAN;
+
+	vh = (struct vlan_hdr *) (nh + 1);
+	vh->vlan_tci = rte_cpu_to_be_16(m->pkt.vlan_macip.f.vlan_tci);
+
+	return 0;
+}
+
 #ifdef __cplusplus
 }
 #endif
#8 lore raw

RFC 6/10 virtio: use software vlan stripping

In reply to Stephen Hemminger

Implement VLAN stripping in software. This allows application to be device independent.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |    2 ++
 lib/librte_pmd_virtio/virtio_pci.h    |    1 +
 lib/librte_pmd_virtio/virtio_rxtx.c   |   20 ++++++++++++++++++--
 3 files changed, 21 insertions(+), 2 deletions(-)
lib/librte_pmd_virtio/virtio_ethdev.c +2 -0
@@ -976,6 +976,8 @@ virtio_dev_configure(struct rte_eth_dev
 		return (-EINVAL);
 	}
 
+	hw->vlan_strip = rxmode->hw_vlan_strip;
+
 	ret = vtpci_irq_config(hw, 0);
 	if (ret != 0)
 		PMD_DRV_LOG(ERR, "failed to set config vector");
lib/librte_pmd_virtio/virtio_pci.h +1 -0
@@ -168,6 +168,7 @@ struct virtio_hw {
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
 	uint16_t    vtnet_hdr_size;
+	uint8_t	    vlan_strip;
 	uint8_t	    use_msix;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
 };
lib/librte_pmd_virtio/virtio_rxtx.c +18 -2
@@ -49,6 +49,7 @@
 #include <rte_prefetch.h>
 #include <rte_string_fns.h>
 #include <rte_errno.h>
+#include <rte_byteorder.h>
 
 #include "virtio_logs.h"
 #include "virtio_ethdev.h"
@@ -406,8 +407,8 @@ virtio_dev_tx_queue_setup(struct rte_eth
 
 	PMD_INIT_FUNC_TRACE();
 
-	if ((tx_conf->txq_flags & ETH_TXQ_FLAGS_NOOFFLOADS)
-	    != ETH_TXQ_FLAGS_NOOFFLOADS) {
+	if ((tx_conf->txq_flags & ETH_TXQ_FLAGS_NOXSUMS)
+	    != ETH_TXQ_FLAGS_NOXSUMS) {
 		PMD_INIT_LOG(ERR, "TX checksum offload not supported\n");
 		return -EINVAL;
 	}
@@ -444,6 +445,7 @@ uint16_t
 virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 {
 	struct virtqueue *rxvq = rx_queue;
+	struct virtio_hw *hw = rxvq->hw;
 	struct rte_mbuf *rxm, *new_mbuf;
 	uint16_t nb_used, num, nb_rx = 0;
 	uint32_t len[VIRTIO_MBUF_BURST_SZ];
@@ -487,6 +489,9 @@ virtio_recv_pkts(void *rx_queue, struct
 		rxm->pkt.pkt_len = (uint32_t)(len[i] - hdr_size);
 		rxm->pkt.data_len = (uint16_t)(len[i] - hdr_size);
 
+		if (hw->vlan_strip)
+			rte_vlan_strip(rxm);
+
 		VIRTIO_DUMP_PACKET(rxm, rxm->pkt.data_len);
 
 		rx_pkts[nb_rx++] = rxm;
@@ -711,6 +716,17 @@ virtio_xmit_pkts(void *tx_queue, struct
 
 		if (tx_pkts[nb_tx]->pkt.nb_segs <= txvq->vq_free_cnt) {
 			txm = tx_pkts[nb_tx];
+
+			/* Do VLAN tag insertion */
+			if (txm->ol_flags & PKT_TX_VLAN_PKT) {
+				error = rte_vlan_insert(txm);
+				if (unlikely(error)) {
+					rte_pktmbuf_free(txm);
+					++nb_tx;
+					continue;
+				}
+			}
+
 			/* Enqueue Packet buffers */
 			error = virtqueue_enqueue_xmit(txvq, txm);
 			if (unlikely(error)) {

A message that is not in the archive (sent off-list or not yet received): 20140826020848.386074683-OTpzqLSitTUnbdJkjeBofR2eb7JE58TQ@public.gmane.org

#10 lore raw

Re: [RFC 06/10] virtio: use software vlan stripping

Hi Stephen,

Would you please describe the use scenario for the front end rx vlan strip and tx vlan insertion? In our current implementation, backend will strip vlan tag for RX, and insert vlan tag for TX.

Thanks
Changchun

Quoted 102 lines

-----Original Message-----
From: Stephen Hemminger [mailto:[email protected]]
Sent: Tuesday, August 26, 2014 10:08 AM
To: Ouyang, Changchun
Cc: [email protected]; Stephen Hemminger
Subject: [RFC 06/10] virtio: use software vlan stripping

Implement VLAN stripping in software. This allows application to be device independent.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |    2 ++
 lib/librte_pmd_virtio/virtio_pci.h    |    1 +
 lib/librte_pmd_virtio/virtio_rxtx.c   |   20 ++++++++++++++++++--
 3 files changed, 21 insertions(+), 2 deletions(-)

--- a/lib/librte_pmd_virtio/virtio_ethdev.c 2014-08-25
19:00:07.574537243 -0700
+++ b/lib/librte_pmd_virtio/virtio_ethdev.c 2014-08-25
19:00:07.574537243 -0700

lib/librte_pmd_virtio/virtio_ethdev.c +2 -0
@@ -976,6 +976,8 @@ virtio_dev_configure(struct rte_eth_dev
 		return (-EINVAL);
 	}
 
+	hw->vlan_strip = rxmode->hw_vlan_strip;
+
 	ret = vtpci_irq_config(hw, 0);
 	if (ret != 0)
 		PMD_DRV_LOG(ERR, "failed to set config vector");
lib/librte_pmd_virtio/virtio_pci.h +0 -0

19:00:07.574537243 -0700

lib/librte_pmd_virtio/virtio_pci.h +1 -0
@@ -168,6 +168,7 @@ struct virtio_hw {
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
 	uint16_t    vtnet_hdr_size;
+	uint8_t	    vlan_strip;
 	uint8_t	    use_msix;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
 };
lib/librte_pmd_virtio/virtio_rxtx.c +0 -0

19:00:07.574537243 -0700

lib/librte_pmd_virtio/virtio_rxtx.c +3 -2
@@ -49,6 +49,7 @@
 #include <rte_prefetch.h>
 #include <rte_string_fns.h>
 #include <rte_errno.h>
+#include <rte_byteorder.h>
 
 #include "virtio_logs.h"
 #include "virtio_ethdev.h"
@@ -406,8 +407,8 @@ virtio_dev_tx_queue_setup(struct rte_eth
 
 	PMD_INIT_FUNC_TRACE();
 
-	if ((tx_conf->txq_flags & ETH_TXQ_FLAGS_NOOFFLOADS)
-	    != ETH_TXQ_FLAGS_NOOFFLOADS) {
+	if ((tx_conf->txq_flags & ETH_TXQ_FLAGS_NOXSUMS)
+	    != ETH_TXQ_FLAGS_NOXSUMS) {
 		PMD_INIT_LOG(ERR, "TX checksum offload not
 supported\n");
 		return -EINVAL;
lib/librte_pmd_virtio/virtio_rxtx.c +15 -0
 	}
@@ -444,6 +445,7 @@ uint16_t
 virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t
 nb_pkts)  {
 	struct virtqueue *rxvq = rx_queue;
+	struct virtio_hw *hw = rxvq->hw;
 	struct rte_mbuf *rxm, *new_mbuf;
 	uint16_t nb_used, num, nb_rx = 0;
 	uint32_t len[VIRTIO_MBUF_BURST_SZ];
@@ -487,6 +489,9 @@ virtio_recv_pkts(void *rx_queue, struct
 		rxm->pkt.pkt_len = (uint32_t)(len[i] - hdr_size);
 		rxm->pkt.data_len = (uint16_t)(len[i] - hdr_size);
 
+		if (hw->vlan_strip)
+			rte_vlan_strip(rxm);
+
 		VIRTIO_DUMP_PACKET(rxm, rxm->pkt.data_len);
 
 		rx_pkts[nb_rx++] = rxm;
@@ -711,6 +716,17 @@ virtio_xmit_pkts(void *tx_queue, struct
 
 		if (tx_pkts[nb_tx]->pkt.nb_segs <= txvq->vq_free_cnt) {
 			txm = tx_pkts[nb_tx];
+
+			/* Do VLAN tag insertion */
+			if (txm->ol_flags & PKT_TX_VLAN_PKT) {
+				error = rte_vlan_insert(txm);
+				if (unlikely(error)) {
+					rte_pktmbuf_free(txm);
+					++nb_tx;
+					continue;
+				}
+			}
+
 			/* Enqueue Packet buffers */
 			error = virtqueue_enqueue_xmit(txvq, txm);
 			if (unlikely(error)) {

A message that is not in the archive (sent off-list or not yet received): F52918179C57134FAEC9EA62FA2F96251183B285-E2R4CRU6q/[email protected]

#12 lore raw

Re: [RFC 06/10] virtio: use software vlan stripping

Quoted 7 lines · Changchun

Hi Stephen,

Would you please describe the use scenario for the front end rx vlan strip and tx vlan insertion? In our current implementation, backend will strip vlan tag for RX, and insert vlan tag for TX.

Thanks
Changchun

First, we don't have to do software VLAN strip on our backend if we do this. And this way we can always use VLAN insert on transmit. Otherwise you have to introduce special case because there is no DPDK API to determine if device does or does not do VLAN handling.

#13 lore raw

Re: [RFC 06/10] virtio: use software vlan stripping

Quoted 18 lines

-----Original Message-----
From: Stephen Hemminger [mailto:[email protected]]
Sent: Wednesday, August 27, 2014 12:24 AM
To: Ouyang, Changchun
Cc: [email protected]
Subject: Re: [RFC 06/10] virtio: use software vlan stripping

Quoted 3 lines · Changchun

Hi Stephen,

Would you please describe the use scenario for the front end rx vlan strip

and tx vlan insertion?

Quoted 1 line

In our current implementation, backend will strip vlan tag for RX, and insert

vlan tag for TX.

Quoted 1 line
Quoted 8 lines
Quoted 2 lines

Thanks
Changchun

First, we don't have to do software VLAN strip on our backend if we do this. And this way we can always use VLAN insert on transmit. Otherwise you have to introduce special case because there is no DPDK API to determine if device does or does not do VLAN handling.

How the virtio frontend tell backend whether it has software VLAN strip feature or not? It seems no feature bit to negotiate it.

Thanks
Changchun

A message that is not in the archive (sent off-list or not yet received): F52918179C57134FAEC9EA62FA2F96251183B79C-E2R4CRU6q/[email protected]

#15 lore raw

Re: [RFC 06/10] virtio: use software vlan stripping

Quoted 27 lines · Changchun
Quoted 18 lines

-----Original Message-----
From: Stephen Hemminger [mailto:[email protected]]
Sent: Wednesday, August 27, 2014 12:24 AM
To: Ouyang, Changchun
Cc: [email protected]
Subject: Re: [RFC 06/10] virtio: use software vlan stripping

Quoted 3 lines · Changchun

Hi Stephen,

Would you please describe the use scenario for the front end rx vlan strip

and tx vlan insertion?

Quoted 1 line

In our current implementation, backend will strip vlan tag for RX, and insert

vlan tag for TX.

Quoted 1 line
Quoted 8 lines
Quoted 2 lines

Thanks
Changchun

First, we don't have to do software VLAN strip on our backend if we do this. And this way we can always use VLAN insert on transmit. Otherwise you have to introduce special case because there is no DPDK API to determine if device does or does not do VLAN handling.

Quoted 6 lines

How the virtio frontend tell backend whether it has software VLAN strip feature or not? It seems no feature bit to negotiate it.

Thanks
Changchun

All other drivers have VLAN stripping as option under rte_eth_rxmode / hw_vlan_strip. There is negotiation in DPDK, it is strictly ask for feature and either get it or an error. Therefore we went ahead and emulated the feature in software.

#16 lore raw

RFC 7/10 virtio: remove unnecessary adapter structure

In reply to Stephen Hemminger

Cleanup virtio code by eliminating unnecessary nesting of virtio hardware structure inside adapter structure. Also allows removing unneeded macro, making code clearer.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |   31 +++++++++++--------------------
 lib/librte_pmd_virtio/virtio_ethdev.h |    9 ---------
 lib/librte_pmd_virtio/virtio_rxtx.c   |    3 +--
 3 files changed, 12 insertions(+), 31 deletions(-)
lib/librte_pmd_virtio/virtio_ethdev.c +11 -20
@@ -203,8 +203,7 @@ virtio_send_command(struct virtqueue *vq
 static int
 virtio_set_multiple_queues(struct rte_eth_dev *dev, uint16_t nb_queues)
 {
-	struct virtio_hw *hw
-		= VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct virtio_hw *hw = dev->data->dev_private;
 	struct virtio_pmd_ctrl ctrl;
 	int dlen[1];
 	int ret;
@@ -238,8 +237,7 @@ int virtio_dev_queue_setup(struct rte_et
 	const struct rte_memzone *mz;
 	uint16_t vq_size;
 	int size;
-	struct virtio_hw *hw =
-		VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct virtio_hw *hw = dev->data->dev_private;
 	struct virtqueue  *vq = NULL;
 
 	/* Write the virtqueue index to the Queue Select Field */
@@ -379,8 +377,7 @@ virtio_dev_cq_queue_setup(struct rte_eth
 	struct virtqueue *vq;
 	uint16_t nb_desc = 0;
 	int ret;
-	struct virtio_hw *hw =
-		VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct virtio_hw *hw = dev->data->dev_private;
 
 	PMD_INIT_FUNC_TRACE();
 	ret = virtio_dev_queue_setup(dev, VTNET_CQ, VTNET_SQ_CQ_QUEUE_IDX,
@@ -765,8 +762,7 @@ virtio_interrupt_handler(__rte_unused st
 			 void *param)
 {
 	struct rte_eth_dev *dev = param;
-	struct virtio_hw *hw =
-		VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct virtio_hw *hw = dev->data->dev_private;
 	uint8_t isr;
 
 	/* Read interrupt status which clears interrupt */
@@ -792,12 +788,11 @@ static int
 eth_virtio_dev_init(__rte_unused struct eth_driver *eth_drv,
 		struct rte_eth_dev *eth_dev)
 {
+	struct virtio_hw *hw = eth_dev->data->dev_private;
 	struct virtio_net_config *config;
 	struct virtio_net_config local_config;
 	uint32_t offset_conf = sizeof(config->mac);
 	struct rte_pci_device *pci_dev;
-	struct virtio_hw *hw =
-		VIRTIO_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
 
 	if (RTE_PKTMBUF_HEADROOM < sizeof(struct virtio_net_hdr)) {
 		PMD_INIT_LOG(ERR,
@@ -928,7 +923,7 @@ static struct eth_driver rte_virtio_pmd
 		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	},
 	.eth_dev_init = eth_virtio_dev_init,
-	.dev_private_size = sizeof(struct virtio_adapter),
+	.dev_private_size = sizeof(struct virtio_hw),
 };
 
 /*
@@ -965,8 +960,7 @@ static int
 virtio_dev_configure(struct rte_eth_dev *dev)
 {
 	const struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
-	struct virtio_hw *hw =
-		VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct virtio_hw *hw = dev->data->dev_private;
 	int ret;
 
 	PMD_INIT_LOG(DEBUG, "configure");
@@ -990,8 +984,7 @@ static int
 virtio_dev_start(struct rte_eth_dev *dev)
 {
 	uint16_t nb_queues, i;
-	struct virtio_hw *hw =
-		VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct virtio_hw *hw = dev->data->dev_private;
 
 	/* Tell the host we've noticed this device. */
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_ACK);
@@ -1097,8 +1090,7 @@ static void virtio_dev_free_mbufs(struct
 static void
 virtio_dev_stop(struct rte_eth_dev *dev)
 {
-	struct virtio_hw *hw =
-		VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct virtio_hw *hw = dev->data->dev_private;
 
 	/* reset the NIC */
 	vtpci_irq_config(hw, 0);
@@ -1111,8 +1103,7 @@ virtio_dev_link_update(struct rte_eth_de
 {
 	struct rte_eth_link link, old;
 	uint16_t status;
-	struct virtio_hw *hw =
-		VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct virtio_hw *hw = dev->data->dev_private;
 	memset(&link, 0, sizeof(link));
 	virtio_dev_atomic_read_link_status(dev, &link);
 	old = link;
@@ -1144,7 +1135,7 @@ virtio_dev_link_update(struct rte_eth_de
 static void
 virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
-	struct virtio_hw *hw = VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct virtio_hw *hw = dev->data->dev_private;
 
 	dev_info->driver_name = dev->driver->pci_drv.name;
 	dev_info->max_rx_queues = (uint16_t)hw->max_rx_queues;
lib/librte_pmd_virtio/virtio_ethdev.h +0 -9
@@ -110,15 +110,6 @@ uint16_t virtio_recv_mergeable_pkts(void
 uint16_t virtio_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 		uint16_t nb_pkts);
 
-/*
- * Structure to store private data for each driver instance (for each port).
- */
-struct virtio_adapter {
-	struct virtio_hw hw;
-};
-
-#define VIRTIO_DEV_PRIVATE_TO_HW(adapter)\
-	(&((struct virtio_adapter *)adapter)->hw)
 
 /*
  * The VIRTIO_NET_F_GUEST_TSO[46] features permit the host to send us
lib/librte_pmd_virtio/virtio_rxtx.c +1 -2
@@ -326,8 +326,7 @@ virtio_dev_vring_start(struct virtqueue
 void
 virtio_dev_cq_start(struct rte_eth_dev *dev)
 {
-	struct virtio_hw *hw
-		= VIRTIO_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct virtio_hw *hw = dev->data->dev_private;
 
 	virtio_dev_vring_start(hw->cvq, VTNET_CQ);
 	VIRTQUEUE_DUMP((struct virtqueue *)hw->cvq);

A message that is not in the archive (sent off-list or not yet received): 20140826020851.474452281-OTpzqLSitTUnbdJkjeBofR2eb7JE58TQ@public.gmane.org

Acked-by Changchun Ouyang
#18 lore raw

Re: [RFC 07/10] virtio: remove unnecessary adapter structure

Quoted 17 lines

-----Original Message-----
From: Stephen Hemminger [mailto:[email protected]]
Sent: Tuesday, August 26, 2014 10:08 AM
To: Ouyang, Changchun
Cc: [email protected]
Subject: [RFC 07/10] virtio: remove unnecessary adapter structure

Cleanup virtio code by eliminating unnecessary nesting of virtio hardware structure inside adapter structure.
Also allows removing unneeded macro, making code clearer.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |   31 +++++++++++--------------------
 lib/librte_pmd_virtio/virtio_ethdev.h |    9 ---------
 lib/librte_pmd_virtio/virtio_rxtx.c   |    3 +--
 3 files changed, 12 insertions(+), 31 deletions(-)
#19 lore raw

RFC 8/10 virtio: remove redundant vq_alignment

In reply to Stephen Hemminger

Since vq_alignment is constant (always 4K), it does not need to be part of the vring struct.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |    1 -
 lib/librte_pmd_virtio/virtio_rxtx.c   |    2 +-
 lib/librte_pmd_virtio/virtqueue.h     |    3 +--
 3 files changed, 2 insertions(+), 4 deletions(-)
lib/librte_pmd_virtio/virtio_ethdev.c +0 -1
@@ -290,7 +290,6 @@ int virtio_dev_queue_setup(struct rte_et
 	vq->port_id = dev->data->port_id;
 	vq->queue_id = queue_idx;
 	vq->vq_queue_index = vtpci_queue_idx;
-	vq->vq_alignment = VIRTIO_PCI_VRING_ALIGN;
 	vq->vq_nentries = vq_size;
 	vq->vq_free_cnt = vq_size;
 
lib/librte_pmd_virtio/virtio_rxtx.c +1 -1
@@ -258,7 +258,7 @@ virtio_dev_vring_start(struct virtqueue
 	 * Reinitialise since virtio port might have been stopped and restarted
 	 */
 	memset(vq->vq_ring_virt_mem, 0, vq->vq_ring_size);
-	vring_init(vr, size, ring_mem, vq->vq_alignment);
+	vring_init(vr, size, ring_mem, VIRTIO_PCI_VRING_ALIGN);
 	vq->vq_used_cons_idx = 0;
 	vq->vq_desc_head_idx = 0;
 	vq->vq_avail_idx = 0;
lib/librte_pmd_virtio/virtqueue.h +1 -2
@@ -139,8 +139,7 @@ struct virtqueue {
 	uint8_t     port_id;              /**< Device port identifier. */
 
 	void        *vq_ring_virt_mem;    /**< linear address of vring*/
-	int         vq_alignment;
-	int         vq_ring_size;
+	unsigned int vq_ring_size;
 	phys_addr_t vq_ring_mem;          /**< physical address of vring */
 
 	struct vring vq_ring;    /**< vring keeping desc, used and avail */

A message that is not in the archive (sent off-list or not yet received): 20140826020853.851222673-OTpzqLSitTUnbdJkjeBofR2eb7JE58TQ@public.gmane.org

#21 lore raw

Re: [RFC 08/10] virtio: remove redundant vq_alignment

Acked by: Changchun Ouyang <[email protected]>

Quoted 55 lines

-----Original Message-----
From: Stephen Hemminger [mailto:[email protected]]
Sent: Tuesday, August 26, 2014 10:08 AM
To: Ouyang, Changchun
Cc: [email protected]; Stephen Hemminger
Subject: [RFC 08/10] virtio: remove redundant vq_alignment

Since vq_alignment is constant (always 4K), it does not need to be part of the vring struct.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |    1 -
 lib/librte_pmd_virtio/virtio_rxtx.c   |    2 +-
 lib/librte_pmd_virtio/virtqueue.h     |    3 +--
 3 files changed, 2 insertions(+), 4 deletions(-)

--- a/lib/librte_pmd_virtio/virtio_ethdev.c 2014-08-25
19:00:09.918550097 -0700
+++ b/lib/librte_pmd_virtio/virtio_ethdev.c 2014-08-25
19:00:09.918550097 -0700

lib/librte_pmd_virtio/virtio_ethdev.c +0 -1
@@ -290,7 +290,6 @@ int virtio_dev_queue_setup(struct rte_et
 	vq->port_id = dev->data->port_id;
 	vq->queue_id = queue_idx;
 	vq->vq_queue_index = vtpci_queue_idx;
-	vq->vq_alignment = VIRTIO_PCI_VRING_ALIGN;
 	vq->vq_nentries = vq_size;
 	vq->vq_free_cnt = vq_size;
 
lib/librte_pmd_virtio/virtio_rxtx.c +0 -0

19:00:09.918550097 -0700

lib/librte_pmd_virtio/virtio_rxtx.c +1 -1
@@ -258,7 +258,7 @@ virtio_dev_vring_start(struct virtqueue
 	 * Reinitialise since virtio port might have been stopped and restarted
 	 */
 	memset(vq->vq_ring_virt_mem, 0, vq->vq_ring_size);
-	vring_init(vr, size, ring_mem, vq->vq_alignment);
+	vring_init(vr, size, ring_mem, VIRTIO_PCI_VRING_ALIGN);
 	vq->vq_used_cons_idx = 0;
 	vq->vq_desc_head_idx = 0;
 	vq->vq_avail_idx = 0;
lib/librte_pmd_virtio/virtqueue.h +0 -0

19:00:09.918550097 -0700

lib/librte_pmd_virtio/virtqueue.h +1 -2
@@ -139,8 +139,7 @@ struct virtqueue {
 	uint8_t     port_id;              /**< Device port identifier. */
 
 	void        *vq_ring_virt_mem;    /**< linear address of vring*/
-	int         vq_alignment;
-	int         vq_ring_size;
+	unsigned int vq_ring_size;
 	phys_addr_t vq_ring_mem;          /**< physical address of vring */
 
 	struct vring vq_ring;    /**< vring keeping desc, used and avail */
#22 lore raw

RFC 9/10 virtio: fix how states are handled during initialization

In reply to Stephen Hemminger

Change order of initialiazation to match Linux kernel. Don't blow away control queue by doing reset when stopped.

---
 lib/librte_pmd_virtio/virtio_ethdev.c |   50 ++++++++++------------------------
 lib/librte_pmd_virtio/virtio_rxtx.c   |    2 +
 2 files changed, 18 insertions(+), 34 deletions(-)
lib/librte_pmd_virtio/virtio_ethdev.c +16 -34
@@ -394,9 +394,11 @@ virtio_dev_cq_queue_setup(struct rte_eth
 static void
 virtio_dev_close(struct rte_eth_dev *dev)
 {
-	PMD_INIT_LOG(DEBUG, "virtio_dev_close");
+	struct virtio_hw *hw = dev->data->dev_private;
 
-	virtio_dev_stop(dev);
+	vtpci_irq_config(hw, VIRTIO_MSI_NO_VECTOR);
+	vtpci_reset(hw);
+	virtio_dev_free_mbufs(dev);
 }
 
 /*
@@ -811,6 +813,9 @@ eth_virtio_dev_init(__rte_unused struct
 	if (rte_eal_process_type() == RTE_PROC_SECONDARY)
 		return 0;
 
+	/* Tell the host we've noticed this device. */
+	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_ACK);
+
 	pci_dev = eth_dev->pci_dev;
 	if (virtio_resource_init(pci_dev) < 0)
 		return -1;
@@ -821,9 +826,6 @@ eth_virtio_dev_init(__rte_unused struct
 	/* Reset the device although not necessary at startup */
 	vtpci_reset(hw);
 
-	/* Tell the host we've noticed this device. */
-	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_ACK);
-
 	/* Tell the host we've known how to drive the device. */
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
 	virtio_negotiate_features(hw);
@@ -912,6 +914,9 @@ eth_virtio_dev_init(__rte_unused struct
 	/* Setup interrupt callback  */
 	rte_intr_callback_register(&pci_dev->intr_handle,
 				   virtio_interrupt_handler, eth_dev);
+
+	virtio_dev_cq_start(eth_dev);
+
 	return 0;
 }
 
@@ -982,19 +987,8 @@ virtio_dev_configure(struct rte_eth_dev
 static int
 virtio_dev_start(struct rte_eth_dev *dev)
 {
-	uint16_t nb_queues, i;
 	struct virtio_hw *hw = dev->data->dev_private;
-
-	/* Tell the host we've noticed this device. */
-	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_ACK);
-
-	/* Tell the host we've known how to drive the device. */
-	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
-
-	virtio_dev_cq_start(dev);
-
-	/* Do final configuration before rx/tx engine starts */
-	virtio_dev_rxtx_start(dev);
+	uint16_t nb_queues;
 
 	/* check if lsc interrupt feature is enabled */
 	if (dev->data->dev_conf.intr_conf.lsc) {
@@ -1024,18 +1018,8 @@ virtio_dev_start(struct rte_eth_dev *dev
 			return -EINVAL;
 	}
 
-	PMD_INIT_LOG(DEBUG, "nb_queues=%d", nb_queues);
-
-	for (i = 0; i < nb_queues; i++)
-		virtqueue_notify(dev->data->rx_queues[i]);
-
-	PMD_INIT_LOG(DEBUG, "Notified backend at initialization");
-
-	for (i = 0; i < dev->data->nb_rx_queues; i++)
-		VIRTQUEUE_DUMP((struct virtqueue *)dev->data->rx_queues[i]);
-
-	for (i = 0; i < dev->data->nb_tx_queues; i++)
-		VIRTQUEUE_DUMP((struct virtqueue *)dev->data->tx_queues[i]);
+	/* Do final configuration before rx/tx engine starts */
+	virtio_dev_rxtx_start(dev);
 
 	return 0;
 }
@@ -1089,12 +1073,10 @@ static void virtio_dev_free_mbufs(struct
 static void
 virtio_dev_stop(struct rte_eth_dev *dev)
 {
-	struct virtio_hw *hw = dev->data->dev_private;
+	if (dev->data->dev_conf.intr_conf.lsc)
+		rte_intr_disable(&dev->pci_dev->intr_handle);
 
-	/* reset the NIC */
-	vtpci_irq_config(hw, 0);
-	vtpci_reset(hw);
-	virtio_dev_free_mbufs(dev);
+	memset(&dev->data->dev_link, 0, sizeof(struct rte_eth_link));
 }
 
 static int
lib/librte_pmd_virtio/virtio_rxtx.c +2 -0
@@ -350,6 +350,8 @@ virtio_dev_rxtx_start(struct rte_eth_dev
 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
 		virtio_dev_vring_start(dev->data->rx_queues[i], VTNET_RQ);
 		VIRTQUEUE_DUMP((struct virtqueue *)dev->data->rx_queues[i]);
+
+		virtqueue_notify(dev->data->rx_queues[i]);
 	}
 
 	/* Start tx vring. */
#23 lore raw

RFC 10/10 virtio: add support for promiscious and multicast

In reply to Stephen Hemminger

Implement standard virtio controls for enabling and disabling promiscious and multicast.

lib/librte_pmd_virtio/virtio_ethdev.c +82 -16
@@ -77,6 +77,11 @@ static void virtio_get_hwaddr(struct vir
 static void virtio_dev_rx_queue_release(__rte_unused void *rxq);
 static void virtio_dev_tx_queue_release(__rte_unused void *txq);
 
+static void virtio_promiscuous_enable(struct rte_eth_dev *dev);
+static void virtio_promiscuous_disable(struct rte_eth_dev *dev);
+static void virtio_allmulticast_enable(struct rte_eth_dev *dev);
+static void virtio_allmulticast_disable(struct rte_eth_dev *dev);
+
 static void virtio_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
 static void virtio_dev_stats_reset(struct rte_eth_dev *dev);
 static void virtio_dev_free_mbufs(struct rte_eth_dev *dev);
@@ -405,23 +410,27 @@ virtio_dev_close(struct rte_eth_dev *dev
  * dev_ops for virtio, bare necessities for basic operation
  */
 static struct eth_dev_ops virtio_eth_dev_ops = {
-	.dev_configure           = virtio_dev_configure,
-	.dev_start               = virtio_dev_start,
-	.dev_stop                = virtio_dev_stop,
-	.dev_close               = virtio_dev_close,
-
-	.dev_infos_get           = virtio_dev_info_get,
-	.stats_get               = virtio_dev_stats_get,
-	.stats_reset             = virtio_dev_stats_reset,
-	.link_update             = virtio_dev_link_update,
-	.mac_addr_add            = NULL,
-	.mac_addr_remove         = NULL,
-	.rx_queue_setup          = virtio_dev_rx_queue_setup,
+	.dev_configure		 = virtio_dev_configure,
+	.dev_start		 = virtio_dev_start,
+	.dev_stop		 = virtio_dev_stop,
+	.dev_close		 = virtio_dev_close,
+
+	.dev_infos_get		 = virtio_dev_info_get,
+	.stats_get		 = virtio_dev_stats_get,
+	.stats_reset		 = virtio_dev_stats_reset,
+	.link_update		 = virtio_dev_link_update,
+	.promiscuous_enable	 = virtio_promiscuous_enable,
+	.promiscuous_disable	 = virtio_promiscuous_disable,
+	.allmulticast_enable	 = virtio_allmulticast_enable,
+	.allmulticast_disable	 = virtio_allmulticast_disable,
+	.mac_addr_add		 = NULL,
+	.mac_addr_remove	 = NULL,
+	.rx_queue_setup		 = virtio_dev_rx_queue_setup,
 	/* meaningfull only to multiple queue */
-	.rx_queue_release        = virtio_dev_rx_queue_release,
-	.tx_queue_setup          = virtio_dev_tx_queue_setup,
+	.rx_queue_release	 = virtio_dev_rx_queue_release,
+	.tx_queue_setup		 = virtio_dev_tx_queue_setup,
 	/* meaningfull only to multiple queue */
-	.tx_queue_release        = virtio_dev_tx_queue_release,
+	.tx_queue_release	 = virtio_dev_tx_queue_release,
 	/* collect stats per queue */
 	.queue_stats_mapping_set = virtio_dev_queue_stats_mapping_set,
 };
@@ -466,6 +475,63 @@ virtio_dev_atomic_write_link_status(stru
 	return 0;
 }
 
+/* Control receive processing (ie multicast, promiscious, mac address). */
+static int virtio_ctrl_rx(struct virtio_hw *hw, uint8_t cmd, uint8_t onoff)
+{
+	struct virtio_pmd_ctrl ctrl;
+	int len, ret;
+
+	if (!vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_RX))
+		return -ENOTSUP;
+
+	ctrl.hdr.class = VIRTIO_NET_CTRL_RX;
+	ctrl.hdr.cmd = cmd;
+	memcpy(ctrl.data, &onoff, sizeof(uint8_t));
+
+	len = sizeof(uint8_t);
+	ret = virtio_send_command(hw->cvq, &ctrl, &len, 1);
+	if (ret != 0)
+		PMD_DRV_LOG(NOTICE, "ctrl_rx %u failed: %d\n", cmd, ret);
+
+	return ret;
+}
+
+static void
+virtio_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct virtio_hw *hw = dev->data->dev_private;
+
+	PMD_INIT_LOG(DEBUG, "promiscious enable");
+	virtio_ctrl_rx(hw, VIRTIO_NET_CTRL_RX_PROMISC, 1);
+}
+
+static void
+virtio_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct virtio_hw *hw = dev->data->dev_private;
+
+	PMD_INIT_LOG(DEBUG, "promiscious disable");
+	virtio_ctrl_rx(hw, VIRTIO_NET_CTRL_RX_PROMISC, 0);
+}
+
+static void
+virtio_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct virtio_hw *hw = dev->data->dev_private;
+
+	PMD_INIT_LOG(DEBUG, "allmulticast enable");
+	virtio_ctrl_rx(hw, VIRTIO_NET_CTRL_RX_ALLMULTI, 1);
+}
+
+static void
+virtio_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct virtio_hw *hw = dev->data->dev_private;
+
+	PMD_INIT_LOG(DEBUG, "allmulticast disable");
+	virtio_ctrl_rx(hw, VIRTIO_NET_CTRL_RX_ALLMULTI, 0);
+}
+
 static void
 virtio_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 {
@@ -559,7 +625,7 @@ virtio_negotiate_features(struct virtio_
 {
 	uint32_t host_features, mask;
 
-	mask = VIRTIO_NET_F_CTRL_RX | VIRTIO_NET_F_CTRL_VLAN;
+	mask = VIRTIO_NET_F_CTRL_VLAN;
 	mask |= VIRTIO_NET_F_CSUM | VIRTIO_NET_F_GUEST_CSUM;
 
 	/* TSO and LRO are only available when their corresponding

A message that is not in the archive (sent off-list or not yet received): 20140826020858.448904783-OTpzqLSitTUnbdJkjeBofR2eb7JE58TQ@public.gmane.org

#25 lore raw

Re: [RFC 10/10] virtio: add support for promiscious and multicast

This patch is very similar with my previous patch:

[PATCH 4/5] virtio: New API to enable/disable multicast and promisc mode

So suggest applying only one of both.

Thanks
Changchun

Quoted 16 lines

-----Original Message-----
From: Stephen Hemminger [mailto:[email protected]]
Sent: Tuesday, August 26, 2014 10:08 AM
To: Ouyang, Changchun
Cc: [email protected]; Stephen Hemminger
Subject: [RFC 10/10] virtio: add support for promiscious and multicast

Implement standard virtio controls for enabling and disabling promiscious and multicast.

--- a/lib/librte_pmd_virtio/virtio_ethdev.c 2014-08-25
19:00:16.754586819 -0700
+++ b/lib/librte_pmd_virtio/virtio_ethdev.c 2014-08-25
19:02:48.019397658 -0700