From: alvinx.zhang@intel.com
To: dev@dpdk.org
Cc: xiaolong.ye@intel.com
Subject: [dpdk-dev] [PATCH v4 09/11] net/igc: implement feature of VLAN
Date: Wed, 15 Apr 2020 16:48:08 +0800 [thread overview]
Message-ID: <20200415084810.20816-10-alvinx.zhang@intel.com> (raw)
In-Reply-To: <20200415084810.20816-1-alvinx.zhang@intel.com>
From: Alvin Zhang <alvinx.zhang@intel.com>
Below ops ware added:
vlan_filter_set
vlan_offload_set
vlan_tpid_set
vlan_strip_queue_set
Signed-off-by: Alvin Zhang <alvinx.zhang@intel.com>
V2: Fix max packet length fault when extend vlan is enabled or disabled.
V3: Fix queue vlan offload fault, update docs.
V4: Modify codes according to comments.
---
doc/guides/nics/features/igc.ini | 2 +
doc/guides/nics/igc.rst | 35 +++++++
drivers/net/igc/igc_ethdev.c | 205 +++++++++++++++++++++++++++++++++++++++
drivers/net/igc/igc_ethdev.h | 16 +++
drivers/net/igc/igc_txrx.c | 38 ++++++++
drivers/net/igc/igc_txrx.h | 3 +-
6 files changed, 298 insertions(+), 1 deletion(-)
diff --git a/doc/guides/nics/features/igc.ini b/doc/guides/nics/features/igc.ini
index 23434af..5bc901f 100644
--- a/doc/guides/nics/features/igc.ini
+++ b/doc/guides/nics/features/igc.ini
@@ -30,6 +30,8 @@ Rx interrupt = Y
Flow control = Y
RSS key update = Y
RSS reta update = Y
+VLAN filter = Y
+VLAN offload = Y
Linux UIO = Y
Linux VFIO = Y
x86-64 = Y
diff --git a/doc/guides/nics/igc.rst b/doc/guides/nics/igc.rst
index 358aec2..389c780 100644
--- a/doc/guides/nics/igc.rst
+++ b/doc/guides/nics/igc.rst
@@ -40,3 +40,38 @@ Foxville LM (I225 LM): Client 2.5G LAN vPro Corporate
Foxville V (I225 V): Client 2.5G LAN Consumer
Foxville I (I225 I): Client 2.5G Industrial Temp
Foxville V (I225 K): Client 2.5G LAN Consumer
+
+
+Sample Application Notes
+------------------------
+
+Vlan filter
+~~~~~~~~~~~
+
+VLAN stripping off only works with inner vlan.
+Only the outer VLAN TPID can be set to a vlan other than 0x8100.
+
+If extend VLAN is enabled:
+
+- The VLAN header in a packet that carries a single VLAN header is treated as the external VLAN.
+
+- Foxville expects that any transmitted packet to have at least the external VLAN added by the
+ software. For those packets where an external VLAN is not present, any offload that relates to
+ inner fields to the EtherType might not be provided.
+
+- If VLAN TX-OFFLOAD is enabled and the packet does not contain an external VLAN, the packet is
+ dropped, and if configured, the queue from which the packet was sent is disabled.
+
+To start ``testpmd``, add vlan 10 to port, set vlan stripping off on, set extend on, set TPID of
+outer VLAN to 0x9100:
+
+.. code-block:: console
+
+ ./app/testpmd -l 4-8 -- -i
+ ...
+
+ testpmd> vlan set filter on 0
+ testpmd> rx_vlan add 10 0
+ testpmd> vlan set strip off 0
+ testpmd> vlan set extend on 0
+ testpmd> vlan set outer tpid 0x9100 0
diff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c
index baef681..e2e427c 100644
--- a/drivers/net/igc/igc_ethdev.c
+++ b/drivers/net/igc/igc_ethdev.c
@@ -50,6 +50,10 @@
/* External VLAN Enable bit mask */
#define IGC_CTRL_EXT_EXT_VLAN (1u << 26)
+/* External VLAN Ether Type bit mask and shift */
+#define IGC_VET_EXT 0xFFFF0000
+#define IGC_VET_EXT_SHIFT 16
+
/* Per Queue Good Packets Received Count */
#define IGC_PQGPRC(idx) (0x10010 + 0x100 * (idx))
/* Per Queue Good Octets Received Count */
@@ -227,6 +231,11 @@ static int eth_igc_rss_hash_update(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
static int eth_igc_rss_hash_conf_get(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf);
+static int
+eth_igc_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on);
+static int eth_igc_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int eth_igc_vlan_tpid_set(struct rte_eth_dev *dev,
+ enum rte_vlan_type vlan_type, uint16_t tpid);
static const struct eth_dev_ops eth_igc_ops = {
.dev_configure = eth_igc_configure,
@@ -279,6 +288,10 @@ static int eth_igc_rss_hash_conf_get(struct rte_eth_dev *dev,
.reta_query = eth_igc_rss_reta_query,
.rss_hash_update = eth_igc_rss_hash_update,
.rss_hash_conf_get = eth_igc_rss_hash_conf_get,
+ .vlan_filter_set = eth_igc_vlan_filter_set,
+ .vlan_offload_set = eth_igc_vlan_offload_set,
+ .vlan_tpid_set = eth_igc_vlan_tpid_set,
+ .vlan_strip_queue_set = eth_igc_vlan_strip_queue_set,
};
/*
@@ -950,6 +963,11 @@ static int eth_igc_rss_hash_conf_get(struct rte_eth_dev *dev,
igc_clear_hw_cntrs_base_generic(hw);
+ /* VLAN Offload Settings */
+ eth_igc_vlan_offload_set(dev,
+ ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK |
+ ETH_VLAN_EXTEND_MASK);
+
/* Setup link speed and duplex */
speeds = &dev->data->dev_conf.link_speeds;
if (*speeds == ETH_LINK_SPEED_AUTONEG) {
@@ -1443,6 +1461,7 @@ static int eth_igc_rss_hash_conf_get(struct rte_eth_dev *dev,
dev_info->max_mac_addrs = hw->mac.rar_entry_count;
dev_info->rx_offload_capa = IGC_RX_OFFLOAD_ALL;
dev_info->tx_offload_capa = IGC_TX_OFFLOAD_ALL;
+ dev_info->rx_queue_offload_capa = DEV_RX_OFFLOAD_VLAN_STRIP;
dev_info->max_rx_queues = IGC_QUEUE_PAIRS_NUM;
dev_info->max_tx_queues = IGC_QUEUE_PAIRS_NUM;
@@ -2359,6 +2378,192 @@ static int eth_igc_rss_hash_conf_get(struct rte_eth_dev *dev,
}
static int
+eth_igc_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+ struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+ struct igc_vfta *shadow_vfta = IGC_DEV_PRIVATE_VFTA(dev);
+ uint32_t vfta;
+ uint32_t vid_idx;
+ uint32_t vid_bit;
+
+ vid_idx = (vlan_id >> IGC_VFTA_ENTRY_SHIFT) & IGC_VFTA_ENTRY_MASK;
+ vid_bit = 1u << (vlan_id & IGC_VFTA_ENTRY_BIT_SHIFT_MASK);
+ vfta = shadow_vfta->vfta[vid_idx];
+ if (on)
+ vfta |= vid_bit;
+ else
+ vfta &= ~vid_bit;
+ IGC_WRITE_REG_ARRAY(hw, IGC_VFTA, vid_idx, vfta);
+
+ /* update local VFTA copy */
+ shadow_vfta->vfta[vid_idx] = vfta;
+
+ return 0;
+}
+
+static void
+igc_vlan_hw_filter_disable(struct rte_eth_dev *dev)
+{
+ struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+ igc_read_reg_check_clear_bits(hw, IGC_RCTL,
+ IGC_RCTL_CFIEN | IGC_RCTL_VFE);
+}
+
+static void
+igc_vlan_hw_filter_enable(struct rte_eth_dev *dev)
+{
+ struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+ struct igc_vfta *shadow_vfta = IGC_DEV_PRIVATE_VFTA(dev);
+ uint32_t reg_val;
+ int i;
+
+ /* Filter Table Enable, CFI not used for packet acceptance */
+ reg_val = IGC_READ_REG(hw, IGC_RCTL);
+ reg_val &= ~IGC_RCTL_CFIEN;
+ reg_val |= IGC_RCTL_VFE;
+ IGC_WRITE_REG(hw, IGC_RCTL, reg_val);
+
+ /* restore VFTA table */
+ for (i = 0; i < IGC_VFTA_SIZE; i++)
+ IGC_WRITE_REG_ARRAY(hw, IGC_VFTA, i, shadow_vfta->vfta[i]);
+}
+
+static void
+igc_vlan_hw_strip_disable(struct rte_eth_dev *dev)
+{
+ struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+
+ igc_read_reg_check_clear_bits(hw, IGC_CTRL, IGC_CTRL_VME);
+}
+
+static void
+igc_vlan_hw_strip_enable(struct rte_eth_dev *dev)
+{
+ struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+
+ igc_read_reg_check_set_bits(hw, IGC_CTRL, IGC_CTRL_VME);
+}
+
+static int
+igc_vlan_hw_extend_disable(struct rte_eth_dev *dev)
+{
+ struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+ uint32_t ctrl_ext;
+
+ ctrl_ext = IGC_READ_REG(hw, IGC_CTRL_EXT);
+
+ /* if extend vlan hasn't been enabled */
+ if ((ctrl_ext & IGC_CTRL_EXT_EXT_VLAN) == 0)
+ return 0;
+
+ if ((dev->data->dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_JUMBO_FRAME) == 0)
+ goto write_ext_vlan;
+
+ /* Update maximum packet length */
+ if (dev->data->dev_conf.rxmode.max_rx_pkt_len <
+ RTE_ETHER_MIN_MTU + VLAN_TAG_SIZE) {
+ PMD_DRV_LOG(ERR, "Maximum packet length %u error, min is %u",
+ dev->data->dev_conf.rxmode.max_rx_pkt_len,
+ VLAN_TAG_SIZE + RTE_ETHER_MIN_MTU);
+ return -EINVAL;
+ }
+ dev->data->dev_conf.rxmode.max_rx_pkt_len -= VLAN_TAG_SIZE;
+ IGC_WRITE_REG(hw, IGC_RLPML,
+ dev->data->dev_conf.rxmode.max_rx_pkt_len);
+
+write_ext_vlan:
+ IGC_WRITE_REG(hw, IGC_CTRL_EXT, ctrl_ext & ~IGC_CTRL_EXT_EXT_VLAN);
+ return 0;
+}
+
+static int
+igc_vlan_hw_extend_enable(struct rte_eth_dev *dev)
+{
+ struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+ uint32_t ctrl_ext;
+
+ ctrl_ext = IGC_READ_REG(hw, IGC_CTRL_EXT);
+
+ /* if extend vlan has been enabled */
+ if (ctrl_ext & IGC_CTRL_EXT_EXT_VLAN)
+ return 0;
+
+ if ((dev->data->dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_JUMBO_FRAME) == 0)
+ goto write_ext_vlan;
+
+ /* Update maximum packet length */
+ if (dev->data->dev_conf.rxmode.max_rx_pkt_len >
+ MAX_RX_JUMBO_FRAME_SIZE - VLAN_TAG_SIZE) {
+ PMD_DRV_LOG(ERR, "Maximum packet length %u error, max is %u",
+ dev->data->dev_conf.rxmode.max_rx_pkt_len +
+ VLAN_TAG_SIZE, MAX_RX_JUMBO_FRAME_SIZE);
+ return -EINVAL;
+ }
+ dev->data->dev_conf.rxmode.max_rx_pkt_len += VLAN_TAG_SIZE;
+ IGC_WRITE_REG(hw, IGC_RLPML,
+ dev->data->dev_conf.rxmode.max_rx_pkt_len);
+
+write_ext_vlan:
+ IGC_WRITE_REG(hw, IGC_CTRL_EXT, ctrl_ext | IGC_CTRL_EXT_EXT_VLAN);
+ return 0;
+}
+
+static int
+eth_igc_vlan_offload_set(struct rte_eth_dev *dev, int mask)
+{
+ struct rte_eth_rxmode *rxmode;
+
+ rxmode = &dev->data->dev_conf.rxmode;
+ if (mask & ETH_VLAN_STRIP_MASK) {
+ if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
+ igc_vlan_hw_strip_enable(dev);
+ else
+ igc_vlan_hw_strip_disable(dev);
+ }
+
+ if (mask & ETH_VLAN_FILTER_MASK) {
+ if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER)
+ igc_vlan_hw_filter_enable(dev);
+ else
+ igc_vlan_hw_filter_disable(dev);
+ }
+
+ if (mask & ETH_VLAN_EXTEND_MASK) {
+ if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_EXTEND)
+ return igc_vlan_hw_extend_enable(dev);
+ else
+ return igc_vlan_hw_extend_disable(dev);
+ }
+
+ return 0;
+}
+
+static int
+eth_igc_vlan_tpid_set(struct rte_eth_dev *dev,
+ enum rte_vlan_type vlan_type,
+ uint16_t tpid)
+{
+ struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+ uint32_t reg_val;
+
+ /* only outer TPID of double VLAN can be configured*/
+ if (vlan_type == ETH_VLAN_TYPE_OUTER) {
+ reg_val = IGC_READ_REG(hw, IGC_VET);
+ reg_val = (reg_val & (~IGC_VET_EXT)) |
+ ((uint32_t)tpid << IGC_VET_EXT_SHIFT);
+ IGC_WRITE_REG(hw, IGC_VET, reg_val);
+
+ return 0;
+ }
+
+ /* all other TPID values are read-only*/
+ PMD_DRV_LOG(ERR, "Not supported");
+ return -ENOTSUP;
+}
+
+static int
eth_igc_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
struct rte_pci_device *pci_dev)
{
diff --git a/drivers/net/igc/igc_ethdev.h b/drivers/net/igc/igc_ethdev.h
index e8fd1b1..4b84127 100644
--- a/drivers/net/igc/igc_ethdev.h
+++ b/drivers/net/igc/igc_ethdev.h
@@ -17,6 +17,10 @@
#endif
#define IGC_RSS_RDT_SIZD 128
+
+/* VLAN filter table size */
+#define IGC_VFTA_SIZE 128
+
#define IGC_QUEUE_PAIRS_NUM 4
#define IGC_HKEY_MAX_INDEX 10
@@ -54,6 +58,9 @@
#define IGC_TX_MAX_MTU_SEG UINT8_MAX
#define IGC_RX_OFFLOAD_ALL ( \
+ DEV_RX_OFFLOAD_VLAN_STRIP | \
+ DEV_RX_OFFLOAD_VLAN_FILTER | \
+ DEV_RX_OFFLOAD_VLAN_EXTEND | \
DEV_RX_OFFLOAD_IPV4_CKSUM | \
DEV_RX_OFFLOAD_UDP_CKSUM | \
DEV_RX_OFFLOAD_TCP_CKSUM | \
@@ -113,6 +120,11 @@ struct igc_hw_queue_stats {
/* per transmit queue drop packet count */
};
+/* local vfta copy */
+struct igc_vfta {
+ uint32_t vfta[IGC_VFTA_SIZE];
+};
+
/*
* Structure to store private data for each driver instance (for each port).
*/
@@ -124,6 +136,7 @@ struct igc_adapter {
int16_t rxq_stats_map[IGC_QUEUE_PAIRS_NUM];
struct igc_interrupt intr;
+ struct igc_vfta shadow_vfta;
bool stopped;
};
@@ -141,6 +154,9 @@ struct igc_adapter {
#define IGC_DEV_PRIVATE_INTR(_dev) \
(&((struct igc_adapter *)(_dev)->data->dev_private)->intr)
+#define IGC_DEV_PRIVATE_VFTA(_dev) \
+ (&((struct igc_adapter *)(_dev)->data->dev_private)->shadow_vfta)
+
static inline void
igc_read_reg_check_set_bits(struct igc_hw *hw, uint32_t reg, uint32_t bits)
{
diff --git a/drivers/net/igc/igc_txrx.c b/drivers/net/igc/igc_txrx.c
index 5ef5b0d..8f78f00 100644
--- a/drivers/net/igc/igc_txrx.c
+++ b/drivers/net/igc/igc_txrx.c
@@ -1162,6 +1162,16 @@ int eth_igc_rx_descriptor_status(void *rx_queue, uint16_t offset)
IGC_WRITE_REG(hw, IGC_RDH(rxq->reg_idx), 0);
IGC_WRITE_REG(hw, IGC_RDT(rxq->reg_idx),
rxq->nb_rx_desc - 1);
+
+ /* strip queue vlan offload */
+ if (rxq->offloads & DEV_RX_OFFLOAD_VLAN_STRIP) {
+ uint32_t dvmolr;
+ dvmolr = IGC_READ_REG(hw, IGC_DVMOLR(rxq->queue_id));
+
+ /* If vlan been stripped off, the CRC is meaningless. */
+ dvmolr |= IGC_DVMOLR_STRVLAN | IGC_DVMOLR_STRCRC;
+ IGC_WRITE_REG(hw, IGC_DVMOLR(rxq->reg_idx), dvmolr);
+ }
}
return 0;
@@ -2107,3 +2117,31 @@ int eth_igc_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx,
qinfo->conf.tx_thresh.wthresh = txq->wthresh;
qinfo->conf.offloads = txq->offloads;
}
+
+void
+eth_igc_vlan_strip_queue_set(struct rte_eth_dev *dev,
+ uint16_t rx_queue_id, int on)
+{
+ struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+ struct igc_rx_queue *rxq = dev->data->rx_queues[rx_queue_id];
+ uint32_t reg_val;
+
+ if (rx_queue_id >= IGC_QUEUE_PAIRS_NUM) {
+ PMD_DRV_LOG(ERR, "Queue index(%u) illegal, max is %u",
+ rx_queue_id, IGC_QUEUE_PAIRS_NUM - 1);
+ return;
+ }
+
+ reg_val = IGC_READ_REG(hw, IGC_DVMOLR(rx_queue_id));
+ if (on) {
+ /* If vlan been stripped off, the CRC is meaningless. */
+ reg_val |= IGC_DVMOLR_STRVLAN | IGC_DVMOLR_STRCRC;
+ rxq->offloads |= DEV_RX_OFFLOAD_VLAN_STRIP;
+ } else {
+ reg_val &= ~(IGC_DVMOLR_STRVLAN | IGC_DVMOLR_HIDVLAN |
+ IGC_DVMOLR_STRCRC);
+ rxq->offloads &= ~DEV_RX_OFFLOAD_VLAN_STRIP;
+ }
+
+ IGC_WRITE_REG(hw, IGC_DVMOLR(rx_queue_id), reg_val);
+}
diff --git a/drivers/net/igc/igc_txrx.h b/drivers/net/igc/igc_txrx.h
index 63b19f5..dbda56c 100644
--- a/drivers/net/igc/igc_txrx.h
+++ b/drivers/net/igc/igc_txrx.h
@@ -44,7 +44,8 @@ void eth_igc_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
struct rte_eth_rxq_info *qinfo);
void eth_igc_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
struct rte_eth_txq_info *qinfo);
-
+void eth_igc_vlan_strip_queue_set(struct rte_eth_dev *dev,
+ uint16_t rx_queue_id, int on);
#ifdef __cplusplus
}
#endif
--
1.8.3.1
next prev parent reply other threads:[~2020-04-15 8:51 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-13 6:30 [dpdk-dev] [PATCH v3 00/11] igc pmd alvinx.zhang
2020-04-13 6:30 ` [dpdk-dev] [PATCH v3 01/11] net/igc: add igc PMD alvinx.zhang
2020-04-13 15:19 ` Stephen Hemminger
2020-04-15 8:47 ` [dpdk-dev] [PATCH v4 00/11] " alvinx.zhang
2020-04-15 8:48 ` [dpdk-dev] [PATCH v4 01/11] net/igc: add " alvinx.zhang
2020-04-15 8:48 ` [dpdk-dev] [PATCH v4 02/11] net/igc: support device initialization alvinx.zhang
2020-04-15 8:48 ` [dpdk-dev] [PATCH v4 03/11] net/igc: implement device base ops alvinx.zhang
2020-04-15 8:48 ` [dpdk-dev] [PATCH v4 04/11] net/igc: support reception and transmission of packets alvinx.zhang
2020-04-15 8:48 ` [dpdk-dev] [PATCH v4 05/11] net/igc: enable statistics alvinx.zhang
2020-04-15 8:48 ` [dpdk-dev] [PATCH v4 06/11] net/igc: enable Rx queue interrupts alvinx.zhang
2020-04-15 8:48 ` [dpdk-dev] [PATCH v4 07/11] net/igc: implement flow control ops alvinx.zhang
2020-04-15 8:48 ` [dpdk-dev] [PATCH v4 08/11] net/igc: implement RSS API alvinx.zhang
2020-04-15 8:48 ` alvinx.zhang [this message]
2020-04-15 8:48 ` [dpdk-dev] [PATCH v4 10/11] net/igc: implement MAC-loopback mode alvinx.zhang
2020-04-15 8:48 ` [dpdk-dev] [PATCH v4 11/11] net/igc: implement flow API alvinx.zhang
2020-04-15 11:14 ` [dpdk-dev] [PATCH v4 00/11] igc PMD Ferruh Yigit
2020-04-13 6:30 ` [dpdk-dev] [PATCH v3 02/11] net/igc: support device initialization alvinx.zhang
2020-04-13 6:30 ` [dpdk-dev] [PATCH v3 03/11] net/igc: implement device base ops alvinx.zhang
2020-04-13 15:23 ` Stephen Hemminger
2020-04-13 6:30 ` [dpdk-dev] [PATCH v3 04/11] net/igc: support reception and transmission of packets alvinx.zhang
2020-04-13 6:30 ` [dpdk-dev] [PATCH v3 05/11] net/igc: enable statistics alvinx.zhang
2020-04-13 6:30 ` [dpdk-dev] [PATCH v3 06/11] net/igc: enable Rx queue interrupts alvinx.zhang
2020-04-13 6:30 ` [dpdk-dev] [PATCH v3 07/11] net/igc: implement flow control ops alvinx.zhang
2020-04-13 6:30 ` [dpdk-dev] [PATCH v3 08/11] net/igc: implement RSS API alvinx.zhang
2020-04-13 6:30 ` [dpdk-dev] [PATCH v3 09/11] net/igc: implement feature of VLAN alvinx.zhang
2020-04-13 6:30 ` [dpdk-dev] [PATCH v3 10/11] net/igc: implement MAC-loopback mode alvinx.zhang
2020-04-13 6:30 ` [dpdk-dev] [PATCH v3 11/11] net/igc: implement flow API alvinx.zhang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200415084810.20816-10-alvinx.zhang@intel.com \
--to=alvinx.zhang@intel.com \
--cc=dev@dpdk.org \
--cc=xiaolong.ye@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).