* Re: [PATCH 0/4] eal/common: introduce rte_memset and related test
From: Maxime Coquelin @ 2016-12-02 10:00 UTC (permalink / raw)
To: Zhiyong Yang, dev; +Cc: yuanhan.liu, bruce.richardson, konstantin.ananyev
In-Reply-To: <1480926387-63838-1-git-send-email-zhiyong.yang@intel.com>
Hi Zhiyong,
On 12/05/2016 09:26 AM, Zhiyong Yang wrote:
> DPDK code has met performance drop badly in some case when calling glibc
> function memset. Reference to discussions about memset in
> http://dpdk.org/ml/archives/dev/2016-October/048628.html
> It is necessary to introduce more high efficient function to fix it.
> One important thing about rte_memset is that we can get clear control
> on what instruction flow is used.
>
> This patchset introduces rte_memset to bring more high efficient
> implementation, and will bring obvious perf improvement, especially
> for small N bytes in the most application scenarios.
>
> Patch 1 implements rte_memset in the file rte_memset.h on IA platform
> The file supports three types of instruction sets including sse & avx
> (128bits), avx2(256bits) and avx512(512bits). rte_memset makes use of
> vectorization and inline function to improve the perf on IA. In addition,
> cache line and memory alignment are fully taken into consideration.
>
> Patch 2 implements functional autotest to validates the function whether
> to work in a right way.
>
> Patch 3 implements performance autotest separately in cache and memory.
>
> Patch 4 Using rte_memset instead of copy_virtio_net_hdr can bring 3%~4%
> performance improvements on IA platform from virtio/vhost non-mergeable
> loopback testing.
>
> Zhiyong Yang (4):
> eal/common: introduce rte_memset on IA platform
> app/test: add functional autotest for rte_memset
> app/test: add performance autotest for rte_memset
> lib/librte_vhost: improve vhost perf using rte_memset
>
> app/test/Makefile | 3 +
> app/test/test_memset.c | 158 +++++++++
> app/test/test_memset_perf.c | 348 +++++++++++++++++++
> doc/guides/rel_notes/release_17_02.rst | 11 +
> .../common/include/arch/x86/rte_memset.h | 376 +++++++++++++++++++++
> lib/librte_eal/common/include/generic/rte_memset.h | 51 +++
> lib/librte_vhost/virtio_net.c | 18 +-
> 7 files changed, 958 insertions(+), 7 deletions(-)
> create mode 100644 app/test/test_memset.c
> create mode 100644 app/test/test_memset_perf.c
> create mode 100644 lib/librte_eal/common/include/arch/x86/rte_memset.h
> create mode 100644 lib/librte_eal/common/include/generic/rte_memset.h
>
Thanks for the series, idea looks good to me.
Wouldn't be worth to also use rte_memset in Virtio PMD (not
compiled/tested)? :
diff --git a/drivers/net/virtio/virtio_rxtx.c
b/drivers/net/virtio/virtio_rxtx.c
index 22d97a4..a5f70c4 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -287,7 +287,7 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq,
struct rte_mbuf *cookie,
rte_pktmbuf_prepend(cookie, head_size);
/* if offload disabled, it is not zeroed below, do it
now */
if (offload == 0)
- memset(hdr, 0, head_size);
+ rte_memset(hdr, 0, head_size);
} else if (use_indirect) {
/* setup tx ring slot to point to indirect
* descriptor list stored in reserved region.
Cheers,
Maxime
^ permalink raw reply related
* [PATCH 2/2] crypto/aesni_mb: add new option to select SIMD mode
From: Declan Doherty @ 2016-12-02 9:46 UTC (permalink / raw)
To: dev; +Cc: Declan Doherty
In-Reply-To: <1480671985-3677-1-git-send-email-declan.doherty@intel.com>
Add new initialisation option to the aesni_mb_pmd to allow the user to specify
which set of SIMD functions to load from the AESNI Multi-Buffer Crypto for IPsec
library.
Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c | 141 ++++++++++++++++++---
drivers/crypto/aesni_mb/rte_aesni_mb_pmd_private.h | 7 +
2 files changed, 129 insertions(+), 19 deletions(-)
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
index c400b17..70b1d20 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
@@ -594,17 +594,16 @@ aesni_mb_pmd_dequeue_burst(void *queue_pair, struct rte_crypto_op **ops,
return nb_dequeued;
}
-
static int cryptodev_aesni_mb_remove(const char *name);
static int
cryptodev_aesni_mb_create(const char *name,
- struct rte_crypto_vdev_init_params *init_params)
+ struct rte_crypto_vdev_init_params *init_params,
+ struct aesni_mb_init_params *aesni_mb_init_params)
{
struct rte_cryptodev *dev;
char crypto_dev_name[RTE_CRYPTODEV_NAME_MAX_LEN];
struct aesni_mb_private *internals;
- enum aesni_mb_vector_mode vector_mode;
/* Check CPU for support for AES instruction set */
if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_AES)) {
@@ -612,18 +611,50 @@ cryptodev_aesni_mb_create(const char *name,
return -EFAULT;
}
- /* Check CPU for supported vector instruction set */
- if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F))
- vector_mode = RTE_AESNI_MB_AVX512;
- else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
- vector_mode = RTE_AESNI_MB_AVX2;
- else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX))
- vector_mode = RTE_AESNI_MB_AVX;
- else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE4_1))
- vector_mode = RTE_AESNI_MB_SSE;
- else {
- MB_LOG_ERR("Vector instructions are not supported by CPU");
- return -EFAULT;
+
+ switch(aesni_mb_init_params->mode) {
+ case RTE_AESNI_MB_AVX512:
+ if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F)) {
+ MB_LOG_ERR("specified instruction set AVX512 "
+ "not supported by CPU");
+ return -EFAULT;
+ }
+ break;
+ case RTE_AESNI_MB_AVX2:
+ if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2)) {
+ MB_LOG_ERR("specified instruction set AVX2 "
+ "not supported by CPU");
+ return -EFAULT;
+ }
+ break;
+ case RTE_AESNI_MB_AVX:
+ if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX)) {
+ MB_LOG_ERR("specified instruction set AVX "
+ "not supported by CPU");
+ return -EFAULT;
+ }
+ break;
+ case RTE_AESNI_MB_SSE:
+ if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE4_1)) {
+ MB_LOG_ERR("specified instruction set SSE "
+ "not supported by CPU");
+ return -EFAULT;
+ }
+ break;
+ default:
+ /* Check CPU for supported vector instruction set */
+ if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F))
+ aesni_mb_init_params->mode = RTE_AESNI_MB_AVX512;
+ else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
+ aesni_mb_init_params->mode = RTE_AESNI_MB_AVX2;
+ else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX))
+ aesni_mb_init_params->mode = RTE_AESNI_MB_AVX;
+ else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE4_1))
+ aesni_mb_init_params->mode = RTE_AESNI_MB_SSE;
+ else {
+ MB_LOG_ERR("Vector instructions are not supported by CPU");
+ return -EFAULT;
+ }
}
/* create a unique device name */
@@ -652,7 +683,7 @@ cryptodev_aesni_mb_create(const char *name,
RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING |
RTE_CRYPTODEV_FF_CPU_AESNI;
- switch (vector_mode) {
+ switch (aesni_mb_init_params->mode) {
case RTE_AESNI_MB_SSE:
dev->feature_flags |= RTE_CRYPTODEV_FF_CPU_SSE;
break;
@@ -672,7 +703,7 @@ cryptodev_aesni_mb_create(const char *name,
/* Set vector instructions mode supported */
internals = dev->data->dev_private;
- internals->vector_mode = vector_mode;
+ internals->vector_mode = aesni_mb_init_params->mode;
internals->max_nb_queue_pairs = init_params->max_nb_queue_pairs;
internals->max_nb_sessions = init_params->max_nb_sessions;
@@ -684,18 +715,90 @@ cryptodev_aesni_mb_create(const char *name,
return -EFAULT;
}
+static int
+parse_simd_mode_option(const char *key __rte_unused,
+ const char *value, void *extra_args)
+{
+ int retval = -1;
+
+ enum aesni_mb_vector_mode *mode =
+ (enum aesni_mb_vector_mode *)extra_args;
+
+ if (strcmp("avx512", value) == 0) {
+ *mode = RTE_AESNI_MB_AVX512;
+ retval = 0;
+ }
+ else if (strcmp("avx2", value) == 0) {
+ *mode = RTE_AESNI_MB_AVX2;
+ retval = 0;
+ }
+ else if (strcmp("avx", value) == 0) {
+ *mode = RTE_AESNI_MB_AVX;
+ retval = 0;
+ }
+ else if (strcmp("sse", value) == 0) {
+ *mode = RTE_AESNI_MB_SSE;
+ retval = 0;
+ }
+
+ return retval;
+}
+
+static const char *cryptodev_vdev_valid_params[] = {
+ AESNI_MB_PMD_SIMD_MODE_ARG
+};
+
+static int
+aesni_mb_parse_init_params(struct aesni_mb_init_params *params,
+ const char *input_args)
+{
+ struct rte_kvargs *kvlist = NULL;
+ int ret = 0;
+
+ if (params == NULL)
+ return -EINVAL;
+
+ if (input_args) {
+ kvlist = rte_kvargs_parse(input_args,
+ cryptodev_vdev_valid_params);
+ if (kvlist == NULL)
+ return -1;
+
+ ret = rte_kvargs_process(kvlist,
+ AESNI_MB_PMD_SIMD_MODE_ARG,
+ &parse_simd_mode_option,
+ ¶ms->mode);
+ if (ret < 0)
+ goto free_kvlist;
+ }
+
+free_kvlist:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
static int
cryptodev_aesni_mb_probe(const char *name,
const char *input_args)
{
+ int retval;
+ struct aesni_mb_init_params aesni_mb_init_params = {
+ RTE_AESNI_MB_NOT_SUPPORTED
+ };
struct rte_crypto_vdev_init_params init_params = {
RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS,
RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS,
rte_socket_id()
};
- rte_cryptodev_parse_vdev_init_params(&init_params, input_args);
+ retval = rte_cryptodev_parse_vdev_init_params(&init_params, input_args);
+ if (retval)
+ RTE_LOG(ERR, PMD, "Failed to parse default init params\n");
+
+ retval = aesni_mb_parse_init_params(&aesni_mb_init_params, input_args);
+ if (retval)
+ RTE_LOG(ERR, PMD, "Failed to parse aesni mb init params\n");
RTE_LOG(INFO, PMD, "Initialising %s on NUMA node %d\n", name,
init_params.socket_id);
@@ -704,7 +807,7 @@ cryptodev_aesni_mb_probe(const char *name,
RTE_LOG(INFO, PMD, " Max number of sessions = %d\n",
init_params.max_nb_sessions);
- return cryptodev_aesni_mb_create(name, &init_params);
+ return cryptodev_aesni_mb_create(name, &init_params, &aesni_mb_init_params);
}
static int
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_private.h b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_private.h
index 17f367f..aea5da1 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_private.h
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_private.h
@@ -225,5 +225,12 @@ aesni_mb_set_session_parameters(const struct aesni_mb_ops *mb_ops,
extern struct rte_cryptodev_ops *rte_aesni_mb_pmd_ops;
+#define AESNI_MB_PMD_SIMD_MODE_ARG ("simd-mode")
+
+/** Device specific initialisation parameters */
+struct aesni_mb_init_params {
+ enum aesni_mb_vector_mode mode;
+};
+
#endif /* _RTE_AESNI_MB_PMD_PRIVATE_H_ */
--
2.5.5
^ permalink raw reply related
* [PATCH 1/2] crypto/aesni_mb: enablement of avx512 support in IPsec_mb library
From: Declan Doherty @ 2016-12-02 9:46 UTC (permalink / raw)
To: dev; +Cc: Declan Doherty
In-Reply-To: <1480671985-3677-1-git-send-email-declan.doherty@intel.com>
Release v0.44 of Intel(R) Multi-Buffer Crypto for IPsec library adds support for
AVX512 instructions. This patch enables the new AVX512 accelerated functions
from the aesni_mb_pmd crypto poll mode driver.
This patch set requires that the aesni_mb_pmd is linked against the version 0.44
or greater of the Multi-Buffer Crypto for IPsec library.
Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
drivers/crypto/aesni_mb/aesni_mb_ops.h | 28 +++++++++++++++++++++++++++-
drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c | 7 ++++++-
lib/librte_cryptodev/rte_cryptodev.h | 2 ++
3 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/drivers/crypto/aesni_mb/aesni_mb_ops.h b/drivers/crypto/aesni_mb/aesni_mb_ops.h
index 0c119bf..2d41d73 100644
--- a/drivers/crypto/aesni_mb/aesni_mb_ops.h
+++ b/drivers/crypto/aesni_mb/aesni_mb_ops.h
@@ -44,7 +44,8 @@ enum aesni_mb_vector_mode {
RTE_AESNI_MB_NOT_SUPPORTED = 0,
RTE_AESNI_MB_SSE,
RTE_AESNI_MB_AVX,
- RTE_AESNI_MB_AVX2
+ RTE_AESNI_MB_AVX2,
+ RTE_AESNI_MB_AVX512
};
typedef void (*md5_one_block_t)(void *data, void *digest);
@@ -203,6 +204,31 @@ static const struct aesni_mb_ops job_ops[] = {
aes_xcbc_expand_key_avx2
}
}
+ },
+ [RTE_AESNI_MB_AVX512] = {
+ .job = {
+ init_mb_mgr_avx512,
+ get_next_job_avx512,
+ submit_job_avx512,
+ get_completed_job_avx512,
+ flush_job_avx512
+ },
+ .aux = {
+ .one_block = {
+ md5_one_block_avx512,
+ sha1_one_block_avx512,
+ sha224_one_block_avx512,
+ sha256_one_block_avx512,
+ sha384_one_block_avx512,
+ sha512_one_block_avx512
+ },
+ .keyexp = {
+ aes_keyexp_128_avx512,
+ aes_keyexp_192_avx512,
+ aes_keyexp_256_avx512,
+ aes_xcbc_expand_key_avx512
+ }
+ }
}
};
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
index f07cd07..c400b17 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
@@ -613,7 +613,9 @@ cryptodev_aesni_mb_create(const char *name,
}
/* Check CPU for supported vector instruction set */
- if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
+ if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F))
+ vector_mode = RTE_AESNI_MB_AVX512;
+ else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
vector_mode = RTE_AESNI_MB_AVX2;
else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX))
vector_mode = RTE_AESNI_MB_AVX;
@@ -660,6 +662,9 @@ cryptodev_aesni_mb_create(const char *name,
case RTE_AESNI_MB_AVX2:
dev->feature_flags |= RTE_CRYPTODEV_FF_CPU_AVX2;
break;
+ case RTE_AESNI_MB_AVX512:
+ dev->feature_flags |= RTE_CRYPTODEV_FF_CPU_AVX512;
+ break;
default:
break;
}
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 8f63e8f..29d8eec 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -225,6 +225,8 @@ struct rte_cryptodev_capabilities {
/**< Utilises CPU AES-NI instructions */
#define RTE_CRYPTODEV_FF_HW_ACCELERATED (1ULL << 7)
/**< Operations are off-loaded to an external hardware accelerator */
+#define RTE_CRYPTODEV_FF_CPU_AVX512 (1ULL << 8)
+/**< Utilises CPU SIMD AVX512 instructions */
/**
--
2.5.5
^ permalink raw reply related
* [PATCH 0/2] enablement of avx512 instruction support in aesni_mb_pmd
From: Declan Doherty @ 2016-12-02 9:46 UTC (permalink / raw)
To: dev; +Cc: Declan Doherty
In patchset "AESNI MB PMD updates"
(http://dpdk.org/ml/archives/dev/2016-December/050976.html) the AESNI
Multi-Buffer Crypto for IPsec library which the aesni_mb_pmd depends on is
updated to v0.44
The first patch in this patchset enables support for the AVX512 accelerated
functions added in the new version of the library to the aesni_mb_pmd.
The second patch add a new initialisation option which allows the user to
explicitly select which set of SIMD functions to use from the base library.
Declan Doherty (2):
crypto/aesni_mb: enablement of avx512 support in IPsec_mb library
crypto/aesni_mb: add new option to select SIMD mode
drivers/crypto/aesni_mb/aesni_mb_ops.h | 28 +++-
drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c | 142 ++++++++++++++++++---
drivers/crypto/aesni_mb/rte_aesni_mb_pmd_private.h | 7 +
lib/librte_cryptodev/rte_cryptodev.h | 2 +
4 files changed, 161 insertions(+), 18 deletions(-)
--
2.5.5
^ permalink raw reply
* Re: [PATCH 4/4] lib/librte_vhost: improve vhost perf using rte_memset
From: Thomas Monjalon @ 2016-12-02 9:46 UTC (permalink / raw)
To: Zhiyong Yang; +Cc: dev, yuanhan.liu, bruce.richardson, konstantin.ananyev
In-Reply-To: <1480926387-63838-5-git-send-email-zhiyong.yang@intel.com>
2016-12-05 16:26, Zhiyong Yang:
> +* **Introduced rte_memset and related test on IA platform.**
> +
> + Performance drop had been caused in some cases on Ivybridge when DPDK code calls glibc
> + function memset. It was necessary to introduce more high efficient function to fix it.
> + The function rte_memset supported three types of instruction sets including sse & avx(128 bits),
> + avx2(256 bits) and avx512(512bits).
> +
> + * Added rte_memset support on IA platform.
> + * Added functional autotest support for rte_memset.
> + * Added performance autotest support for rte_memset.
No need to reference autotests in the release notes.
> + * Improved performance to use rte_memset instead of copy_virtio_net_hdr in lib/librte_vhost.
Please describe this change at a higher level. Which case it is improving?
^ permalink raw reply
* [PATCH v3] nfp: report link speed using hardware info
From: Alejandro Lucero @ 2016-12-02 9:05 UTC (permalink / raw)
To: dev
Previous reported speed was hardcoded.
v3: remove unsed macro
v2: using RTE_DIM instead of own macro
Signed-off-by: Alejandro Lucero <alejandro.lucero@netronome.com>
---
drivers/net/nfp/nfp_net.c | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index c6b1587..24f3164 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -816,6 +816,17 @@ static void nfp_net_read_mac(struct nfp_net_hw *hw)
struct rte_eth_link link, old;
uint32_t nn_link_status;
+ static const uint32_t ls_to_ethtool[] = {
+ [NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED] = ETH_SPEED_NUM_NONE,
+ [NFP_NET_CFG_STS_LINK_RATE_UNKNOWN] = ETH_SPEED_NUM_NONE,
+ [NFP_NET_CFG_STS_LINK_RATE_1G] = ETH_SPEED_NUM_1G,
+ [NFP_NET_CFG_STS_LINK_RATE_10G] = ETH_SPEED_NUM_10G,
+ [NFP_NET_CFG_STS_LINK_RATE_25G] = ETH_SPEED_NUM_25G,
+ [NFP_NET_CFG_STS_LINK_RATE_40G] = ETH_SPEED_NUM_40G,
+ [NFP_NET_CFG_STS_LINK_RATE_50G] = ETH_SPEED_NUM_50G,
+ [NFP_NET_CFG_STS_LINK_RATE_100G] = ETH_SPEED_NUM_100G,
+ };
+
PMD_DRV_LOG(DEBUG, "Link update\n");
hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
@@ -831,8 +842,21 @@ static void nfp_net_read_mac(struct nfp_net_hw *hw)
link.link_status = ETH_LINK_UP;
link.link_duplex = ETH_LINK_FULL_DUPLEX;
- /* Other cards can limit the tx and rx rate per VF */
- link.link_speed = ETH_SPEED_NUM_40G;
+
+ nn_link_status = (nn_link_status >> NFP_NET_CFG_STS_LINK_RATE_SHIFT) &
+ NFP_NET_CFG_STS_LINK_RATE_MASK;
+
+ if ((NFD_CFG_MAJOR_VERSION_of(hw->ver) < 4) ||
+ ((NFD_CFG_MINOR_VERSION_of(hw->ver) == 4) &&
+ (NFD_CFG_MINOR_VERSION_of(hw->ver) == 0)))
+ link.link_speed = ETH_SPEED_NUM_40G;
+ else {
+ if (nn_link_status == NFP_NET_CFG_STS_LINK_RATE_UNKNOWN ||
+ nn_link_status >= RTE_DIM(ls_to_ethtool))
+ link.link_speed = ETH_SPEED_NUM_NONE;
+ else
+ link.link_speed = ls_to_ethtool[nn_link_status];
+ }
if (old.link_status != link.link_status) {
nfp_net_dev_atomic_write_link_status(dev, &link);
--
1.9.1
^ permalink raw reply related
* Re: [PATCH 00/31] Support VFD and DPDK PF + kernel VF on i40e
From: Andrew Rybchenko @ 2016-12-02 8:59 UTC (permalink / raw)
To: Wenzhuo Lu, dev
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
On 12/02/2016 03:11 AM, Wenzhuo Lu wrote:
> 1, VF Daemon (VFD)
> VFD is an idea to control all the VFs from PF.
> As we need to support the scenario kernel PF + DPDK VF, DPDK follows the interface
> between kernel PF + kernel VF. We don't want to introduce too many new messages
> between PF and VF. So this patch set adds some new APIs to control VFs directly
> from PF.
> The new APIs include,
> 1) set VF MAC anti-spoofing
> 2) set VF VLAN anti-spoofing
> 3) set TX loopback
> 4) set VF unicast promiscuous mode
> 5) set VF multicast promiscuous mode
> 6) set VF MTU
> 7) get/reset VF stats
> 8) set VF MAC address
> 9) set VF VLAN stripping
> 10) VF VLAN insertion
> 12) set VF broadcast mode
> 12) set VF VLAN tag
> 13) set VF VLAN filter
> VFD also includes VF to PF mailbox message management by APP. When PF receives mailbox
> messages from VF, PF should call the callback provided by APP to know if they're
> permitted to be processed.
The patch series adds i40e-specific API functions for VF control (advertise link
status change, MAC anti-spoofing, VLAN anti-spoofing, promiscuous mode, MAC change,
VLAN controls), but RTE API is added to get VF stats. I'm wondering why.
Corresponding patches do not explain why i40e-specific API is added instead of
generic RTE API. IMHO, it is hardly convenient for applications.
(I guess it was a discussion and decision, but I've failed to find in the archive).
Andrew.
^ permalink raw reply
* [PATCH 4/4] lib/librte_vhost: improve vhost perf using rte_memset
From: Zhiyong Yang @ 2016-12-02 8:36 UTC (permalink / raw)
To: dev; +Cc: yuanhan.liu, bruce.richardson, konstantin.ananyev, Zhiyong Yang
In-Reply-To: <1480926387-63838-1-git-send-email-zhiyong.yang@intel.com>
Using rte_memset instead of copy_virtio_net_hdr can bring 3%~4%
performance improvements on IA platform from virtio/vhost
non-mergeable loopback testing.
Two key points have been considered:
1. One variable initialization could be saved, which involves memory
store.
2. copy_virtio_net_hdr involves both load (from stack, the virtio_hdr
var) and store (to virtio driver memory), while rte_memset just involves
store.
Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
---
doc/guides/rel_notes/release_17_02.rst | 11 +++++++++++
lib/librte_vhost/virtio_net.c | 18 +++++++++++-------
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/doc/guides/rel_notes/release_17_02.rst b/doc/guides/rel_notes/release_17_02.rst
index 3b65038..eecf857 100644
--- a/doc/guides/rel_notes/release_17_02.rst
+++ b/doc/guides/rel_notes/release_17_02.rst
@@ -38,6 +38,17 @@ New Features
Also, make sure to start the actual text at the margin.
=========================================================
+* **Introduced rte_memset and related test on IA platform.**
+
+ Performance drop had been caused in some cases on Ivybridge when DPDK code calls glibc
+ function memset. It was necessary to introduce more high efficient function to fix it.
+ The function rte_memset supported three types of instruction sets including sse & avx(128 bits),
+ avx2(256 bits) and avx512(512bits).
+
+ * Added rte_memset support on IA platform.
+ * Added functional autotest support for rte_memset.
+ * Added performance autotest support for rte_memset.
+ * Improved performance to use rte_memset instead of copy_virtio_net_hdr in lib/librte_vhost.
Resolved Issues
---------------
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
index 595f67c..392b31b 100644
--- a/lib/librte_vhost/virtio_net.c
+++ b/lib/librte_vhost/virtio_net.c
@@ -37,6 +37,7 @@
#include <rte_mbuf.h>
#include <rte_memcpy.h>
+#include <rte_memset.h>
#include <rte_ether.h>
#include <rte_ip.h>
#include <rte_virtio_net.h>
@@ -194,7 +195,7 @@ copy_mbuf_to_desc(struct virtio_net *dev, struct vring_desc *descs,
uint32_t cpy_len;
struct vring_desc *desc;
uint64_t desc_addr;
- struct virtio_net_hdr_mrg_rxbuf virtio_hdr = {{0, 0, 0, 0, 0, 0}, 0};
+ struct virtio_net_hdr *virtio_hdr;
desc = &descs[desc_idx];
desc_addr = gpa_to_vva(dev, desc->addr);
@@ -208,8 +209,9 @@ copy_mbuf_to_desc(struct virtio_net *dev, struct vring_desc *descs,
rte_prefetch0((void *)(uintptr_t)desc_addr);
- virtio_enqueue_offload(m, &virtio_hdr.hdr);
- copy_virtio_net_hdr(dev, desc_addr, virtio_hdr);
+ virtio_hdr = (struct virtio_net_hdr *)(uintptr_t)desc_addr;
+ rte_memset(virtio_hdr, 0, sizeof(*virtio_hdr));
+ virtio_enqueue_offload(m, virtio_hdr);
vhost_log_write(dev, desc->addr, dev->vhost_hlen);
PRINT_PACKET(dev, (uintptr_t)desc_addr, dev->vhost_hlen, 0);
@@ -459,7 +461,6 @@ static inline int __attribute__((always_inline))
copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct rte_mbuf *m,
struct buf_vector *buf_vec, uint16_t num_buffers)
{
- struct virtio_net_hdr_mrg_rxbuf virtio_hdr = {{0, 0, 0, 0, 0, 0}, 0};
uint32_t vec_idx = 0;
uint64_t desc_addr;
uint32_t mbuf_offset, mbuf_avail;
@@ -480,7 +481,6 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct rte_mbuf *m,
hdr_phys_addr = buf_vec[vec_idx].buf_addr;
rte_prefetch0((void *)(uintptr_t)hdr_addr);
- virtio_hdr.num_buffers = num_buffers;
LOG_DEBUG(VHOST_DATA, "(%d) RX: num merge buffers %d\n",
dev->vid, num_buffers);
@@ -512,8 +512,12 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct rte_mbuf *m,
}
if (hdr_addr) {
- virtio_enqueue_offload(hdr_mbuf, &virtio_hdr.hdr);
- copy_virtio_net_hdr(dev, hdr_addr, virtio_hdr);
+ struct virtio_net_hdr_mrg_rxbuf *hdr =
+ (struct virtio_net_hdr_mrg_rxbuf *)(uintptr_t)hdr_addr;
+
+ rte_memset(&(hdr->hdr), 0, sizeof(hdr->hdr));
+ hdr->num_buffers = num_buffers;
+ virtio_enqueue_offload(hdr_mbuf, &(hdr->hdr));
vhost_log_write(dev, hdr_phys_addr, dev->vhost_hlen);
PRINT_PACKET(dev, (uintptr_t)hdr_addr,
dev->vhost_hlen, 0);
--
2.7.4
^ permalink raw reply related
* [PATCH 3/4] app/test: add performance autotest for rte_memset
From: Zhiyong Yang @ 2016-12-02 8:36 UTC (permalink / raw)
To: dev; +Cc: yuanhan.liu, bruce.richardson, konstantin.ananyev, Zhiyong Yang
In-Reply-To: <1480926387-63838-1-git-send-email-zhiyong.yang@intel.com>
The file implements the perf autotest for rte_memset. The perf data
can be gotten compared between memset and rte_memset when you run it.
The first column shows the N size for memset.
The second column lists a set of numbers for memset in cache,
The third column lists a set of numbers for memset in memory.
Usage:
step 1: run ./x86_64-native-linuxapp-gcc/app/test
step 2: run command memset_perf_autotest at the run time.
Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
---
app/test/Makefile | 1 +
app/test/test_memset_perf.c | 348 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 349 insertions(+)
create mode 100644 app/test/test_memset_perf.c
diff --git a/app/test/Makefile b/app/test/Makefile
index 82da3f3..1c3e7f1 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -124,6 +124,7 @@ SRCS-y += test_memcpy.c
SRCS-y += test_memcpy_perf.c
SRCS-y += test_memset.c
+SRCS-y += test_memset_perf.c
SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash.c
SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_thash.c
diff --git a/app/test/test_memset_perf.c b/app/test/test_memset_perf.c
new file mode 100644
index 0000000..83b15b5
--- /dev/null
+++ b/app/test/test_memset_perf.c
@@ -0,0 +1,348 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_random.h>
+#include <rte_malloc.h>
+#include <rte_memset.h>
+#include "test.h"
+
+/*
+ * Set this to the maximum buffer size you want to test. If it is 0, then the
+ * values in the buf_sizes[] array below will be used.
+ */
+#define TEST_VALUE_RANGE 0
+
+/* List of buffer sizes to test */
+#if TEST_VALUE_RANGE == 0
+static size_t buf_sizes[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 15, 16, 17, 31, 32, 33, 63, 64, 65,
+ 70, 85, 96, 105, 115, 127, 128, 129, 161, 191, 192, 193, 255, 256,
+ 257, 319, 320, 321, 383, 384, 385, 447, 448, 449, 511, 512, 513,
+ 767, 768, 769, 1023, 1024, 1025, 1518, 1522, 1536, 1600, 2048, 2560,
+ 3072, 3584, 4096, 4608, 5120, 5632, 6144, 6656, 7168, 7680, 8192
+};
+/* MUST be as large as largest packet size above */
+#define SMALL_BUFFER_SIZE 8192
+#else /* TEST_VALUE_RANGE != 0 */
+static size_t buf_sizes[TEST_VALUE_RANGE];
+#define SMALL_BUFFER_SIZE TEST_VALUE_RANGE
+#endif /* TEST_VALUE_RANGE == 0 */
+
+/*
+ * Arrays of this size are used for measuring uncached memory accesses by
+ * picking a random location within the buffer. Make this smaller if there are
+ * memory allocation errors.
+ */
+#define LARGE_BUFFER_SIZE (100 * 1024 * 1024)
+
+/* How many times to run timing loop for performance tests */
+#define TEST_ITERATIONS 1000000
+#define TEST_BATCH_SIZE 100
+
+/* Data is aligned on this many bytes (power of 2) */
+#ifdef RTE_MACHINE_CPUFLAG_AVX512F
+#define ALIGNMENT_UNIT 64
+#elif defined RTE_MACHINE_CPUFLAG_AVX2
+#define ALIGNMENT_UNIT 32
+#else /* RTE_MACHINE_CPUFLAG */
+#define ALIGNMENT_UNIT 16
+#endif /* RTE_MACHINE_CPUFLAG */
+
+/*
+ * Pointers used in performance tests. The two large buffers are for uncached
+ * access where random addresses within the buffer are used for each
+ * memset. The two small buffers are for cached access.
+ */
+static uint8_t *large_buf_read, *large_buf_write;
+static uint8_t *small_buf_read, *small_buf_write;
+
+/* Initialise data buffers. */
+static int
+init_buffers(void)
+{
+ unsigned int i;
+
+ large_buf_read = rte_malloc("memset", LARGE_BUFFER_SIZE
+ + ALIGNMENT_UNIT, ALIGNMENT_UNIT);
+ if (large_buf_read == NULL)
+ goto error_large_buf_read;
+
+ large_buf_write = rte_malloc("memset", LARGE_BUFFER_SIZE
+ + ALIGNMENT_UNIT, ALIGNMENT_UNIT);
+ if (large_buf_write == NULL)
+ goto error_large_buf_write;
+
+ small_buf_read = rte_malloc("memset", SMALL_BUFFER_SIZE
+ + ALIGNMENT_UNIT, ALIGNMENT_UNIT);
+ if (small_buf_read == NULL)
+ goto error_small_buf_read;
+
+ small_buf_write = rte_malloc("memset", SMALL_BUFFER_SIZE
+ + ALIGNMENT_UNIT, ALIGNMENT_UNIT);
+ if (small_buf_write == NULL)
+ goto error_small_buf_write;
+
+ for (i = 0; i < LARGE_BUFFER_SIZE; i++)
+ large_buf_read[i] = rte_rand();
+ for (i = 0; i < SMALL_BUFFER_SIZE; i++)
+ small_buf_read[i] = rte_rand();
+
+ return 0;
+
+error_small_buf_write:
+ rte_free(small_buf_read);
+error_small_buf_read:
+ rte_free(large_buf_write);
+error_large_buf_write:
+ rte_free(large_buf_read);
+error_large_buf_read:
+ printf("ERROR: not enough memory\n");
+ return -1;
+}
+
+/* Cleanup data buffers */
+static void
+free_buffers(void)
+{
+ rte_free(large_buf_read);
+ rte_free(large_buf_write);
+ rte_free(small_buf_read);
+ rte_free(small_buf_write);
+}
+
+/*
+ * Get a random offset into large array, with enough space needed to perform
+ * max memset size. Offset is aligned, uoffset is used for unalignment setting.
+ */
+static inline size_t
+get_rand_offset(size_t uoffset)
+{
+ return ((rte_rand() % (LARGE_BUFFER_SIZE - SMALL_BUFFER_SIZE)) &
+ ~(ALIGNMENT_UNIT - 1)) + uoffset;
+}
+
+/* Fill in destination addresses. */
+static inline void
+fill_addr_arrays(size_t *dst_addr, int is_dst_cached, size_t dst_uoffset)
+{
+ unsigned int i;
+
+ for (i = 0; i < TEST_BATCH_SIZE; i++)
+ dst_addr[i] = (is_dst_cached) ? dst_uoffset :
+ get_rand_offset(dst_uoffset);
+}
+
+/*
+ * WORKAROUND: For some reason the first test doing an uncached write
+ * takes a very long time (~25 times longer than is expected). So we do
+ * it once without timing.
+ */
+static void
+do_uncached_write(uint8_t *dst, int is_dst_cached, size_t size)
+{
+ unsigned int i, j;
+ size_t dst_addrs[TEST_BATCH_SIZE];
+ int ch = rte_rand() & 0xff;
+
+ for (i = 0; i < (TEST_ITERATIONS / TEST_BATCH_SIZE); i++) {
+ fill_addr_arrays(dst_addrs, is_dst_cached, 0);
+ for (j = 0; j < TEST_BATCH_SIZE; j++)
+ rte_memset(dst+dst_addrs[j], ch, size);
+ }
+}
+
+/*
+ * Run a single memset performance test. This is a macro to ensure that if
+ * the "size" parameter is a constant it won't be converted to a variable.
+ */
+#define SINGLE_PERF_TEST(dst, is_dst_cached, dst_uoffset, size) \
+do { \
+ unsigned int iter, t; \
+ size_t dst_addrs[TEST_BATCH_SIZE]; \
+ uint64_t start_time, total_time = 0; \
+ uint64_t total_time2 = 0; \
+ int ch = rte_rand() & 0xff; \
+ \
+ for (iter = 0; iter < (TEST_ITERATIONS / TEST_BATCH_SIZE); iter++) {\
+ fill_addr_arrays(dst_addrs, is_dst_cached, dst_uoffset); \
+ start_time = rte_rdtsc(); \
+ for (t = 0; t < TEST_BATCH_SIZE; t++) \
+ rte_memset(dst+dst_addrs[t], ch, size); \
+ total_time += rte_rdtsc() - start_time; \
+ } \
+ for (iter = 0; iter < (TEST_ITERATIONS / TEST_BATCH_SIZE); iter++) {\
+ fill_addr_arrays(dst_addrs, is_dst_cached, dst_uoffset); \
+ start_time = rte_rdtsc(); \
+ for (t = 0; t < TEST_BATCH_SIZE; t++) \
+ memset(dst+dst_addrs[t], ch, size); \
+ total_time2 += rte_rdtsc() - start_time; \
+ } \
+ printf("%8.0f -", (double)total_time / TEST_ITERATIONS); \
+ printf("%5.0f", (double)total_time2 / TEST_ITERATIONS); \
+} while (0)
+
+/* Run aligned memset tests. */
+#define ALL_PERF_TESTS_FOR_SIZE(n) \
+do { \
+ if (__builtin_constant_p(n)) \
+ printf("\nC%6u", (unsigned int)n); \
+ else \
+ printf("\n%7u", (unsigned int)n); \
+ SINGLE_PERF_TEST(small_buf_write, 1, 0, n); \
+ SINGLE_PERF_TEST(large_buf_write, 0, 0, n); \
+} while (0)
+
+/* Run unaligned memset tests */
+#define ALL_PERF_TESTS_FOR_SIZE_UNALIGNED(n) \
+do { \
+ if (__builtin_constant_p(n)) \
+ printf("\nC%6u", (unsigned int)n); \
+ else \
+ printf("\n%7u", (unsigned int)n); \
+ SINGLE_PERF_TEST(small_buf_write, 1, 1, n); \
+ SINGLE_PERF_TEST(large_buf_write, 0, 1, n); \
+} while (0)
+
+/* Run memset tests for constant length */
+#define ALL_PERF_TEST_FOR_CONSTANT \
+do { \
+ TEST_CONSTANT(6U); TEST_CONSTANT(64U); TEST_CONSTANT(128U); \
+ TEST_CONSTANT(192U); TEST_CONSTANT(256U); TEST_CONSTANT(512U); \
+ TEST_CONSTANT(768U); TEST_CONSTANT(1024U); TEST_CONSTANT(1536U); \
+} while (0)
+
+/* Run all memset tests for aligned constant cases */
+static inline void
+perf_test_constant_aligned(void)
+{
+#define TEST_CONSTANT ALL_PERF_TESTS_FOR_SIZE
+ ALL_PERF_TEST_FOR_CONSTANT;
+#undef TEST_CONSTANT
+}
+
+/* Run all memset tests for unaligned constant cases */
+static inline void
+perf_test_constant_unaligned(void)
+{
+#define TEST_CONSTANT ALL_PERF_TESTS_FOR_SIZE_UNALIGNED
+ ALL_PERF_TEST_FOR_CONSTANT;
+#undef TEST_CONSTANT
+}
+
+/* Run all memset tests for aligned variable cases */
+static inline void
+perf_test_variable_aligned(void)
+{
+ unsigned int n = sizeof(buf_sizes) / sizeof(buf_sizes[0]);
+ unsigned int i;
+
+ for (i = 0; i < n; i++)
+ ALL_PERF_TESTS_FOR_SIZE((size_t)buf_sizes[i]);
+}
+
+/* Run all memset tests for unaligned variable cases */
+static inline void
+perf_test_variable_unaligned(void)
+{
+ unsigned int n = sizeof(buf_sizes) / sizeof(buf_sizes[0]);
+ unsigned int i;
+
+ for (i = 0; i < n; i++)
+ ALL_PERF_TESTS_FOR_SIZE_UNALIGNED((size_t)buf_sizes[i]);
+}
+
+/* Run all memset tests */
+static int
+perf_test(void)
+{
+ int ret;
+
+ ret = init_buffers();
+ if (ret != 0)
+ return ret;
+
+#if TEST_VALUE_RANGE != 0
+ /* Set up buf_sizes array, if required */
+ unsigned int i;
+
+ for (i = 0; i < TEST_VALUE_RANGE; i++)
+ buf_sizes[i] = i;
+#endif
+
+ /* See function comment */
+ do_uncached_write(large_buf_write, 0, SMALL_BUFFER_SIZE);
+
+ printf("\n** rte_memset() - memset perf tests \t\n \
+ (C = compile-time constant) **\n"
+ "======== ======= ======== ======= ========\n"
+ " Size memset in cache memset in mem\n"
+ "(bytes) (ticks) (ticks)\n"
+ "------- -------------- ---------------");
+
+ printf("\n============= %2dB aligned ================", ALIGNMENT_UNIT);
+ /* Do aligned tests where size is a variable */
+ perf_test_variable_aligned();
+ printf("\n------ -------------- -------------- ------");
+ /* Do aligned tests where size is a compile-time constant */
+ perf_test_constant_aligned();
+ printf("\n============= Unaligned ===================");
+ /* Do unaligned tests where size is a variable */
+ perf_test_variable_unaligned();
+ printf("\n------ -------------- -------------- ------");
+ /* Do unaligned tests where size is a compile-time constant */
+ perf_test_constant_unaligned();
+ printf("\n====== ============== ============== =======\n\n");
+
+ free_buffers();
+
+ return 0;
+}
+
+static int
+test_memset_perf(void)
+{
+ int ret;
+
+ ret = perf_test();
+ if (ret != 0)
+ return -1;
+ return 0;
+}
+
+REGISTER_TEST_COMMAND(memset_perf_autotest, test_memset_perf);
--
2.7.4
^ permalink raw reply related
* [PATCH 2/4] app/test: add functional autotest for rte_memset
From: Zhiyong Yang @ 2016-12-02 8:36 UTC (permalink / raw)
To: dev; +Cc: yuanhan.liu, bruce.richardson, konstantin.ananyev, Zhiyong Yang
In-Reply-To: <1480926387-63838-1-git-send-email-zhiyong.yang@intel.com>
The file implements the functional autotest for rte_memset, which
validates the new function rte_memset whether to work in a right
way. The implementation of test_memcpy.c is used as a reference.
Usage:
step 1: run ./x86_64-native-linuxapp-gcc/app/test
step 2: run command memset_autotest at the run time.
Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
---
app/test/Makefile | 2 +
app/test/test_memset.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 160 insertions(+)
create mode 100644 app/test/test_memset.c
diff --git a/app/test/Makefile b/app/test/Makefile
index 5be023a..82da3f3 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -123,6 +123,8 @@ SRCS-y += test_logs.c
SRCS-y += test_memcpy.c
SRCS-y += test_memcpy_perf.c
+SRCS-y += test_memset.c
+
SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash.c
SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_thash.c
SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_perf.c
diff --git a/app/test/test_memset.c b/app/test/test_memset.c
new file mode 100644
index 0000000..c9020bf
--- /dev/null
+++ b/app/test/test_memset.c
@@ -0,0 +1,158 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <rte_common.h>
+#include <rte_random.h>
+#include <rte_memset.h>
+#include "test.h"
+
+/*
+ * Set this to the maximum buffer size you want to test. If it is 0, then the
+ * values in the buf_sizes[] array below will be used.
+ */
+#define TEST_VALUE_RANGE 0
+#define MAX_INT8 127
+#define MIN_INT8 -128
+/* List of buffer sizes to test */
+#if TEST_VALUE_RANGE == 0
+static size_t buf_sizes[] = {
+ 0, 1, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 127, 128, 129,
+ 255, 256, 257, 320, 384, 511, 512, 513, 1023, 1024, 1025, 1518,
+ 1522, 1600, 2048, 3072, 4096, 5120, 6144, 7168, 8192
+};
+/* MUST be as large as largest packet size above */
+#define BUFFER_SIZE 8192
+#else /* TEST_VALUE_RANGE != 0 */
+static size_t buf_sizes[TEST_VALUE_RANGE];
+#define BUFFER_SIZE TEST_VALUE_RANGE
+#endif /* TEST_VALUE_RANGE == 0 */
+
+/* Data is aligned on this many bytes (power of 2) */
+#define ALIGNMENT_UNIT 32
+
+/*
+ * Create two buffers, and initialize the one as the reference buffer with
+ * random values. Another(dest_buff) is assigned by the reference buffer.
+ * Set some memory area of dest_buff by using ch and then compare to see
+ * if the rte_memset is successful. The bytes outside the setted area are
+ * also checked to make sure they are not changed.
+ */
+static int
+test_single_memset(unsigned int off_dst, int ch, size_t size)
+{
+ unsigned int i;
+ uint8_t dest_buff[BUFFER_SIZE + ALIGNMENT_UNIT];
+ uint8_t ref_buff[BUFFER_SIZE + ALIGNMENT_UNIT];
+ void *ret;
+
+ /* Setup buffers */
+ for (i = 0; i < BUFFER_SIZE + ALIGNMENT_UNIT; i++) {
+ ref_buff[i] = (uint8_t) rte_rand();
+ dest_buff[i] = ref_buff[i];
+ }
+ /* Do the rte_memset */
+ ret = rte_memset(dest_buff + off_dst, ch, size);
+ if (ret != (dest_buff + off_dst)) {
+ printf("rte_memset() returned %p, not %p\n",
+ ret, dest_buff + off_dst);
+ }
+ /* Check nothing before offset was affected */
+ for (i = 0; i < off_dst; i++) {
+ if (dest_buff[i] != ref_buff[i]) {
+ printf("rte_memset() failed for %u bytes (offsets=%u): \
+ [modified before start of dst].\n",
+ (unsigned int)size, off_dst);
+ return -1;
+ }
+ }
+ /* Check every byte was setted */
+ for (i = 0; i < size; i++) {
+ if (dest_buff[i + off_dst] != (uint8_t)ch) {
+ printf("rte_memset() failed for %u bytes (offsets=%u): \
+ [didn't memset byte %u].\n",
+ (unsigned int)size, off_dst, i);
+ return -1;
+ }
+ }
+ /* Check nothing after memset was affected */
+ for (i = off_dst + size; i < BUFFER_SIZE + ALIGNMENT_UNIT; i++) {
+ if (dest_buff[i] != ref_buff[i]) {
+ printf("rte_memset() failed for %u bytes (offsets=%u): \
+ [memset too many].\n",
+ (unsigned int)size, off_dst);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Check functionality for various buffer sizes and data offsets/alignments.
+ */
+static int
+func_test(void)
+{
+ unsigned int off_dst, i;
+ unsigned int num_buf_sizes = sizeof(buf_sizes) / sizeof(buf_sizes[0]);
+ int ret;
+ int j;
+
+ for (j = MIN_INT8; j <= MAX_INT8; j++) {
+ for (off_dst = 0; off_dst < ALIGNMENT_UNIT; off_dst++) {
+ for (i = 0; i < num_buf_sizes; i++) {
+ ret = test_single_memset(off_dst, j,
+ buf_sizes[i]);
+ if (ret != 0)
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+test_memset(void)
+{
+ int ret;
+
+ ret = func_test();
+ if (ret != 0)
+ return -1;
+ return 0;
+}
+
+REGISTER_TEST_COMMAND(memset_autotest, test_memset);
--
2.7.4
^ permalink raw reply related
* [PATCH 1/4] eal/common: introduce rte_memset on IA platform
From: Zhiyong Yang @ 2016-12-02 8:36 UTC (permalink / raw)
To: dev; +Cc: yuanhan.liu, bruce.richardson, konstantin.ananyev, Zhiyong Yang
In-Reply-To: <1480926387-63838-1-git-send-email-zhiyong.yang@intel.com>
Performance drop has been caused in some cases when DPDK code calls glibc
function memset. reference to discussions about memset in
http://dpdk.org/ml/archives/dev/2016-October/048628.html
It is necessary to introduce more high efficient function to fix it.
One important thing about rte_memset is that we can get clear control
on what instruction flow is used. This patch supports instruction sets
such as sse & avx(128 bits), avx2(256 bits) and avx512(512bits).
rte_memset makes full use of vectorization and inline function to improve
the perf on IA. In addition, cache line and memory alignment are fully
taken into consideration.
Signed-off-by: Zhiyong Yang <zhiyong.yang@intel.com>
---
.../common/include/arch/x86/rte_memset.h | 376 +++++++++++++++++++++
lib/librte_eal/common/include/generic/rte_memset.h | 51 +++
2 files changed, 427 insertions(+)
create mode 100644 lib/librte_eal/common/include/arch/x86/rte_memset.h
create mode 100644 lib/librte_eal/common/include/generic/rte_memset.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_memset.h b/lib/librte_eal/common/include/arch/x86/rte_memset.h
new file mode 100644
index 0000000..3b2d3a3
--- /dev/null
+++ b/lib/librte_eal/common/include/arch/x86/rte_memset.h
@@ -0,0 +1,376 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_MEMSET_X86_64_H_
+#define _RTE_MEMSET_X86_64_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ *
+ * Functions for vectorised implementation of memset().
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <rte_vect.h>
+
+static inline void *
+rte_memset(void *dst, int a, size_t n) __attribute__((always_inline));
+
+static inline void
+rte_memset_less16(void *dst, int a, size_t n)
+{
+ uintptr_t dstu = (uintptr_t)dst;
+
+ if (n & 0x01) {
+ *(uint8_t *)dstu = (uint8_t)a;
+ dstu = (uintptr_t)((uint8_t *)dstu + 1);
+ }
+ if (n & 0x02) {
+ *(uint16_t *)dstu = (uint8_t)a | (((uint8_t)a) << 8);
+ dstu = (uintptr_t)((uint16_t *)dstu + 1);
+ }
+ if (n & 0x04) {
+ uint16_t b = ((uint8_t)a | (((uint8_t)a) << 8));
+
+ *(uint32_t *)dstu = (uint32_t)(b | (b << 16));
+ dstu = (uintptr_t)((uint32_t *)dstu + 1);
+ }
+ if (n & 0x08) {
+ uint16_t b = ((uint8_t)a | (((uint8_t)a) << 8));
+ uint32_t c = b | (b << 16);
+
+ *(uint32_t *)dstu = c;
+ *((uint32_t *)dstu + 1) = c;
+ dstu = (uintptr_t)((uint32_t *)dstu + 2);
+ }
+}
+
+static inline void
+rte_memset16(uint8_t *dst, int8_t a)
+{
+ __m128i xmm0;
+
+ xmm0 = _mm_set1_epi8(a);
+ _mm_storeu_si128((__m128i *)dst, xmm0);
+}
+
+static inline void
+rte_memset_17to32(void *dst, int a, size_t n)
+{
+ rte_memset16((uint8_t *)dst, a);
+ rte_memset16((uint8_t *)dst - 16 + n, a);
+}
+
+#ifdef RTE_MACHINE_CPUFLAG_AVX512
+
+/**
+ * AVX512 implementation below
+ */
+
+static inline void
+rte_memset32(uint8_t *dst, int8_t a)
+{
+ __m256i ymm0;
+
+ ymm0 = _mm256_set1_epi8(a);
+ _mm256_storeu_si256((__m256i *)dst, ymm0);
+}
+
+static inline void
+rte_memset64(uint8_t *dst, int8_t a)
+{
+ __m512i zmm0;
+
+ zmm0 = _mm512_set1_epi8(a);
+ _mm512_storeu_si512((void *)dst, zmm0);
+}
+
+static inline void
+rte_memset128blocks(uint8_t *dst, int8_t a, size_t n)
+{
+ __m512i zmm0;
+
+ zmm0 = _mm512_set1_epi8(a);
+ while (n >= 128) {
+ n -= 128;
+ _mm512_store_si512((void *)(dst + 0 * 64), zmm0);
+ _mm512_store_si512((void *)(dst + 1 * 64), zmm0);
+ dst = dst + 128;
+ }
+}
+
+static inline void *
+rte_memset(void *dst, int a, size_t n)
+{
+ void *ret = dst;
+ size_t dstofss;
+ size_t bits;
+
+ if (n < 16) {
+ rte_memset_less16(dst, a, n);
+ return ret;
+ } else if (n == 16) {
+ rte_memset16((uint8_t *)dst, a);
+ return ret;
+ }
+ if (n <= 32) {
+ rte_memset_17to32(dst, a, n);
+ return ret;
+ }
+ if (n <= 64) {
+ rte_memset32((uint8_t *)dst, a);
+ rte_memset32((uint8_t *)dst - 32 + n, a);
+ return ret;
+ }
+ if (n >= 256) {
+ dstofss = ((uintptr_t)dst & 0x3F);
+ if (dstofss > 0) {
+ dstofss = 64 - dstofss;
+ n -= dstofss;
+ rte_memset64((uint8_t *)dst, a);
+ dst = (uint8_t *)dst + dstofss;
+ }
+ rte_memset128blocks((uint8_t *)dst, a, n);
+ bits = n;
+ n = n & 127;
+ bits -= n;
+ dst = (uint8_t *)dst + bits;
+ }
+ if (n > 128) {
+ n -= 128;
+ rte_memset64((uint8_t *)dst, a);
+ rte_memset64((uint8_t *)dst + 64, a);
+ dst = (uint8_t *)dst + 128;
+ }
+ if (n > 64) {
+ rte_memset64((uint8_t *)dst, a);
+ rte_memset64((uint8_t *)dst - 64 + n, a);
+ return ret;
+ }
+ if (n > 0)
+ rte_memset64((uint8_t *)dst - 64 + n, a);
+ return ret;
+}
+
+#elif defined RTE_MACHINE_CPUFLAG_AVX2
+
+/**
+ * AVX2 implementation below
+ */
+
+static inline void
+rte_memset32(uint8_t *dst, int8_t a)
+{
+ __m256i ymm0;
+
+ ymm0 = _mm256_set1_epi8(a);
+ _mm256_storeu_si256((__m256i *)dst, ymm0);
+}
+
+static inline void
+rte_memset_33to64(void *dst, int a, size_t n)
+{
+ rte_memset32((uint8_t *)dst, a);
+ rte_memset32((uint8_t *)dst - 32 + n, a);
+}
+
+static inline void
+rte_memset64blocks(uint8_t *dst, int8_t a, size_t n)
+{
+ __m256i ymm0;
+
+ ymm0 = _mm256_set1_epi8(a);
+ while (n >= 64) {
+ n -= 64;
+ _mm256_store_si256((__m256i *)((uint8_t *)dst + 0 * 32), ymm0);
+ _mm256_store_si256((__m256i *)((uint8_t *)dst + 1 * 32), ymm0);
+ dst = (uint8_t *)dst + 64;
+
+ }
+}
+
+static inline void *
+rte_memset(void *dst, int a, size_t n)
+{
+ void *ret = dst;
+ size_t dstofss;
+ size_t bits;
+
+ if (n < 16) {
+ rte_memset_less16(dst, a, n);
+ return ret;
+ } else if (n == 16) {
+ rte_memset16((uint8_t *)dst, a);
+ return ret;
+ }
+ if (n <= 32) {
+ rte_memset_17to32(dst, a, n);
+ return ret;
+ }
+ if (n <= 64) {
+ rte_memset_33to64(dst, a, n);
+ return ret;
+ }
+ if (n > 64) {
+ dstofss = (uintptr_t)dst & 0x1F;
+ if (dstofss > 0) {
+ dstofss = 32 - dstofss;
+ n -= dstofss;
+ rte_memset32((uint8_t *)dst, a);
+ dst = (uint8_t *)dst + dstofss;
+ }
+ rte_memset64blocks((uint8_t *)dst, a, n);
+ bits = n;
+ n = n & 63;
+ bits -= n;
+ dst = (uint8_t *)dst + bits;
+ }
+ if (n > 32) {
+ rte_memset_33to64(dst, a, n);
+ return ret;
+ }
+ if (n > 0)
+ rte_memset32((uint8_t *)dst - 32 + n, a);
+ return ret;
+}
+
+#else /* RTE_MACHINE_CPUFLAG */
+
+/**
+ * SSE && AVX implementation below
+ */
+
+static inline void
+rte_memset32(uint8_t *dst, int8_t a)
+{
+ __m128i xmm0 = _mm_set1_epi8(a);
+
+ _mm_storeu_si128((__m128i *)dst, xmm0);
+ _mm_storeu_si128((__m128i *)(dst + 16), xmm0);
+}
+
+static inline void
+rte_memset16blocks(uint8_t *dst, int8_t a, size_t n)
+{
+ __m128i xmm0 = _mm_set1_epi8(a);
+
+ while (n >= 16) {
+ n -= 16;
+ _mm_store_si128((__m128i *)(dst + 0 * 16), xmm0);
+ dst = (uint8_t *)dst + 16;
+ }
+}
+
+static inline void
+rte_memset64blocks(uint8_t *dst, int8_t a, size_t n)
+{
+ __m128i xmm0 = _mm_set1_epi8(a);
+
+ while (n >= 64) {
+ n -= 64;
+ _mm_store_si128((__m128i *)(dst + 0 * 16), xmm0);
+ _mm_store_si128((__m128i *)(dst + 1 * 16), xmm0);
+ _mm_store_si128((__m128i *)(dst + 2 * 16), xmm0);
+ _mm_store_si128((__m128i *)(dst + 3 * 16), xmm0);
+ dst = (uint8_t *)dst + 64;
+ }
+}
+
+static inline void *
+rte_memset(void *dst, int a, size_t n)
+{
+ void *ret = dst;
+ size_t dstofss;
+ size_t bits;
+
+ if (n < 16) {
+ rte_memset_less16(dst, a, n);
+ return ret;
+ } else if (n == 16) {
+ rte_memset16((uint8_t *)dst, a);
+ return ret;
+ }
+ if (n <= 32) {
+ rte_memset_17to32(dst, a, n);
+ return ret;
+ }
+ if (n <= 48) {
+ rte_memset32((uint8_t *)dst, a);
+ rte_memset16((uint8_t *)dst - 16 + n, a);
+ return ret;
+ }
+ if (n <= 64) {
+ rte_memset32((uint8_t *)dst, a);
+ rte_memset16((uint8_t *)dst + 32, a);
+ rte_memset16((uint8_t *)dst - 16 + n, a);
+ return ret;
+ }
+ if (n > 64) {
+ dstofss = (uintptr_t)dst & 0xF;
+ if (dstofss > 0) {
+ dstofss = 16 - dstofss;
+ n -= dstofss;
+ rte_memset16((uint8_t *)dst, a);
+ dst = (uint8_t *)dst + dstofss;
+ }
+ rte_memset64blocks((uint8_t *)dst, a, n);
+ bits = n;
+ n &= 63;
+ bits -= n;
+ dst = (uint8_t *)dst + bits;
+ rte_memset16blocks((uint8_t *)dst, a, n);
+ bits = n;
+ n &= 0xf;
+ bits -= n;
+ dst = (uint8_t *)dst + bits;
+ if (n > 0) {
+ rte_memset16((uint8_t *)dst - 16 + n, a);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+#endif /* RTE_MACHINE_CPUFLAG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_MEMSET_H_ */
diff --git a/lib/librte_eal/common/include/generic/rte_memset.h b/lib/librte_eal/common/include/generic/rte_memset.h
new file mode 100644
index 0000000..416a638
--- /dev/null
+++ b/lib/librte_eal/common/include/generic/rte_memset.h
@@ -0,0 +1,51 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_MEMSET_H_
+#define _RTE_MEMSET_H_
+
+/**
+ * @file
+ *
+ * Functions for vectorised implementation of memset().
+ */
+#ifndef _RTE_MEMSET_X86_64_H_
+
+#define rte_memset memset
+
+#else
+
+static void *
+rte_memset(void *dst, int a, size_t n);
+
+#endif
+#endif /* _RTE_MEMSET_H_ */
--
2.7.4
^ permalink raw reply related
* [PATCH 0/4] eal/common: introduce rte_memset and related test
From: Zhiyong Yang @ 2016-12-02 8:36 UTC (permalink / raw)
To: dev; +Cc: yuanhan.liu, bruce.richardson, konstantin.ananyev
DPDK code has met performance drop badly in some case when calling glibc
function memset. Reference to discussions about memset in
http://dpdk.org/ml/archives/dev/2016-October/048628.html
It is necessary to introduce more high efficient function to fix it.
One important thing about rte_memset is that we can get clear control
on what instruction flow is used.
This patchset introduces rte_memset to bring more high efficient
implementation, and will bring obvious perf improvement, especially
for small N bytes in the most application scenarios.
Patch 1 implements rte_memset in the file rte_memset.h on IA platform
The file supports three types of instruction sets including sse & avx
(128bits), avx2(256bits) and avx512(512bits). rte_memset makes use of
vectorization and inline function to improve the perf on IA. In addition,
cache line and memory alignment are fully taken into consideration.
Patch 2 implements functional autotest to validates the function whether
to work in a right way.
Patch 3 implements performance autotest separately in cache and memory.
Patch 4 Using rte_memset instead of copy_virtio_net_hdr can bring 3%~4%
performance improvements on IA platform from virtio/vhost non-mergeable
loopback testing.
Zhiyong Yang (4):
eal/common: introduce rte_memset on IA platform
app/test: add functional autotest for rte_memset
app/test: add performance autotest for rte_memset
lib/librte_vhost: improve vhost perf using rte_memset
app/test/Makefile | 3 +
app/test/test_memset.c | 158 +++++++++
app/test/test_memset_perf.c | 348 +++++++++++++++++++
doc/guides/rel_notes/release_17_02.rst | 11 +
.../common/include/arch/x86/rte_memset.h | 376 +++++++++++++++++++++
lib/librte_eal/common/include/generic/rte_memset.h | 51 +++
lib/librte_vhost/virtio_net.c | 18 +-
7 files changed, 958 insertions(+), 7 deletions(-)
create mode 100644 app/test/test_memset.c
create mode 100644 app/test/test_memset_perf.c
create mode 100644 lib/librte_eal/common/include/arch/x86/rte_memset.h
create mode 100644 lib/librte_eal/common/include/generic/rte_memset.h
--
2.7.4
^ permalink raw reply
* [PATCH] vhost: optimize vhost memcpy
From: Zhihong Wang @ 2016-12-02 1:19 UTC (permalink / raw)
To: dev; +Cc: yuanhan.liu, Zhihong Wang
This patch optimizes Vhost performance for large packets when the
Mergeable Rx buffer feature is enabled. It introduces a dedicated
memcpy function for vhost enqueue/dequeue to replace rte_memcpy.
The reason is that rte_memcpy is for general cases, it handles
unaligned copies and make store aligned, it even makes load aligned
for micro architectures like Ivy Bridge. However alignment handling
comes at a price: It introduces extra load/store instructions.
Vhost memcpy is rather special: The copy is aligned, and remote,
and there is header write along which is also remote. In this case
the memcpy instruction stream should be simplified, to reduce extra
load/store, therefore reduce the probability of load/store buffer
full caused pipeline stall, to let the actual memcpy instructions
be issued and let H/W prefetcher goes to work as early as possible.
Performance gain is visible when packet size:
1. Larger than 512 bytes on AVX/SSE platforms like Ivy Bridge
2. Larger than 256 bytes on AVX2 platforms like Haswell
3. Larger than 512 bytes on AVX512 platforms like Skylake
Up to 20% gain can be achieved by this patch for PVP traffic. The
test can also be conducted without NIC, by using loopback traffic
between Vhost and Virtio. For example, increase TXONLY_DEF_PACKET_LEN
to the requested packet size in testpmd.h, rebuild and start testpmd
in both host and guest, then "start" on one side and "start tx_first 32"
on the other.
Signed-off-by: Zhihong Wang <zhihong.wang@intel.com>
---
lib/librte_vhost/virtio_net.c | 72 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 69 insertions(+), 3 deletions(-)
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
index 595f67c..cd6f21a 100644
--- a/lib/librte_vhost/virtio_net.c
+++ b/lib/librte_vhost/virtio_net.c
@@ -50,6 +50,72 @@
#define MAX_PKT_BURST 32
#define VHOST_LOG_PAGE 4096
+/**
+ * This function is used to for vhost memcpy, to replace rte_memcpy.
+ * The reason is that rte_memcpy is for general cases, where vhost
+ * memcpy is a rather special case: The copy is aligned, and remote,
+ * and there is header write along which is also remote. In this case
+ * the memcpy instruction stream should be simplified to reduce extra
+ * load/store, therefore reduce the probability of load/store buffer
+ * full caused pipeline stall, to let the actual memcpy instructions
+ * be issued and let H/W prefetcher goes to work as early as possible.
+ */
+static inline void __attribute__((always_inline))
+vhost_memcpy(void *dst, const void *src, size_t n)
+{
+ /* Copy size <= 16 bytes */
+ if (n < 16) {
+ if (n & 0x01) {
+ *(uint8_t *)dst = *(const uint8_t *)src;
+ src = (const uint8_t *)src + 1;
+ dst = (uint8_t *)dst + 1;
+ }
+ if (n & 0x02) {
+ *(uint16_t *)dst = *(const uint16_t *)src;
+ src = (const uint16_t *)src + 1;
+ dst = (uint16_t *)dst + 1;
+ }
+ if (n & 0x04) {
+ *(uint32_t *)dst = *(const uint32_t *)src;
+ src = (const uint32_t *)src + 1;
+ dst = (uint32_t *)dst + 1;
+ }
+ if (n & 0x08)
+ *(uint64_t *)dst = *(const uint64_t *)src;
+
+ return;
+ }
+
+ /* Copy 16 <= size <= 32 bytes */
+ if (n <= 32) {
+ rte_mov16((uint8_t *)dst, (const uint8_t *)src);
+ rte_mov16((uint8_t *)dst - 16 + n,
+ (const uint8_t *)src - 16 + n);
+
+ return;
+ }
+
+ /* Copy 32 < size <= 64 bytes */
+ if (n <= 64) {
+ rte_mov32((uint8_t *)dst, (const uint8_t *)src);
+ rte_mov32((uint8_t *)dst - 32 + n,
+ (const uint8_t *)src - 32 + n);
+
+ return;
+ }
+
+ /* Copy 64 bytes blocks */
+ for (; n >= 64; n -= 64) {
+ rte_mov64((uint8_t *)dst, (const uint8_t *)src);
+ dst = (uint8_t *)dst + 64;
+ src = (const uint8_t *)src + 64;
+ }
+
+ /* Copy whatever left */
+ rte_mov64((uint8_t *)dst - 64 + n,
+ (const uint8_t *)src - 64 + n);
+}
+
static inline void __attribute__((always_inline))
vhost_log_page(uint8_t *log_base, uint64_t page)
{
@@ -246,7 +312,7 @@ copy_mbuf_to_desc(struct virtio_net *dev, struct vring_desc *descs,
}
cpy_len = RTE_MIN(desc_avail, mbuf_avail);
- rte_memcpy((void *)((uintptr_t)(desc_addr + desc_offset)),
+ vhost_memcpy((void *)((uintptr_t)(desc_addr + desc_offset)),
rte_pktmbuf_mtod_offset(m, void *, mbuf_offset),
cpy_len);
vhost_log_write(dev, desc->addr + desc_offset, cpy_len);
@@ -522,7 +588,7 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct rte_mbuf *m,
}
cpy_len = RTE_MIN(desc_avail, mbuf_avail);
- rte_memcpy((void *)((uintptr_t)(desc_addr + desc_offset)),
+ vhost_memcpy((void *)((uintptr_t)(desc_addr + desc_offset)),
rte_pktmbuf_mtod_offset(m, void *, mbuf_offset),
cpy_len);
vhost_log_write(dev, buf_vec[vec_idx].buf_addr + desc_offset,
@@ -856,7 +922,7 @@ copy_desc_to_mbuf(struct virtio_net *dev, struct vring_desc *descs,
*/
mbuf_avail = cpy_len;
} else {
- rte_memcpy(rte_pktmbuf_mtod_offset(cur, void *,
+ vhost_memcpy(rte_pktmbuf_mtod_offset(cur, void *,
mbuf_offset),
(void *)((uintptr_t)(desc_addr + desc_offset)),
cpy_len);
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v12 1/6] ethdev: add Tx preparation
From: Olivier Matz @ 2016-12-02 8:24 UTC (permalink / raw)
To: Ananyev, Konstantin; +Cc: Thomas Monjalon, Kulasek, TomaszX, dev@dpdk.org
In-Reply-To: <2601191342CEEE43887BDE71AB9772583F0E2AB0@irsmsx105.ger.corp.intel.com>
Hi Konstantin,
On Fri, 2 Dec 2016 01:06:30 +0000, "Ananyev, Konstantin"
<konstantin.ananyev@intel.com> wrote:
> >
> > 2016-11-23 18:36, Tomasz Kulasek:
> > > +/**
> > > + * Process a burst of output packets on a transmit queue of an
> > > Ethernet device.
> > > + *
> > > + * The rte_eth_tx_prepare() function is invoked to prepare
> > > output packets to be
> > > + * transmitted on the output queue *queue_id* of the Ethernet
> > > device designated
> > > + * by its *port_id*.
> > > + * The *nb_pkts* parameter is the number of packets to be
> > > prepared which are
> > > + * supplied in the *tx_pkts* array of *rte_mbuf* structures,
> > > each of them
> > > + * allocated from a pool created with rte_pktmbuf_pool_create().
> > > + * For each packet to send, the rte_eth_tx_prepare() function
> > > performs
> > > + * the following operations:
> > > + *
> > > + * - Check if packet meets devices requirements for tx offloads.
> > > + *
> > > + * - Check limitations about number of segments.
> > > + *
> > > + * - Check additional requirements when debug is enabled.
> > > + *
> > > + * - Update and/or reset required checksums when tx offload is
> > > set for packet.
> > > + *
> > > + * Since this function can modify packet data, provided mbufs
> > > must be safely
> > > + * writable (e.g. modified data cannot be in shared segment).
> >
> > I think we will have to remove this limitation in next releases.
> > As we don't know how it could affect the API, I suggest to declare
> > this API EXPERIMENTAL.
>
> While I don't really mind to mart it as experimental, I don't really
> understand the reasoning: Why " this function can modify packet data,
> provided mbufs must be safely writable" suddenly becomes a problem?
> That seems like and obvious limitation to me and let say tx_burst()
> has the same one. Second, I don't see how you are going to remove it
> without introducing a heavy performance impact. Konstantin
>
About tx_burst(), I don't think we should force the user to provide a
writable mbuf. There are many use cases where passing a clone
already works as of today and it avoids duplicating the mbuf data. For
instance: traffic generator, multicast, bridging/tap, etc...
Moreover, this requirement would be inconsistent with the model you are
proposing in case of pipeline:
- tx_prepare() on core X, may update the data
- tx_burst() on core Y, should not touch the data to avoid cache misses
Regards,
Olivier
^ permalink raw reply
* [PATCH 31/31] i40e: enhance in sanity check of mac
From: Wenzhuo Lu @ 2016-12-02 0:12 UTC (permalink / raw)
To: dev; +Cc: Chen Jing D(Mark)
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
When VF sends request to add a new mac address, PF host
will check if it's a non-zero or uncast address, or it
will return with error. In fact, VF still can set multicast
address. This change remove to check if it's a unicast
address.
Signed-off-by: Chen Jing D(Mark) <jing.d.chen@intel.com>
---
drivers/net/i40e/i40e_pf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index 4b0da75..c9cca1e 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -890,7 +890,7 @@
mac = (struct ether_addr *)(addr_list->list[i].addr);
(void)rte_memcpy(&filter.mac_addr, mac, ETHER_ADDR_LEN);
filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
- if(!is_valid_assigned_ether_addr(mac) ||
+ if(is_zero_ether_addr(mac) ||
i40e_vsi_add_mac(vf->vsi, &filter)) {
ret = I40E_ERR_INVALID_MAC_ADDR;
goto send_msg;
--
1.9.3
^ permalink raw reply related
* [PATCH 30/31] net/i40e: support Linux VF to configure IRQ link list
From: Wenzhuo Lu @ 2016-12-02 0:12 UTC (permalink / raw)
To: dev; +Cc: Chen Jing D(Mark)
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
i40e PF host only support to work with DPDK VF driver, Linux
VF driver is not supported. This change will enhance in
configuring IRQ link list.
This Change will identify VF client by number of vector
requested. DPDK VF will ask only single one while Linux VF
will request at least 2. It will have different configuration
for different clients. DPDK VF will be configured to link all
queue together, while Linux VF will be configured per request.
Signed-off-by: Chen Jing D(Mark) <jing.d.chen@intel.com>
---
drivers/net/i40e/i40e_pf.c | 151 +++++++++++++++++++++++++++++++++++++++++----
1 file changed, 138 insertions(+), 13 deletions(-)
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index 1ad5ed1..4b0da75 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -585,14 +585,116 @@
return ret;
}
+static void
+i40e_pf_config_irq_link_list(struct i40e_pf_vf *vf,
+ struct i40e_virtchnl_vector_map *vvm)
+{
+ uint64_t linklistmap = 0, tempmap;
+ struct i40e_hw *hw = I40E_PF_TO_HW(vf->pf);
+ uint16_t qid;
+ bool b_first_q = true;
+ enum i40e_queue_type qtype;
+ uint16_t vector_id;
+ uint32_t reg, reg_idx;
+ uint16_t itr_idx = 0, i;
+
+ vector_id = vvm->vector_id;
+ /* setup the head */
+ if (!vector_id)
+ reg_idx = I40E_VPINT_LNKLST0(vf->vf_idx);
+ else
+ reg_idx = I40E_VPINT_LNKLSTN(
+ ((hw->func_caps.num_msix_vectors_vf - 1) * vf->vf_idx)
+ + (vector_id - 1));
+
+ if (vvm->rxq_map == 0 && vvm->txq_map == 0) {
+ I40E_WRITE_REG(hw, reg_idx,
+ I40E_VPINT_LNKLST0_FIRSTQ_INDX_MASK);
+ goto cfg_irq_done;
+ }
+
+ /* sort all rx and tx queues */
+ tempmap = vvm->rxq_map;
+ for (i = 0; i < sizeof(vvm->rxq_map) * 8; i++) {
+ if (tempmap & 0x1)
+ linklistmap |= (1 << (2 * i));
+ tempmap >>= 1;
+ }
+
+ tempmap = vvm->txq_map;
+ for (i = 0; i < sizeof(vvm->txq_map) * 8; i++) {
+ if (tempmap & 0x1)
+ linklistmap |= (1 << (2 * i + 1));
+ tempmap >>= 1;
+ }
+
+ /* Link all rx and tx queues into a chained list */
+ tempmap = linklistmap;
+ i = 0;
+ b_first_q = true;
+ do {
+ if (tempmap & 0x1) {
+ qtype = i % 2;
+ qid = vf->vsi->base_queue + i / 2;
+ if (b_first_q) {
+ /* This is header */
+ b_first_q = false;
+ reg = ((qtype <<
+ I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT)
+ | qid);
+ } else {
+ /* element in the link list */
+ reg = (vector_id) |
+ (qtype << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
+ (qid << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
+ BIT(I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) |
+ (itr_idx << I40E_QINT_RQCTL_ITR_INDX_SHIFT);
+ }
+ I40E_WRITE_REG(hw, reg_idx, reg);
+ /* find next register to program */
+ switch (qtype) {
+ case I40E_QUEUE_TYPE_RX:
+ reg_idx = I40E_QINT_RQCTL(qid);
+ itr_idx = vvm->rxitr_idx;
+ break;
+ case I40E_QUEUE_TYPE_TX:
+ reg_idx = I40E_QINT_TQCTL(qid);
+ itr_idx = vvm->txitr_idx;
+ break;
+ default:
+ break;
+ }
+ }
+ i++;
+ tempmap >>= 1;
+ } while (tempmap);
+
+ /* Terminate the link list */
+ reg = (vector_id) |
+ (0 << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
+ (0x7FF << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
+ BIT(I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) |
+ (itr_idx << I40E_QINT_RQCTL_ITR_INDX_SHIFT);
+ I40E_WRITE_REG(hw, reg_idx, reg);
+
+cfg_irq_done:
+ I40E_WRITE_FLUSH(hw);
+}
+
static int
i40e_pf_host_process_cmd_config_irq_map(struct i40e_pf_vf *vf,
uint8_t *msg, uint16_t msglen,
bool b_op)
{
int ret = I40E_SUCCESS;
+ struct i40e_pf *pf = vf->pf;
+ struct i40e_hw *hw = I40E_PF_TO_HW(vf->pf);
struct i40e_virtchnl_irq_map_info *irqmap =
(struct i40e_virtchnl_irq_map_info *)msg;
+ struct i40e_virtchnl_vector_map *map;
+ int i;
+ uint16_t vector_id;
+ unsigned long qbit_max;
if (!b_op) {
i40e_pf_host_send_msg_to_vf(
@@ -608,23 +710,46 @@
goto send_msg;
}
- /* Assume VF only have 1 vector to bind all queues */
- if (irqmap->num_vectors != 1) {
- PMD_DRV_LOG(ERR, "DKDK host only support 1 vector");
- ret = I40E_ERR_PARAM;
+ /* PF host will support both DPDK VF or Linux VF driver, identify by
+ * number of vectors requested.
+ */
+
+ /* DPDK VF only requires single vector */
+ if (irqmap->num_vectors == 1) {
+ /* This MSIX intr store the intr in VF range */
+ vf->vsi->msix_intr = irqmap->vecmap[0].vector_id;
+ vf->vsi->nb_msix = irqmap->num_vectors;
+ vf->vsi->nb_used_qps = vf->vsi->nb_qps;
+
+ /* Don't care how the TX/RX queue mapping with this vector.
+ * Link all VF RX queues together. Only did mapping work.
+ * VF can disable/enable the intr by itself.
+ */
+ i40e_vsi_queues_bind_intr(vf->vsi);
goto send_msg;
}
- /* This MSIX intr store the intr in VF range */
- vf->vsi->msix_intr = irqmap->vecmap[0].vector_id;
- vf->vsi->nb_msix = irqmap->num_vectors;
- vf->vsi->nb_used_qps = vf->vsi->nb_qps;
+ /* Then, it's Linux VF driver */
+ qbit_max = 1 << pf->vf_nb_qp_max;
+ for (i = 0; i < irqmap->num_vectors; i++) {
+ map = &irqmap->vecmap[i];
+
+ vector_id = map->vector_id;
+ /* validate msg params */
+ if (vector_id >= hw->func_caps.num_msix_vectors_vf) {
+ ret = I40E_ERR_PARAM;
+ goto send_msg;
+ }
+
+ if ((map->rxq_map < qbit_max) && (map->txq_map < qbit_max)) {
+ i40e_pf_config_irq_link_list(vf, map);
+ } else {
+ /* configured queue size excceed limit */
+ ret = I40E_ERR_PARAM;
+ goto send_msg;
+ }
+ }
- /* Don't care how the TX/RX queue mapping with this vector.
- * Link all VF RX queues together. Only did mapping work.
- * VF can disable/enable the intr by itself.
- */
- i40e_vsi_queues_bind_intr(vf->vsi);
send_msg:
i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
ret, NULL, 0);
--
1.9.3
^ permalink raw reply related
* [PATCH 29/31] net/i40e: parse more VF parameter and configure
From: Wenzhuo Lu @ 2016-12-02 0:12 UTC (permalink / raw)
To: dev; +Cc: Chen Jing D(Mark)
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
When VF requested to configure TX queue, a few parameters are
missed to be configured in PF host. This change have more
fields parsed and configured for TX context.
Signed-off-by: Chen Jing D(Mark) <jing.d.chen@intel.com>
---
drivers/net/i40e/i40e_pf.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index 8319c2c..1ad5ed1 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -422,10 +422,12 @@
/* clear the context structure first */
memset(&tx_ctx, 0, sizeof(tx_ctx));
- tx_ctx.new_context = 1;
tx_ctx.base = txq->dma_ring_addr / I40E_QUEUE_BASE_ADDR_UNIT;
tx_ctx.qlen = txq->ring_len;
tx_ctx.rdylist = rte_le_to_cpu_16(vf->vsi->info.qs_handle[0]);
+ tx_ctx.head_wb_ena = txq->headwb_enabled;
+ tx_ctx.head_wb_addr = txq->dma_headwb_addr;
+
err = i40e_clear_lan_tx_queue_context(hw, abs_queue_id);
if (err != I40E_SUCCESS)
return err;
--
1.9.3
^ permalink raw reply related
* [PATCH 28/31] net/i40e: return correct vsi_id
From: Wenzhuo Lu @ 2016-12-02 0:12 UTC (permalink / raw)
To: dev; +Cc: Chen Jing D(Mark)
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
PF host didn't return correct VSI id to VF.
This change fix it.
Signed-off-by: Chen Jing D(Mark) <jing.d.chen@intel.com>
---
drivers/net/i40e/i40e_pf.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index 0f582ed..8319c2c 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -351,8 +351,7 @@
/* Change below setting if PF host can support more VSIs for VF */
vf_res->vsi_res[0].vsi_type = I40E_VSI_SRIOV;
- /* As assume Vf only has single VSI now, always return 0 */
- vf_res->vsi_res[0].vsi_id = 0;
+ vf_res->vsi_res[0].vsi_id = vf->vsi->vsi_id;
vf_res->vsi_res[0].num_queue_pairs = vf->vsi->nb_qps;
ether_addr_copy(&vf->mac_addr,
(struct ether_addr *)vf_res->vsi_res[0].default_mac_addr);
--
1.9.3
^ permalink raw reply related
* [PATCH 27/31] net/i40e: change version number to support Linux VF
From: Wenzhuo Lu @ 2016-12-02 0:12 UTC (permalink / raw)
To: dev; +Cc: Chen Jing D(Mark)
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
i40e PF host only support to work with DPDK VF driver, Linux
VF driver is not supported. This change will enhance in version
number returned.
Current version info returned won't be able to be recognized
by Linux VF driver, change to values that both DPDK VF and Linux
driver can recognize.
The expense is original DPDK host specific feature like
CFG_VLAN_PVID and CONFIG_VSI_QUEUES_EXT will not available.
DPDK VF also can't identify host driver by version number returned.
It always assume talking with Linux PF.
Signed-off-by: Chen Jing D(Mark) <jing.d.chen@intel.com>
---
drivers/net/i40e/i40e_pf.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index 2bc3355..0f582ed 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -279,8 +279,19 @@
{
struct i40e_virtchnl_version_info info;
- info.major = I40E_DPDK_VERSION_MAJOR;
- info.minor = I40E_DPDK_VERSION_MINOR;
+ /* Respond like a Linux PF host in order to support both DPDK VF and
+ * Linux VF driver. The expense is original DPDK host specific feature
+ * like CFG_VLAN_PVID and CONFIG_VSI_QUEUES_EXT will not available.
+ *
+ * DPDK VF also can't identify host driver by version number returned.
+ * It always assume talking with Linux PF.
+ *
+ * TODO:
+ * Discuss with Linux driver maintainer if possible to carry more info
+ * in this function to identify it's Linux or DPDK host.
+ */
+ info.major = I40E_VIRTCHNL_VERSION_MAJOR;
+ info.minor = I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS;
if (b_op)
i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_VERSION,
--
1.9.3
^ permalink raw reply related
* [PATCH 26/31] app/testpmd: initialize receive mode for VMDq
From: Wenzhuo Lu @ 2016-12-02 0:12 UTC (permalink / raw)
To: dev; +Cc: Bernard Iremonger
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
Initialise VMDq in the init_port_config function in a similar
way to how it is done in the VMDq sample application.
Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
---
app/test-pmd/testpmd.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index a0332c2..c0c8f60 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -1842,9 +1842,12 @@ struct pmd_test_command {
ETH_MQ_RX_VMDQ_RSS;
else
port->dev_conf.rxmode.mq_mode =
- ETH_MQ_RX_NONE;
+ ETH_MQ_RX_VMDQ_ONLY;
port->dev_conf.txmode.mq_mode = ETH_MQ_TX_NONE;
+
+ port->dev_conf.rx_adv_conf.vmdq_rx_conf.nb_queue_pools =
+ ETH_8_POOLS;
}
rxtx_port_config(port);
--
1.9.3
^ permalink raw reply related
* [PATCH 25/31] app/testpmd: handle i40e in VF VLAN filter command
From: Wenzhuo Lu @ 2016-12-02 0:12 UTC (permalink / raw)
To: dev; +Cc: Bernard Iremonger
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
modify set_vf_rx_vlan function to handle the i40e PMD.
Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
---
app/test-pmd/config.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 36c47ab..0368dc6 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -92,6 +92,9 @@
#include <rte_ethdev.h>
#include <rte_string_fns.h>
#include <rte_cycles.h>
+#ifdef RTE_LIBRTE_I40E_PMD
+#include <rte_pmd_i40e.h>
+#endif
#include "testpmd.h"
@@ -2349,12 +2352,24 @@ struct igb_ring_desc_16_bytes {
set_vf_rx_vlan(portid_t port_id, uint16_t vlan_id, uint64_t vf_mask, uint8_t on)
{
int diag;
+ struct rte_eth_dev_info dev_info;
if (port_id_is_invalid(port_id, ENABLED_WARN))
return;
if (vlan_id_is_invalid(vlan_id))
return;
- diag = rte_eth_dev_set_vf_vlan_filter(port_id, vlan_id, vf_mask, on);
+
+ rte_eth_dev_info_get(port_id, &dev_info);
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (strstr(dev_info.driver_name, "i40e") != NULL)
+ diag = rte_pmd_i40e_set_vf_vlan_filter(port_id, vlan_id,
+ vf_mask, on);
+ else
+#endif
+ diag = rte_eth_dev_set_vf_vlan_filter(port_id, vlan_id,
+ vf_mask, on);
+
if (diag == 0)
return;
printf("rte_eth_dev_set_vf_vlan_filter for port_id=%d failed "
--
1.9.3
^ permalink raw reply related
* [PATCH 24/31] app/testpmd: add command to test VF VLAN tag on i40e
From: Wenzhuo Lu @ 2016-12-02 0:12 UTC (permalink / raw)
To: dev; +Cc: Bernard Iremonger
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
command is: set vf vlan tag port_id vf_id on|off
Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
---
app/test-pmd/cmdline.c | 90 +++++++++++++++++++++++++++++
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 7 +++
2 files changed, 97 insertions(+)
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 56d275b..9135e45 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -301,6 +301,11 @@ static void cmd_help_long_parsed(void *parsed_result,
" Set VLAN antispoof for a VF from the PF.\n\n"
#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+ "set vf vlan tag (port_id) (vf_id) (on|off)\n"
+ " Set VLAN tag for a VF from the PF.\n\n"
+#endif
+
"vlan set filter (on|off) (port_id)\n"
" Set the VLAN filter on a port.\n\n"
@@ -11738,6 +11743,90 @@ struct cmd_set_vf_broadcast_result {
NULL,
},
};
+
+/* vf vlan tag configuration */
+
+/* Common result structure for vf vlan tag */
+struct cmd_set_vf_vlan_tag_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t vlan;
+ cmdline_fixed_string_t tag;
+ uint8_t port_id;
+ uint16_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for vf vlan tag enable disable */
+cmdline_parse_token_string_t cmd_set_vf_vlan_tag_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_vf_vlan_tag_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_set_vf_vlan_tag_vlan =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ vlan, "vlan");
+cmdline_parse_token_string_t cmd_set_vf_vlan_tag_tag =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ tag, "tag");
+cmdline_parse_token_num_t cmd_set_vf_vlan_tag_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_vf_vlan_tag_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ vf_id, UINT16);
+cmdline_parse_token_string_t cmd_set_vf_vlan_tag_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_vlan_tag_parsed(
+ void *parsed_result,
+ __attribute__((unused)) struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_set_vf_vlan_tag_result *res = parsed_result;
+ int ret;
+ int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ ret = rte_pmd_i40e_set_vf_vlan_tag(res->port_id, res->vf_id, is_on);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d or is_on %d\n", res->vf_id, is_on);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_vlan_tag = {
+ .f = cmd_set_vf_vlan_tag_parsed,
+ .data = NULL,
+ .help_str = "set vf vlan tag port_id vf_id on|off",
+ .tokens = {
+ (void *)&cmd_set_vf_vlan_tag_set,
+ (void *)&cmd_set_vf_vlan_tag_vf,
+ (void *)&cmd_set_vf_vlan_tag_vlan,
+ (void *)&cmd_set_vf_vlan_tag_tag,
+ (void *)&cmd_set_vf_vlan_tag_port_id,
+ (void *)&cmd_set_vf_vlan_tag_vf_id,
+ (void *)&cmd_set_vf_vlan_tag_on_off,
+ NULL,
+ },
+};
#endif
/* ******************************************************************************** */
@@ -11910,6 +11999,7 @@ struct cmd_set_vf_broadcast_result {
(cmdline_parse_inst_t *)&cmd_set_vf_unicast_promisc,
(cmdline_parse_inst_t *)&cmd_set_vf_multicast_promisc,
(cmdline_parse_inst_t *)&cmd_set_vf_broadcast,
+ (cmdline_parse_inst_t *)&cmd_set_vf_vlan_tag,
#endif
NULL,
};
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 525d0df..cffcac8 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -542,6 +542,13 @@ Set VLAN insert for a VF from the PF::
testpmd> set vf vlan insert (port_id) (vf_id) (vlan_id)
+vlan set tag (for VF)
+~~~~~~~~~~~~~~~~~~~~~
+
+Set VLAN tag for a VF from the PF::
+
+ testpmd> set vf vlan tag (port_id) (vf_id) (on|off)
+
vlan set antispoof (for VF)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
1.9.3
^ permalink raw reply related
* [PATCH 23/31] app/testpmd: add command to test VF broadcast mode on i40e
From: Wenzhuo Lu @ 2016-12-02 0:12 UTC (permalink / raw)
To: dev; +Cc: Bernard Iremonger
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
Add command to call rte_pmd_i40e_set_vf_broadcast.
Add set vf broadcast in testpmd_funcs.rst file.
Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
---
app/test-pmd/cmdline.c | 84 +++++++++++++++++++++++++++++
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 7 +++
2 files changed, 91 insertions(+)
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index fa60086..56d275b 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -279,6 +279,11 @@ static void cmd_help_long_parsed(void *parsed_result,
" Set MAC antispoof for a VF from the PF.\n\n"
#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+ "set vf broadcast (port_id) (vf_id) (on|off)\n"
+ " Set VF broadcast for a VF from the PF.\n\n"
+#endif
+
"vlan set strip (on|off) (port_id)\n"
" Set the VLAN strip on a port.\n\n"
@@ -11655,6 +11660,84 @@ struct cmd_vf_multicast_promisc_result {
NULL,
},
};
+
+/* vf broadcast mode configuration */
+
+/* Common result structure for vf broadcast */
+struct cmd_set_vf_broadcast_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t broadcast;
+ uint8_t port_id;
+ uint16_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for vf broadcast enable disable */
+cmdline_parse_token_string_t cmd_set_vf_broadcast_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_vf_broadcast_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_set_vf_broadcast_broadcast =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ broadcast, "broadcast");
+cmdline_parse_token_num_t cmd_set_vf_broadcast_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_vf_broadcast_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ vf_id, UINT16);
+cmdline_parse_token_string_t cmd_set_vf_broadcast_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_broadcast_parsed(
+ void *parsed_result,
+ __attribute__((unused)) struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_set_vf_broadcast_result *res = parsed_result;
+ int ret;
+ int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ ret = rte_pmd_i40e_set_vf_broadcast(res->port_id, res->vf_id, is_on);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d or is_on %d\n", res->vf_id, is_on);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_broadcast = {
+ .f = cmd_set_vf_broadcast_parsed,
+ .data = NULL,
+ .help_str = "set vf broadcast port_id vf_id on|off",
+ .tokens = {
+ (void *)&cmd_set_vf_broadcast_set,
+ (void *)&cmd_set_vf_broadcast_vf,
+ (void *)&cmd_set_vf_broadcast_broadcast,
+ (void *)&cmd_set_vf_broadcast_port_id,
+ (void *)&cmd_set_vf_broadcast_vf_id,
+ (void *)&cmd_set_vf_broadcast_on_off,
+ NULL,
+ },
+};
#endif
/* ******************************************************************************** */
@@ -11826,6 +11909,7 @@ struct cmd_vf_multicast_promisc_result {
#ifdef RTE_LIBRTE_I40E_PMD
(cmdline_parse_inst_t *)&cmd_set_vf_unicast_promisc,
(cmdline_parse_inst_t *)&cmd_set_vf_multicast_promisc,
+ (cmdline_parse_inst_t *)&cmd_set_vf_broadcast,
#endif
NULL,
};
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index e1545b7..525d0df 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -507,6 +507,13 @@ Set mac antispoof for a VF from the PF::
testpmd> set vf mac antispoof (port_id) (vf_id) (on|off)
+set broadcast mode (for VF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set broadcast mode for a VF from the PF::
+
+ testpmd> set vf broadcast (port_id) (vf_id) (on|off)
+
vlan set strip
~~~~~~~~~~~~~~
--
1.9.3
^ permalink raw reply related
* [PATCH 22/31] app/testpmd: use multicast promiscuous mode on i40e
From: Wenzhuo Lu @ 2016-12-02 0:12 UTC (permalink / raw)
To: dev; +Cc: Wenzhuo Lu
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
Add testpmd CLI to set VF multicast promiscuous mode on i40e.
Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
---
app/test-pmd/cmdline.c | 83 +++++++++++++++++++++++++++++
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 8 +++
2 files changed, 91 insertions(+)
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 3c0bb77..fa60086 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -407,6 +407,9 @@ static void cmd_help_long_parsed(void *parsed_result,
#ifdef RTE_LIBRTE_I40E_PMD
"set vf unicast-promisc (port_id) (vf_id) (on|off)\n"
" Set unicast promiscuous mode for a VF from the PF.\n\n"
+
+ "set vf multicast-promisc (port_id) (vf_id) (on|off)\n"
+ " Set multicast promiscuous mode for a VF from the PF.\n\n"
#endif
"set flow_ctrl rx (on|off) tx (on|off) (high_water)"
@@ -11573,6 +11576,85 @@ struct cmd_vf_unicast_promisc_result {
NULL,
},
};
+
+/* VF multicast promiscuous mode configuration */
+
+/* Common result structure for VF multicast promiscuous mode */
+struct cmd_vf_multicast_promisc_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t multicast_promisc;
+ uint8_t port_id;
+ uint32_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for VF multicast promiscuous mode enable disable */
+cmdline_parse_token_string_t cmd_vf_multicast_promisc_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_multicast_promisc_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vf_multicast_promisc_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_multicast_promisc_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_vf_multicast_promisc_multicast_promisc =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_multicast_promisc_result,
+ multicast_promisc, "multicast-promisc");
+cmdline_parse_token_num_t cmd_vf_multicast_promisc_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_multicast_promisc_result,
+ port_id, UINT8);
+cmdline_parse_token_num_t cmd_vf_multicast_promisc_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_multicast_promisc_result,
+ vf_id, UINT32);
+cmdline_parse_token_string_t cmd_vf_multicast_promisc_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_multicast_promisc_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_multicast_promisc_parsed(
+ void *parsed_result,
+ __attribute__((unused)) struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_vf_multicast_promisc_result *res = parsed_result;
+ int ret = 0;
+ int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ ret = rte_pmd_i40e_set_vf_multicast_promisc(res->port_id,
+ res->vf_id, is_on);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d\n", res->vf_id);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_multicast_promisc = {
+ .f = cmd_set_vf_multicast_promisc_parsed,
+ .data = NULL,
+ .help_str = "set vf multicast promiscuous port_id vf_id on|off",
+ .tokens = {
+ (void *)&cmd_vf_multicast_promisc_set,
+ (void *)&cmd_vf_multicast_promisc_vf,
+ (void *)&cmd_vf_multicast_promisc_multicast_promisc,
+ (void *)&cmd_vf_multicast_promisc_port_id,
+ (void *)&cmd_vf_multicast_promisc_vf_id,
+ (void *)&cmd_vf_multicast_promisc_on_off,
+ NULL,
+ },
+};
#endif
/* ******************************************************************************** */
@@ -11743,6 +11825,7 @@ struct cmd_vf_unicast_promisc_result {
#endif
#ifdef RTE_LIBRTE_I40E_PMD
(cmdline_parse_inst_t *)&cmd_set_vf_unicast_promisc,
+ (cmdline_parse_inst_t *)&cmd_set_vf_multicast_promisc,
#endif
NULL,
};
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index e17e3d5..e1545b7 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -828,6 +828,14 @@ In promiscuous mode packets are not dropped if they aren't for the specified MAC
testpmd> set vf unicast-promisc (port_id) (vf_id) (on|off)
+set multicast promisc (for VF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set the multicast promiscuous mode for a VF from PF.
+In promiscuous mode packets are not dropped if they aren't for the specified MAC address::
+
+ testpmd> set vf multicast-promisc (port_id) (vf_id) (on|off)
+
set flow_ctrl rx
~~~~~~~~~~~~~~~~
--
1.9.3
^ permalink raw reply related
* [PATCH 21/31] app/testpmd: use unicast promiscuous mode on i40e
From: Wenzhuo Lu @ 2016-12-02 0:12 UTC (permalink / raw)
To: dev; +Cc: Wenzhuo Lu
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
Add testpmd CLI to set VF unicast promiscuous mode on i40e.
Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
---
app/test-pmd/cmdline.c | 89 +++++++++++++++++++++++++++++
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 8 +++
2 files changed, 97 insertions(+)
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 1284d6c..3c0bb77 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -404,6 +404,11 @@ static void cmd_help_long_parsed(void *parsed_result,
"set allmulti (port_id|all) (on|off)\n"
" Set the allmulti mode on port_id, or all.\n\n"
+#ifdef RTE_LIBRTE_I40E_PMD
+ "set vf unicast-promisc (port_id) (vf_id) (on|off)\n"
+ " Set unicast promiscuous mode for a VF from the PF.\n\n"
+#endif
+
"set flow_ctrl rx (on|off) tx (on|off) (high_water)"
" (low_water) (pause_time) (send_xon) mac_ctrl_frame_fwd"
" (on|off) autoneg (on|off) (port_id)\n"
@@ -11489,6 +11494,87 @@ struct cmd_set_vf_mac_addr_result {
};
#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+/* VF unicast promiscuous mode configuration */
+
+/* Common result structure for VF unicast promiscuous mode */
+struct cmd_vf_unicast_promisc_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t unicast_promisc;
+ uint8_t port_id;
+ uint32_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for VF unicast promiscuous mode enable disable */
+cmdline_parse_token_string_t cmd_vf_unicast_promisc_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_unicast_promisc_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vf_unicast_promisc_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_unicast_promisc_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_vf_unicast_promisc_unicast_promisc =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_unicast_promisc_result,
+ unicast_promisc, "unicast-promisc");
+cmdline_parse_token_num_t cmd_vf_unicast_promisc_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_unicast_promisc_result,
+ port_id, UINT8);
+cmdline_parse_token_num_t cmd_vf_unicast_promisc_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_unicast_promisc_result,
+ vf_id, UINT32);
+cmdline_parse_token_string_t cmd_vf_unicast_promisc_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_unicast_promisc_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_unicast_promisc_parsed(
+ void *parsed_result,
+ __attribute__((unused)) struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_vf_unicast_promisc_result *res = parsed_result;
+ int ret = 0;
+ int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ ret = rte_pmd_i40e_set_vf_unicast_promisc(res->port_id,
+ res->vf_id, is_on);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d\n", res->vf_id);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_unicast_promisc = {
+ .f = cmd_set_vf_unicast_promisc_parsed,
+ .data = NULL,
+ .help_str = "set vf unicast promiscuous port_id vf_id on|off",
+ .tokens = {
+ (void *)&cmd_vf_unicast_promisc_set,
+ (void *)&cmd_vf_unicast_promisc_vf,
+ (void *)&cmd_vf_unicast_promisc_unicast_promisc,
+ (void *)&cmd_vf_unicast_promisc_port_id,
+ (void *)&cmd_vf_unicast_promisc_vf_id,
+ (void *)&cmd_vf_unicast_promisc_on_off,
+ NULL,
+ },
+};
+#endif
+
/* ******************************************************************************** */
/* list of instructions */
@@ -11655,6 +11741,9 @@ struct cmd_set_vf_mac_addr_result {
(cmdline_parse_inst_t *)&cmd_set_vf_split_drop_en,
(cmdline_parse_inst_t *)&cmd_set_vf_mac_addr,
#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+ (cmdline_parse_inst_t *)&cmd_set_vf_unicast_promisc,
+#endif
NULL,
};
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index f1c269a..e17e3d5 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -820,6 +820,14 @@ Set the allmulti mode for a port or for all ports::
Same as the ifconfig (8) option. Controls how multicast packets are handled.
+set unicast promisc (for VF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set the unicast promiscuous mode for a VF from PF.
+In promiscuous mode packets are not dropped if they aren't for the specified MAC address::
+
+ testpmd> set vf unicast-promisc (port_id) (vf_id) (on|off)
+
set flow_ctrl rx
~~~~~~~~~~~~~~~~
--
1.9.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox