[v4] app/testpmd: expand noisy neighbour forward mode support

Message ID 20230602182928.1717802-1-mkp@redhat.com (mailing list archive)
State Changes Requested, archived
Delegated to: Ferruh Yigit
Headers
Series [v4] app/testpmd: expand noisy neighbour forward mode support |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing success Unit Testing PASS
ci/Intel-compilation success Compilation OK
ci/intel-Testing success Testing PASS
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-testing success Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/github-robot: build fail github build: failed
ci/intel-Functional success Functional PASS
ci/iol-aarch64-compile-testing success Testing PASS
ci/iol-x86_64-unit-testing success Testing PASS
ci/iol-aarch-unit-testing success Testing PASS
ci/iol-abi-testing success Testing PASS
ci/iol-x86_64-compile-testing success Testing PASS
ci/iol-unit-testing success Testing PASS

Commit Message

Mike Pattrick June 2, 2023, 6:29 p.m. UTC
  Previously the noisy neighbour vnf simulation would only operate in io
mode, forwarding packets as is. However, this limited the usefulness of
noisy neighbour simulation.

This feature has now been expanded to supporting mac, macswap, and
5tswap modes. To facilitate adding this support, some new header files
were added.

Signed-off-by: Mike Pattrick <mkp@redhat.com>
 ---
 v2: Reverted changes to random memory lookup
 v3: Refactored entire patch
 v4: Implemented recommended formatting changes
---
 app/test-pmd/5tswap.c                 | 118 +----------------------
 app/test-pmd/5tswap.h                 | 130 ++++++++++++++++++++++++++
 app/test-pmd/macfwd.c                 |  33 +------
 app/test-pmd/macfwd.h                 |  45 +++++++++
 app/test-pmd/macswap.h                |   2 +-
 app/test-pmd/macswap_neon.h           |   2 +-
 app/test-pmd/macswap_sse.h            |   4 +-
 app/test-pmd/noisy_vnf.c              | 106 +++++++++++++++++----
 app/test-pmd/parameters.c             |  17 ++++
 app/test-pmd/testpmd.c                |   5 +
 app/test-pmd/testpmd.h                |   8 ++
 doc/guides/testpmd_app_ug/run_app.rst |   9 ++
 12 files changed, 313 insertions(+), 166 deletions(-)
 create mode 100644 app/test-pmd/5tswap.h
 create mode 100644 app/test-pmd/macfwd.h
  

Comments

Ferruh Yigit June 6, 2023, 2:27 p.m. UTC | #1
On 6/2/2023 7:29 PM, Mike Pattrick wrote:
> Previously the noisy neighbour vnf simulation would only operate in io
> mode, forwarding packets as is. However, this limited the usefulness of
> noisy neighbour simulation.
> 
> This feature has now been expanded to supporting mac, macswap, and
> 5tswap modes. To facilitate adding this support, some new header files
> were added.
> 
> Signed-off-by: Mike Pattrick <mkp@redhat.com>
>  ---
>  v2: Reverted changes to random memory lookup
>  v3: Refactored entire patch
>  v4: Implemented recommended formatting changes
> ---
>  app/test-pmd/5tswap.c                 | 118 +----------------------
>  app/test-pmd/5tswap.h                 | 130 ++++++++++++++++++++++++++
>  app/test-pmd/macfwd.c                 |  33 +------
>  app/test-pmd/macfwd.h                 |  45 +++++++++
>  app/test-pmd/macswap.h                |   2 +-
>  app/test-pmd/macswap_neon.h           |   2 +-
>  app/test-pmd/macswap_sse.h            |   4 +-
>  app/test-pmd/noisy_vnf.c              | 106 +++++++++++++++++----
>  app/test-pmd/parameters.c             |  17 ++++
>  app/test-pmd/testpmd.c                |   5 +
>  app/test-pmd/testpmd.h                |   8 ++
>  doc/guides/testpmd_app_ug/run_app.rst |   9 ++
>  12 files changed, 313 insertions(+), 166 deletions(-)
>  create mode 100644 app/test-pmd/5tswap.h
>  create mode 100644 app/test-pmd/macfwd.h
> 
> diff --git a/app/test-pmd/5tswap.c b/app/test-pmd/5tswap.c
> index ff8c2dcde5..8e8de2557a 100644
> --- a/app/test-pmd/5tswap.c
> +++ b/app/test-pmd/5tswap.c
> @@ -17,64 +17,8 @@
>  #include <rte_ip.h>
>  #include <rte_flow.h>
>  
> -#include "macswap_common.h"
>  #include "testpmd.h"
> -
> -
> -static inline void
> -swap_mac(struct rte_ether_hdr *eth_hdr)
> -{
> -	struct rte_ether_addr addr;
> -
> -	/* Swap dest and src mac addresses. */
> -	rte_ether_addr_copy(&eth_hdr->dst_addr, &addr);
> -	rte_ether_addr_copy(&eth_hdr->src_addr, &eth_hdr->dst_addr);
> -	rte_ether_addr_copy(&addr, &eth_hdr->src_addr);
> -}
> -
> -static inline void
> -swap_ipv4(struct rte_ipv4_hdr *ipv4_hdr)
> -{
> -	rte_be32_t addr;
> -
> -	/* Swap dest and src ipv4 addresses. */
> -	addr = ipv4_hdr->src_addr;
> -	ipv4_hdr->src_addr = ipv4_hdr->dst_addr;
> -	ipv4_hdr->dst_addr = addr;
> -}
> -
> -static inline void
> -swap_ipv6(struct rte_ipv6_hdr *ipv6_hdr)
> -{
> -	uint8_t addr[16];
> -
> -	/* Swap dest and src ipv6 addresses. */
> -	memcpy(&addr, &ipv6_hdr->src_addr, 16);
> -	memcpy(&ipv6_hdr->src_addr, &ipv6_hdr->dst_addr, 16);
> -	memcpy(&ipv6_hdr->dst_addr, &addr, 16);
> -}
> -
> -static inline void
> -swap_tcp(struct rte_tcp_hdr *tcp_hdr)
> -{
> -	rte_be16_t port;
> -
> -	/* Swap dest and src tcp port. */
> -	port = tcp_hdr->src_port;
> -	tcp_hdr->src_port = tcp_hdr->dst_port;
> -	tcp_hdr->dst_port = port;
> -}
> -
> -static inline void
> -swap_udp(struct rte_udp_hdr *udp_hdr)
> -{
> -	rte_be16_t port;
> -
> -	/* Swap dest and src udp port */
> -	port = udp_hdr->src_port;
> -	udp_hdr->src_port = udp_hdr->dst_port;
> -	udp_hdr->dst_port = port;
> -}
> +#include "5tswap.h"
>  
>  /*
>   * 5 tuple swap forwarding mode: Swap the source and the destination of layers
> @@ -85,22 +29,7 @@ static bool
>  pkt_burst_5tuple_swap(struct fwd_stream *fs)
>  {
>  	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
> -	struct rte_port  *txp;
> -	struct rte_mbuf *mb;
> -	uint16_t next_proto;
> -	uint64_t ol_flags;
> -	uint16_t proto;
>  	uint16_t nb_rx;
> -	int i;
> -	union {
> -		struct rte_ether_hdr *eth;
> -		struct rte_vlan_hdr *vlan;
> -		struct rte_ipv4_hdr *ipv4;
> -		struct rte_ipv6_hdr *ipv6;
> -		struct rte_tcp_hdr *tcp;
> -		struct rte_udp_hdr *udp;
> -		uint8_t *byte;
> -	} h;
>  
>  	/*
>  	 * Receive a burst of packets and forward them.
> @@ -109,49 +38,8 @@ pkt_burst_5tuple_swap(struct fwd_stream *fs)
>  	if (unlikely(nb_rx == 0))
>  		return false;
>  
> -	txp = &ports[fs->tx_port];
> -	ol_flags = ol_flags_init(txp->dev_conf.txmode.offloads);
> -	vlan_qinq_set(pkts_burst, nb_rx, ol_flags,
> -			txp->tx_vlan_id, txp->tx_vlan_id_outer);
> -	for (i = 0; i < nb_rx; i++) {
> -		if (likely(i < nb_rx - 1))
> -			rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i+1],
> -					void *));
> -		mb = pkts_burst[i];
> -		h.eth = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
> -		proto = h.eth->ether_type;
> -		swap_mac(h.eth);
> -		mb->l2_len = sizeof(struct rte_ether_hdr);
> -		h.eth++;
> -		while (proto == RTE_BE16(RTE_ETHER_TYPE_VLAN) ||
> -		       proto == RTE_BE16(RTE_ETHER_TYPE_QINQ)) {
> -			proto = h.vlan->eth_proto;
> -			h.vlan++;
> -			mb->l2_len += sizeof(struct rte_vlan_hdr);
> -		}
> -		if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV4)) {
> -			swap_ipv4(h.ipv4);
> -			next_proto = h.ipv4->next_proto_id;
> -			mb->l3_len = rte_ipv4_hdr_len(h.ipv4);
> -			h.byte += mb->l3_len;
> -		} else if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV6)) {
> -			swap_ipv6(h.ipv6);
> -			next_proto = h.ipv6->proto;
> -			h.ipv6++;
> -			mb->l3_len = sizeof(struct rte_ipv6_hdr);
> -		} else {
> -			mbuf_field_set(mb, ol_flags);
> -			continue;
> -		}
> -		if (next_proto == IPPROTO_UDP) {
> -			swap_udp(h.udp);
> -			mb->l4_len = sizeof(struct rte_udp_hdr);
> -		} else if (next_proto == IPPROTO_TCP) {
> -			swap_tcp(h.tcp);
> -			mb->l4_len = (h.tcp->data_off & 0xf0) >> 2;
> -		}
> -		mbuf_field_set(mb, ol_flags);
> -	}
> +	do_5tswap(pkts_burst, nb_rx, fs);
> +
>  	common_fwd_stream_transmit(fs, pkts_burst, nb_rx);
>  
>  	return true;
> diff --git a/app/test-pmd/5tswap.h b/app/test-pmd/5tswap.h
> new file mode 100644
> index 0000000000..974af1aacd
> --- /dev/null
> +++ b/app/test-pmd/5tswap.h
> @@ -0,0 +1,130 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Intel Corporation
>

I guess intention is to keep original file copyright owner, but it is
not Intel, can you please check again?

> + */
> +
> +#ifndef _5TSWAP_H_
> +#define _5TSWAP_H_
> +
> +#include "macswap_common.h"
> +
> +static inline void
> +swap_mac(struct rte_ether_hdr *eth_hdr)
> +{
> +	struct rte_ether_addr addr;
> +
> +	/* Swap dest and src mac addresses. */
> +	rte_ether_addr_copy(&eth_hdr->dst_addr, &addr);
> +	rte_ether_addr_copy(&eth_hdr->src_addr, &eth_hdr->dst_addr);
> +	rte_ether_addr_copy(&addr, &eth_hdr->src_addr);
> +}
> +
> +static inline void
> +swap_ipv4(struct rte_ipv4_hdr *ipv4_hdr)
> +{
> +	rte_be32_t addr;
> +
> +	/* Swap dest and src ipv4 addresses. */
> +	addr = ipv4_hdr->src_addr;
> +	ipv4_hdr->src_addr = ipv4_hdr->dst_addr;
> +	ipv4_hdr->dst_addr = addr;
> +}
> +
> +static inline void
> +swap_ipv6(struct rte_ipv6_hdr *ipv6_hdr)
> +{
> +	uint8_t addr[16];
> +
> +	/* Swap dest and src ipv6 addresses. */
> +	memcpy(&addr, &ipv6_hdr->src_addr, 16);
> +	memcpy(&ipv6_hdr->src_addr, &ipv6_hdr->dst_addr, 16);
> +	memcpy(&ipv6_hdr->dst_addr, &addr, 16);
> +}
> +
> +static inline void
> +swap_tcp(struct rte_tcp_hdr *tcp_hdr)
> +{
> +	rte_be16_t port;
> +
> +	/* Swap dest and src tcp port. */
> +	port = tcp_hdr->src_port;
> +	tcp_hdr->src_port = tcp_hdr->dst_port;
> +	tcp_hdr->dst_port = port;
> +}
> +
> +static inline void
> +swap_udp(struct rte_udp_hdr *udp_hdr)
> +{
> +	rte_be16_t port;
> +
> +	/* Swap dest and src udp port */
> +	port = udp_hdr->src_port;
> +	udp_hdr->src_port = udp_hdr->dst_port;
> +	udp_hdr->dst_port = port;
> +}
> +
> +static inline void
> +do_5tswap(struct rte_mbuf *pkts_burst[], uint16_t nb_rx,
> +	  struct fwd_stream *fs)
> +{
> +	struct rte_port  *txp;
> +	struct rte_mbuf *mb;
> +	uint16_t next_proto;
> +	uint64_t ol_flags;
> +	uint16_t proto;
> +	int i;
> +	union {
> +		struct rte_ether_hdr *eth;
> +		struct rte_vlan_hdr *vlan;
> +		struct rte_ipv4_hdr *ipv4;
> +		struct rte_ipv6_hdr *ipv6;
> +		struct rte_tcp_hdr *tcp;
> +		struct rte_udp_hdr *udp;
> +		uint8_t *byte;
> +	} h;
> +
> +	txp = &ports[fs->tx_port];
> +	ol_flags = ol_flags_init(txp->dev_conf.txmode.offloads);
> +	vlan_qinq_set(pkts_burst, nb_rx, ol_flags,
> +		      txp->tx_vlan_id, txp->tx_vlan_id_outer);
> +	for (i = 0; i < nb_rx; i++) {
> +		if (likely(i < nb_rx - 1))
> +			rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i+1],
> +						       void *));
> +		mb = pkts_burst[i];
> +		h.eth = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
> +		proto = h.eth->ether_type;
> +		swap_mac(h.eth);
> +		mb->l2_len = sizeof(struct rte_ether_hdr);
> +		h.eth++;
> +		while (proto == RTE_BE16(RTE_ETHER_TYPE_VLAN) ||
> +		       proto == RTE_BE16(RTE_ETHER_TYPE_QINQ)) {
> +			proto = h.vlan->eth_proto;
> +			h.vlan++;
> +			mb->l2_len += sizeof(struct rte_vlan_hdr);
> +		}
> +		if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV4)) {
> +			swap_ipv4(h.ipv4);
> +			next_proto = h.ipv4->next_proto_id;
> +			mb->l3_len = rte_ipv4_hdr_len(h.ipv4);
> +			h.byte += mb->l3_len;
> +		} else if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV6)) {
> +			swap_ipv6(h.ipv6);
> +			next_proto = h.ipv6->proto;
> +			h.ipv6++;
> +			mb->l3_len = sizeof(struct rte_ipv6_hdr);
> +		} else {
> +			mbuf_field_set(mb, ol_flags);
> +			continue;
> +		}
> +		if (next_proto == IPPROTO_UDP) {
> +			swap_udp(h.udp);
> +			mb->l4_len = sizeof(struct rte_udp_hdr);
> +		} else if (next_proto == IPPROTO_TCP) {
> +			swap_tcp(h.tcp);
> +			mb->l4_len = (h.tcp->data_off & 0xf0) >> 2;
> +		}
> +		mbuf_field_set(mb, ol_flags);
> +	}
> +}
> +
> +#endif /* _5TSWAP_H_ */
> diff --git a/app/test-pmd/macfwd.c b/app/test-pmd/macfwd.c
> index 7316d73315..d19ace7395 100644
> --- a/app/test-pmd/macfwd.c
> +++ b/app/test-pmd/macfwd.c
> @@ -35,6 +35,7 @@
>  #include <rte_flow.h>
>  
>  #include "testpmd.h"
> +#include "macfwd.h"
>  
>  /*
>   * Forwarding of packets in MAC mode.
> @@ -45,13 +46,7 @@ static bool
>  pkt_burst_mac_forward(struct fwd_stream *fs)
>  {
>  	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
> -	struct rte_port  *txp;
> -	struct rte_mbuf  *mb;
> -	struct rte_ether_hdr *eth_hdr;
>  	uint16_t nb_rx;
> -	uint16_t i;
> -	uint64_t ol_flags = 0;
> -	uint64_t tx_offloads;
>  
>  	/*
>  	 * Receive a burst of packets and forward them.
> @@ -60,31 +55,7 @@ pkt_burst_mac_forward(struct fwd_stream *fs)
>  	if (unlikely(nb_rx == 0))
>  		return false;
>  
> -	txp = &ports[fs->tx_port];
> -	tx_offloads = txp->dev_conf.txmode.offloads;
> -	if (tx_offloads	& RTE_ETH_TX_OFFLOAD_VLAN_INSERT)
> -		ol_flags = RTE_MBUF_F_TX_VLAN;
> -	if (tx_offloads & RTE_ETH_TX_OFFLOAD_QINQ_INSERT)
> -		ol_flags |= RTE_MBUF_F_TX_QINQ;
> -	if (tx_offloads & RTE_ETH_TX_OFFLOAD_MACSEC_INSERT)
> -		ol_flags |= RTE_MBUF_F_TX_MACSEC;
> -	for (i = 0; i < nb_rx; i++) {
> -		if (likely(i < nb_rx - 1))
> -			rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
> -						       void *));
> -		mb = pkts_burst[i];
> -		eth_hdr = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
> -		rte_ether_addr_copy(&peer_eth_addrs[fs->peer_addr],
> -				&eth_hdr->dst_addr);
> -		rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
> -				&eth_hdr->src_addr);
> -		mb->ol_flags &= RTE_MBUF_F_INDIRECT | RTE_MBUF_F_EXTERNAL;
> -		mb->ol_flags |= ol_flags;
> -		mb->l2_len = sizeof(struct rte_ether_hdr);
> -		mb->l3_len = sizeof(struct rte_ipv4_hdr);
> -		mb->vlan_tci = txp->tx_vlan_id;
> -		mb->vlan_tci_outer = txp->tx_vlan_id_outer;
> -	}
> +	do_macfwd(pkts_burst, nb_rx, fs);
>  
>  	common_fwd_stream_transmit(fs, pkts_burst, nb_rx);
>  
> diff --git a/app/test-pmd/macfwd.h b/app/test-pmd/macfwd.h
> new file mode 100644
> index 0000000000..69d9dfc64f
> --- /dev/null
> +++ b/app/test-pmd/macfwd.h
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Intel Corporation
> + */
> +
> +#ifndef _MACFWD_H_
> +#define _MACFWD_H_
> +
> +static inline void
> +do_macfwd(struct rte_mbuf *pkts_burst[], uint16_t nb_rx,
> +	  struct fwd_stream *fs)
> +{
> +	struct rte_ether_hdr *eth_hdr;
> +	uint64_t ol_flags = 0;
> +	uint64_t tx_offloads;
> +	struct rte_mbuf  *mb;
> +	struct rte_port *txp = &ports[fs->tx_port];
> +	uint16_t i;
> +
> +	tx_offloads = txp->dev_conf.txmode.offloads;
> +	if (tx_offloads	& RTE_ETH_TX_OFFLOAD_VLAN_INSERT)
> +		ol_flags = RTE_MBUF_F_TX_VLAN;
> +	if (tx_offloads & RTE_ETH_TX_OFFLOAD_QINQ_INSERT)
> +		ol_flags |= RTE_MBUF_F_TX_QINQ;
> +	if (tx_offloads & RTE_ETH_TX_OFFLOAD_MACSEC_INSERT)
> +		ol_flags |= RTE_MBUF_F_TX_MACSEC;
> +	for (i = 0; i < nb_rx; i++) {
> +		if (likely(i < nb_rx - 1))
> +			rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
> +						       void *));
> +		mb = pkts_burst[i];
> +		eth_hdr = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
> +		rte_ether_addr_copy(&peer_eth_addrs[fs->peer_addr],
> +				    &eth_hdr->dst_addr);
> +		rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
> +				    &eth_hdr->src_addr);
> +		mb->ol_flags &= RTE_MBUF_F_INDIRECT | RTE_MBUF_F_EXTERNAL;
> +		mb->ol_flags |= ol_flags;
> +		mb->l2_len = sizeof(struct rte_ether_hdr);
> +		mb->l3_len = sizeof(struct rte_ipv4_hdr);
> +		mb->vlan_tci = txp->tx_vlan_id;
> +		mb->vlan_tci_outer = txp->tx_vlan_id_outer;
> +	}
> +}
> +
> +#endif /* _MACFWD_H_ */
> diff --git a/app/test-pmd/macswap.h b/app/test-pmd/macswap.h
> index 29c252bb8f..7fea461e77 100644
> --- a/app/test-pmd/macswap.h
> +++ b/app/test-pmd/macswap.h
> @@ -9,7 +9,7 @@
>  
>  static inline void
>  do_macswap(struct rte_mbuf *pkts[], uint16_t nb,
> -		struct rte_port *txp)
> +	   struct rte_port *txp)
>  {
>  	struct rte_ether_hdr *eth_hdr;
>  	struct rte_mbuf *mb;
> diff --git a/app/test-pmd/macswap_neon.h b/app/test-pmd/macswap_neon.h
> index df6c260cd4..91d4cb7c2e 100644
> --- a/app/test-pmd/macswap_neon.h
> +++ b/app/test-pmd/macswap_neon.h
> @@ -14,7 +14,7 @@
>  
>  static inline void
>  do_macswap(struct rte_mbuf *pkts[], uint16_t nb,
> -		struct rte_port *txp)
> +	   struct rte_port *txp)
>  {
>  	struct rte_ether_hdr *eth_hdr[4];
>  	struct rte_mbuf *mb[4];
> diff --git a/app/test-pmd/macswap_sse.h b/app/test-pmd/macswap_sse.h
> index 223f87a539..e17cc07be0 100644
> --- a/app/test-pmd/macswap_sse.h
> +++ b/app/test-pmd/macswap_sse.h
> @@ -9,7 +9,7 @@
>  
>  static inline void
>  do_macswap(struct rte_mbuf *pkts[], uint16_t nb,
> -		struct rte_port *txp)
> +	   struct rte_port *txp)
>  {
>  	struct rte_ether_hdr *eth_hdr[4];
>  	struct rte_mbuf *mb[4];
> @@ -29,7 +29,7 @@ do_macswap(struct rte_mbuf *pkts[], uint16_t nb,
>  
>  	ol_flags = ol_flags_init(txp->dev_conf.txmode.offloads);
>  	vlan_qinq_set(pkts, nb, ol_flags,
> -			txp->tx_vlan_id, txp->tx_vlan_id_outer);
> +		      txp->tx_vlan_id, txp->tx_vlan_id_outer);
>  
>  	i = 0;
>  	r = nb;

Can you please remove these syntax changes, they are not just noise for
this patch?
And indeed original syntax looks correct, DPDK coding convention doesn't
allign parameters to the paranthesis, but uses tabs for next line.

> diff --git a/app/test-pmd/noisy_vnf.c b/app/test-pmd/noisy_vnf.c
> index 2bf90a983c..9b33930cab 100644
> --- a/app/test-pmd/noisy_vnf.c
> +++ b/app/test-pmd/noisy_vnf.c
> @@ -32,6 +32,18 @@
>  #include <rte_malloc.h>
>  
>  #include "testpmd.h"
> +#include "5tswap.h"
> +#include "macfwd.h"
> +#if defined(RTE_ARCH_X86)
> +#include "macswap_sse.h"
> +#elif defined(__ARM_NEON)
> +#include "macswap_neon.h"
> +#else
> +#include "macswap.h"
> +#endif
> +
> +#define NOISY_STRSIZE 256
> +#define NOISY_RING "noisy_ring_%d\n"
>  
>  struct noisy_config {
>  	struct rte_ring *f;
> @@ -80,9 +92,6 @@ sim_memory_lookups(struct noisy_config *ncf, uint16_t nb_pkts)
>  {
>  	uint16_t i, j;
>  
> -	if (!ncf->do_sim)
> -		return;
> -
>  	for (i = 0; i < nb_pkts; i++) {
>  		for (j = 0; j < noisy_lkup_num_writes; j++)
>  			do_write(ncf->vnf_mem);
> @@ -110,15 +119,13 @@ sim_memory_lookups(struct noisy_config *ncf, uint16_t nb_pkts)
>   *    out of the FIFO
>   * 4. Cases 2 and 3 combined
>   */
> -static bool
> -pkt_burst_noisy_vnf(struct fwd_stream *fs)
> +static uint16_t
> +noisy_eth_tx_burst(struct fwd_stream *fs, uint16_t nb_rx, struct rte_mbuf **pkts_burst)
>  {
>  	const uint64_t freq_khz = rte_get_timer_hz() / 1000;
>  	struct noisy_config *ncf = noisy_cfg[fs->rx_port];
> -	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
>  	struct rte_mbuf *tmp_pkts[MAX_PKT_BURST];
>  	uint16_t nb_deqd = 0;
> -	uint16_t nb_rx = 0;
>  	uint16_t nb_tx = 0;
>  	uint16_t nb_enqd;
>  	unsigned int fifo_free;
> @@ -126,12 +133,16 @@ pkt_burst_noisy_vnf(struct fwd_stream *fs)
>  	bool needs_flush = false;
>  	uint64_t now;
>  
> -	nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
> -	if (unlikely(nb_rx == 0))
> -		goto flush;
> +	if (unlikely(nb_rx == 0)) {
> +		if (!ncf->do_buffering)
> +			goto end;
> +		else
> +			goto flush;
> +	}
>  
>  	if (!ncf->do_buffering) {
> -		sim_memory_lookups(ncf, nb_rx);
> +		if (ncf->do_sim)
> +			sim_memory_lookups(ncf, nb_rx);
>  		nb_tx = common_fwd_stream_transmit(fs, pkts_burst, nb_rx);
>  		goto end;
>  	}
> @@ -150,7 +161,8 @@ pkt_burst_noisy_vnf(struct fwd_stream *fs)
>  			nb_tx = common_fwd_stream_transmit(fs, tmp_pkts, nb_deqd);
>  	}
>  
> -	sim_memory_lookups(ncf, nb_enqd);
> +	if (ncf->do_sim)
> +		sim_memory_lookups(ncf, nb_enqd);
>  
>  flush:
>  	if (ncf->do_flush) {
> @@ -169,11 +181,64 @@ pkt_burst_noisy_vnf(struct fwd_stream *fs)
>  		ncf->prev_time = rte_get_timer_cycles();
>  	}
>  end:
> +	return nb_tx;
> +}
> +
> +static bool
> +pkt_burst_io(struct fwd_stream *fs)
> +{
> +	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
> +	uint16_t nb_rx;
> +	uint16_t nb_tx;
> +
> +	nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
> +	nb_tx = noisy_eth_tx_burst(fs, nb_rx, pkts_burst);
> +
>  	return nb_rx > 0 || nb_tx > 0;
>  }
>  
> -#define NOISY_STRSIZE 256
> -#define NOISY_RING "noisy_ring_%d\n"
> +static bool
> +pkt_burst_mac(struct fwd_stream *fs)
> +{
> +	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
> +	uint16_t nb_rx;
> +	uint16_t nb_tx;
> +
> +	nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
> +	if (likely(nb_rx != 0))
> +		do_macfwd(pkts_burst, nb_rx, fs);
> +	nb_tx = noisy_eth_tx_burst(fs, nb_rx, pkts_burst);
> +
> +	return nb_rx > 0 || nb_tx > 0;
> +}
> +static bool
> +pkt_burst_macswap(struct fwd_stream *fs)
> +{
> +	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
> +	uint16_t nb_rx;
> +	uint16_t nb_tx;
> +
> +	nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
> +	if (likely(nb_rx != 0))
> +		do_macswap(pkts_burst, nb_rx, &ports[fs->tx_port]);
> +	nb_tx = noisy_eth_tx_burst(fs, nb_rx, pkts_burst);
> +
> +	return nb_rx > 0 || nb_tx > 0;
> +}
> +static bool
> +pkt_brust_5tswap(struct fwd_stream *fs)
> +{
> +	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
> +	uint16_t nb_rx;
> +	uint16_t nb_tx;
> +
> +	nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
> +	if (likely(nb_rx != 0))
> +		do_5tswap(pkts_burst, nb_rx, fs);
> +	nb_tx = noisy_eth_tx_burst(fs, nb_rx, pkts_burst);
> +
> +	return nb_rx > 0 || nb_tx > 0;
> +}
>  
>  static void
>  noisy_fwd_end(portid_t pi)
> @@ -226,6 +291,15 @@ noisy_fwd_begin(portid_t pi)
>  			 "--noisy-lkup-memory-size must be > 0\n");
>  	}
>  
> +	if (noisy_fwd_mode == NOISY_FWD_MODE_IO)
> +		noisy_vnf_engine.packet_fwd = pkt_burst_io;
> +	else if (noisy_fwd_mode == NOISY_FWD_MODE_MAC)
> +		noisy_vnf_engine.packet_fwd = pkt_burst_mac;
> +	else if (noisy_fwd_mode == NOISY_FWD_MODE_MACSWAP)
> +		noisy_vnf_engine.packet_fwd = pkt_burst_macswap;
> +	else if (noisy_fwd_mode == NOISY_FWD_MODE_5TSWAP)
> +		noisy_vnf_engine.packet_fwd = pkt_brust_5tswap;
> +
>  	return 0;
>  }
>  
> @@ -233,6 +307,6 @@ struct fwd_engine noisy_vnf_engine = {
>  	.fwd_mode_name  = "noisy",
>  	.port_fwd_begin = noisy_fwd_begin,
>  	.port_fwd_end   = noisy_fwd_end,
> -	.stream_init    = common_fwd_stream_init,
> -	.packet_fwd     = pkt_burst_noisy_vnf,
> +	.stream_init	= common_fwd_stream_init,
> +	.packet_fwd     = pkt_burst_io,
>  };
> diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
> index 3b37809baf..551714cce4 100644
> --- a/app/test-pmd/parameters.c
> +++ b/app/test-pmd/parameters.c
> @@ -196,6 +196,7 @@ usage(char* progname)
>  	printf("  --noisy-lkup-num-writes=N: do N random writes per packet\n");
>  	printf("  --noisy-lkup-num-reads=N: do N random reads per packet\n");
>  	printf("  --noisy-lkup-num-reads-writes=N: do N random reads and writes per packet\n");
> +	printf("  --noisy-fwd-mode=mode: set the fwd mode\n");

'--noisy-fwd-mode' looks more major config option comparing the other
'--noisy-lkup-*' ones, if so can you please move '--noisy-fwd-mode' up
to the top of the '--noisy-*' group?


Also what do you think to list possible values here, to help users, like
'io (default), mac, macswap, 5tswap'.

>  	printf("  --no-iova-contig: mempool memory can be IOVA non contiguous. "
>  	       "valid only with --mp-alloc=anon\n");
>  	printf("  --rx-mq-mode=0xX: hexadecimal bitmask of RX mq mode can be "
> @@ -704,6 +705,7 @@ launch_args_parse(int argc, char** argv)
>  		{ "noisy-lkup-num-writes",	1, 0, 0 },
>  		{ "noisy-lkup-num-reads",	1, 0, 0 },
>  		{ "noisy-lkup-num-reads-writes", 1, 0, 0 },
> +		{ "noisy-fwd-mode",             1, 0, 0 },
>  		{ "no-iova-contig",             0, 0, 0 },
>  		{ "rx-mq-mode",                 1, 0, 0 },
>  		{ "record-core-cycles",         0, 0, 0 },
> @@ -1444,6 +1446,21 @@ launch_args_parse(int argc, char** argv)
>  					rte_exit(EXIT_FAILURE,
>  						 "noisy-lkup-num-reads-writes must be >= 0\n");
>  			}
> +			if (!strcmp(lgopts[opt_idx].name,
> +				    "noisy-fwd-mode")) {
> +				if (!strcmp(optarg, "io"))
> +					noisy_fwd_mode = NOISY_FWD_MODE_IO;
> +				else if (!strcmp(optarg, "mac"))
> +					noisy_fwd_mode = NOISY_FWD_MODE_MAC;
> +				else if (!strcmp(optarg, "macswap"))
> +					noisy_fwd_mode = NOISY_FWD_MODE_MACSWAP;
> +				else if (!strcmp(optarg, "5tswap"))
> +					noisy_fwd_mode = NOISY_FWD_MODE_5TSWAP;
> +				else
> +					rte_exit(EXIT_FAILURE, "noisy-fwd-mode %s invalid -"
> +						 " must be a valid noisy-fwd-mode value\n",
> +						 optarg);
> +			}
>  			if (!strcmp(lgopts[opt_idx].name, "no-iova-contig"))
>  				mempool_flags = RTE_MEMPOOL_F_NO_IOVA_CONTIG;
>  
> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
> index 5cb6f92523..92784873ff 100644
> --- a/app/test-pmd/testpmd.c
> +++ b/app/test-pmd/testpmd.c
> @@ -364,6 +364,11 @@ uint64_t noisy_lkup_num_reads;
>   */
>  uint64_t noisy_lkup_num_reads_writes;
>  
> +/*
> + * Configurable forwarding mode in VNF simulation.

Kind of obvious from variable name but can you extend the comment to
give more detail that this is related to the noisy forwarding mode?

> + */
> +int noisy_fwd_mode;
> +

Why not define named enum and use it here, instead of 'int'?

>  /*
>   * Receive Side Scaling (RSS) configuration.
>   */
> diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
> index bdfbfd36d3..f70397ad26 100644
> --- a/app/test-pmd/testpmd.h
> +++ b/app/test-pmd/testpmd.h
> @@ -116,6 +116,13 @@ enum {
>  	QUEUE_JOB_TYPE_ACTION_QUERY,
>  };
>  
> +enum {
> +	NOISY_FWD_MODE_IO,
> +	NOISY_FWD_MODE_MAC,
> +	NOISY_FWD_MODE_MACSWAP,
> +	NOISY_FWD_MODE_5TSWAP
> +};
> +
>  /**
>   * The data structure associated with RX and TX packet burst statistics
>   * that are recorded for each forwarding stream.
> @@ -561,6 +568,7 @@ extern uint64_t noisy_lkup_mem_sz;
>  extern uint64_t noisy_lkup_num_writes;
>  extern uint64_t noisy_lkup_num_reads;
>  extern uint64_t noisy_lkup_num_reads_writes;
> +extern int noisy_fwd_mode;
>  
>  extern uint8_t dcb_config;
>  
> diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
> index 57b23241cf..fcca3e8921 100644
> --- a/doc/guides/testpmd_app_ug/run_app.rst
> +++ b/doc/guides/testpmd_app_ug/run_app.rst
> @@ -519,6 +519,15 @@ The command line options are:
>      Set the number of r/w accesses to be done in noisy neighbor simulation memory buffer to N.
>      Only available with the noisy forwarding mode. The default value is 0.
>  
> +*   ``--noisy-fwd-mode=mode``
> +
> +    Set the noisy vnf forwarding mode where ``mode`` is one of the following::
> +
> +       io (the default)
> +       mac
> +       macswap
> +       5tswap
> +
>  *   ``--no-iova-contig``
>  
>      Enable to create mempool which is not IOVA contiguous. Valid only with --mp-alloc=anon.
  

Patch

diff --git a/app/test-pmd/5tswap.c b/app/test-pmd/5tswap.c
index ff8c2dcde5..8e8de2557a 100644
--- a/app/test-pmd/5tswap.c
+++ b/app/test-pmd/5tswap.c
@@ -17,64 +17,8 @@ 
 #include <rte_ip.h>
 #include <rte_flow.h>
 
-#include "macswap_common.h"
 #include "testpmd.h"
-
-
-static inline void
-swap_mac(struct rte_ether_hdr *eth_hdr)
-{
-	struct rte_ether_addr addr;
-
-	/* Swap dest and src mac addresses. */
-	rte_ether_addr_copy(&eth_hdr->dst_addr, &addr);
-	rte_ether_addr_copy(&eth_hdr->src_addr, &eth_hdr->dst_addr);
-	rte_ether_addr_copy(&addr, &eth_hdr->src_addr);
-}
-
-static inline void
-swap_ipv4(struct rte_ipv4_hdr *ipv4_hdr)
-{
-	rte_be32_t addr;
-
-	/* Swap dest and src ipv4 addresses. */
-	addr = ipv4_hdr->src_addr;
-	ipv4_hdr->src_addr = ipv4_hdr->dst_addr;
-	ipv4_hdr->dst_addr = addr;
-}
-
-static inline void
-swap_ipv6(struct rte_ipv6_hdr *ipv6_hdr)
-{
-	uint8_t addr[16];
-
-	/* Swap dest and src ipv6 addresses. */
-	memcpy(&addr, &ipv6_hdr->src_addr, 16);
-	memcpy(&ipv6_hdr->src_addr, &ipv6_hdr->dst_addr, 16);
-	memcpy(&ipv6_hdr->dst_addr, &addr, 16);
-}
-
-static inline void
-swap_tcp(struct rte_tcp_hdr *tcp_hdr)
-{
-	rte_be16_t port;
-
-	/* Swap dest and src tcp port. */
-	port = tcp_hdr->src_port;
-	tcp_hdr->src_port = tcp_hdr->dst_port;
-	tcp_hdr->dst_port = port;
-}
-
-static inline void
-swap_udp(struct rte_udp_hdr *udp_hdr)
-{
-	rte_be16_t port;
-
-	/* Swap dest and src udp port */
-	port = udp_hdr->src_port;
-	udp_hdr->src_port = udp_hdr->dst_port;
-	udp_hdr->dst_port = port;
-}
+#include "5tswap.h"
 
 /*
  * 5 tuple swap forwarding mode: Swap the source and the destination of layers
@@ -85,22 +29,7 @@  static bool
 pkt_burst_5tuple_swap(struct fwd_stream *fs)
 {
 	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
-	struct rte_port  *txp;
-	struct rte_mbuf *mb;
-	uint16_t next_proto;
-	uint64_t ol_flags;
-	uint16_t proto;
 	uint16_t nb_rx;
-	int i;
-	union {
-		struct rte_ether_hdr *eth;
-		struct rte_vlan_hdr *vlan;
-		struct rte_ipv4_hdr *ipv4;
-		struct rte_ipv6_hdr *ipv6;
-		struct rte_tcp_hdr *tcp;
-		struct rte_udp_hdr *udp;
-		uint8_t *byte;
-	} h;
 
 	/*
 	 * Receive a burst of packets and forward them.
@@ -109,49 +38,8 @@  pkt_burst_5tuple_swap(struct fwd_stream *fs)
 	if (unlikely(nb_rx == 0))
 		return false;
 
-	txp = &ports[fs->tx_port];
-	ol_flags = ol_flags_init(txp->dev_conf.txmode.offloads);
-	vlan_qinq_set(pkts_burst, nb_rx, ol_flags,
-			txp->tx_vlan_id, txp->tx_vlan_id_outer);
-	for (i = 0; i < nb_rx; i++) {
-		if (likely(i < nb_rx - 1))
-			rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i+1],
-					void *));
-		mb = pkts_burst[i];
-		h.eth = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
-		proto = h.eth->ether_type;
-		swap_mac(h.eth);
-		mb->l2_len = sizeof(struct rte_ether_hdr);
-		h.eth++;
-		while (proto == RTE_BE16(RTE_ETHER_TYPE_VLAN) ||
-		       proto == RTE_BE16(RTE_ETHER_TYPE_QINQ)) {
-			proto = h.vlan->eth_proto;
-			h.vlan++;
-			mb->l2_len += sizeof(struct rte_vlan_hdr);
-		}
-		if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV4)) {
-			swap_ipv4(h.ipv4);
-			next_proto = h.ipv4->next_proto_id;
-			mb->l3_len = rte_ipv4_hdr_len(h.ipv4);
-			h.byte += mb->l3_len;
-		} else if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV6)) {
-			swap_ipv6(h.ipv6);
-			next_proto = h.ipv6->proto;
-			h.ipv6++;
-			mb->l3_len = sizeof(struct rte_ipv6_hdr);
-		} else {
-			mbuf_field_set(mb, ol_flags);
-			continue;
-		}
-		if (next_proto == IPPROTO_UDP) {
-			swap_udp(h.udp);
-			mb->l4_len = sizeof(struct rte_udp_hdr);
-		} else if (next_proto == IPPROTO_TCP) {
-			swap_tcp(h.tcp);
-			mb->l4_len = (h.tcp->data_off & 0xf0) >> 2;
-		}
-		mbuf_field_set(mb, ol_flags);
-	}
+	do_5tswap(pkts_burst, nb_rx, fs);
+
 	common_fwd_stream_transmit(fs, pkts_burst, nb_rx);
 
 	return true;
diff --git a/app/test-pmd/5tswap.h b/app/test-pmd/5tswap.h
new file mode 100644
index 0000000000..974af1aacd
--- /dev/null
+++ b/app/test-pmd/5tswap.h
@@ -0,0 +1,130 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _5TSWAP_H_
+#define _5TSWAP_H_
+
+#include "macswap_common.h"
+
+static inline void
+swap_mac(struct rte_ether_hdr *eth_hdr)
+{
+	struct rte_ether_addr addr;
+
+	/* Swap dest and src mac addresses. */
+	rte_ether_addr_copy(&eth_hdr->dst_addr, &addr);
+	rte_ether_addr_copy(&eth_hdr->src_addr, &eth_hdr->dst_addr);
+	rte_ether_addr_copy(&addr, &eth_hdr->src_addr);
+}
+
+static inline void
+swap_ipv4(struct rte_ipv4_hdr *ipv4_hdr)
+{
+	rte_be32_t addr;
+
+	/* Swap dest and src ipv4 addresses. */
+	addr = ipv4_hdr->src_addr;
+	ipv4_hdr->src_addr = ipv4_hdr->dst_addr;
+	ipv4_hdr->dst_addr = addr;
+}
+
+static inline void
+swap_ipv6(struct rte_ipv6_hdr *ipv6_hdr)
+{
+	uint8_t addr[16];
+
+	/* Swap dest and src ipv6 addresses. */
+	memcpy(&addr, &ipv6_hdr->src_addr, 16);
+	memcpy(&ipv6_hdr->src_addr, &ipv6_hdr->dst_addr, 16);
+	memcpy(&ipv6_hdr->dst_addr, &addr, 16);
+}
+
+static inline void
+swap_tcp(struct rte_tcp_hdr *tcp_hdr)
+{
+	rte_be16_t port;
+
+	/* Swap dest and src tcp port. */
+	port = tcp_hdr->src_port;
+	tcp_hdr->src_port = tcp_hdr->dst_port;
+	tcp_hdr->dst_port = port;
+}
+
+static inline void
+swap_udp(struct rte_udp_hdr *udp_hdr)
+{
+	rte_be16_t port;
+
+	/* Swap dest and src udp port */
+	port = udp_hdr->src_port;
+	udp_hdr->src_port = udp_hdr->dst_port;
+	udp_hdr->dst_port = port;
+}
+
+static inline void
+do_5tswap(struct rte_mbuf *pkts_burst[], uint16_t nb_rx,
+	  struct fwd_stream *fs)
+{
+	struct rte_port  *txp;
+	struct rte_mbuf *mb;
+	uint16_t next_proto;
+	uint64_t ol_flags;
+	uint16_t proto;
+	int i;
+	union {
+		struct rte_ether_hdr *eth;
+		struct rte_vlan_hdr *vlan;
+		struct rte_ipv4_hdr *ipv4;
+		struct rte_ipv6_hdr *ipv6;
+		struct rte_tcp_hdr *tcp;
+		struct rte_udp_hdr *udp;
+		uint8_t *byte;
+	} h;
+
+	txp = &ports[fs->tx_port];
+	ol_flags = ol_flags_init(txp->dev_conf.txmode.offloads);
+	vlan_qinq_set(pkts_burst, nb_rx, ol_flags,
+		      txp->tx_vlan_id, txp->tx_vlan_id_outer);
+	for (i = 0; i < nb_rx; i++) {
+		if (likely(i < nb_rx - 1))
+			rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i+1],
+						       void *));
+		mb = pkts_burst[i];
+		h.eth = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
+		proto = h.eth->ether_type;
+		swap_mac(h.eth);
+		mb->l2_len = sizeof(struct rte_ether_hdr);
+		h.eth++;
+		while (proto == RTE_BE16(RTE_ETHER_TYPE_VLAN) ||
+		       proto == RTE_BE16(RTE_ETHER_TYPE_QINQ)) {
+			proto = h.vlan->eth_proto;
+			h.vlan++;
+			mb->l2_len += sizeof(struct rte_vlan_hdr);
+		}
+		if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV4)) {
+			swap_ipv4(h.ipv4);
+			next_proto = h.ipv4->next_proto_id;
+			mb->l3_len = rte_ipv4_hdr_len(h.ipv4);
+			h.byte += mb->l3_len;
+		} else if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV6)) {
+			swap_ipv6(h.ipv6);
+			next_proto = h.ipv6->proto;
+			h.ipv6++;
+			mb->l3_len = sizeof(struct rte_ipv6_hdr);
+		} else {
+			mbuf_field_set(mb, ol_flags);
+			continue;
+		}
+		if (next_proto == IPPROTO_UDP) {
+			swap_udp(h.udp);
+			mb->l4_len = sizeof(struct rte_udp_hdr);
+		} else if (next_proto == IPPROTO_TCP) {
+			swap_tcp(h.tcp);
+			mb->l4_len = (h.tcp->data_off & 0xf0) >> 2;
+		}
+		mbuf_field_set(mb, ol_flags);
+	}
+}
+
+#endif /* _5TSWAP_H_ */
diff --git a/app/test-pmd/macfwd.c b/app/test-pmd/macfwd.c
index 7316d73315..d19ace7395 100644
--- a/app/test-pmd/macfwd.c
+++ b/app/test-pmd/macfwd.c
@@ -35,6 +35,7 @@ 
 #include <rte_flow.h>
 
 #include "testpmd.h"
+#include "macfwd.h"
 
 /*
  * Forwarding of packets in MAC mode.
@@ -45,13 +46,7 @@  static bool
 pkt_burst_mac_forward(struct fwd_stream *fs)
 {
 	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
-	struct rte_port  *txp;
-	struct rte_mbuf  *mb;
-	struct rte_ether_hdr *eth_hdr;
 	uint16_t nb_rx;
-	uint16_t i;
-	uint64_t ol_flags = 0;
-	uint64_t tx_offloads;
 
 	/*
 	 * Receive a burst of packets and forward them.
@@ -60,31 +55,7 @@  pkt_burst_mac_forward(struct fwd_stream *fs)
 	if (unlikely(nb_rx == 0))
 		return false;
 
-	txp = &ports[fs->tx_port];
-	tx_offloads = txp->dev_conf.txmode.offloads;
-	if (tx_offloads	& RTE_ETH_TX_OFFLOAD_VLAN_INSERT)
-		ol_flags = RTE_MBUF_F_TX_VLAN;
-	if (tx_offloads & RTE_ETH_TX_OFFLOAD_QINQ_INSERT)
-		ol_flags |= RTE_MBUF_F_TX_QINQ;
-	if (tx_offloads & RTE_ETH_TX_OFFLOAD_MACSEC_INSERT)
-		ol_flags |= RTE_MBUF_F_TX_MACSEC;
-	for (i = 0; i < nb_rx; i++) {
-		if (likely(i < nb_rx - 1))
-			rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
-						       void *));
-		mb = pkts_burst[i];
-		eth_hdr = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
-		rte_ether_addr_copy(&peer_eth_addrs[fs->peer_addr],
-				&eth_hdr->dst_addr);
-		rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
-				&eth_hdr->src_addr);
-		mb->ol_flags &= RTE_MBUF_F_INDIRECT | RTE_MBUF_F_EXTERNAL;
-		mb->ol_flags |= ol_flags;
-		mb->l2_len = sizeof(struct rte_ether_hdr);
-		mb->l3_len = sizeof(struct rte_ipv4_hdr);
-		mb->vlan_tci = txp->tx_vlan_id;
-		mb->vlan_tci_outer = txp->tx_vlan_id_outer;
-	}
+	do_macfwd(pkts_burst, nb_rx, fs);
 
 	common_fwd_stream_transmit(fs, pkts_burst, nb_rx);
 
diff --git a/app/test-pmd/macfwd.h b/app/test-pmd/macfwd.h
new file mode 100644
index 0000000000..69d9dfc64f
--- /dev/null
+++ b/app/test-pmd/macfwd.h
@@ -0,0 +1,45 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _MACFWD_H_
+#define _MACFWD_H_
+
+static inline void
+do_macfwd(struct rte_mbuf *pkts_burst[], uint16_t nb_rx,
+	  struct fwd_stream *fs)
+{
+	struct rte_ether_hdr *eth_hdr;
+	uint64_t ol_flags = 0;
+	uint64_t tx_offloads;
+	struct rte_mbuf  *mb;
+	struct rte_port *txp = &ports[fs->tx_port];
+	uint16_t i;
+
+	tx_offloads = txp->dev_conf.txmode.offloads;
+	if (tx_offloads	& RTE_ETH_TX_OFFLOAD_VLAN_INSERT)
+		ol_flags = RTE_MBUF_F_TX_VLAN;
+	if (tx_offloads & RTE_ETH_TX_OFFLOAD_QINQ_INSERT)
+		ol_flags |= RTE_MBUF_F_TX_QINQ;
+	if (tx_offloads & RTE_ETH_TX_OFFLOAD_MACSEC_INSERT)
+		ol_flags |= RTE_MBUF_F_TX_MACSEC;
+	for (i = 0; i < nb_rx; i++) {
+		if (likely(i < nb_rx - 1))
+			rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
+						       void *));
+		mb = pkts_burst[i];
+		eth_hdr = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
+		rte_ether_addr_copy(&peer_eth_addrs[fs->peer_addr],
+				    &eth_hdr->dst_addr);
+		rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
+				    &eth_hdr->src_addr);
+		mb->ol_flags &= RTE_MBUF_F_INDIRECT | RTE_MBUF_F_EXTERNAL;
+		mb->ol_flags |= ol_flags;
+		mb->l2_len = sizeof(struct rte_ether_hdr);
+		mb->l3_len = sizeof(struct rte_ipv4_hdr);
+		mb->vlan_tci = txp->tx_vlan_id;
+		mb->vlan_tci_outer = txp->tx_vlan_id_outer;
+	}
+}
+
+#endif /* _MACFWD_H_ */
diff --git a/app/test-pmd/macswap.h b/app/test-pmd/macswap.h
index 29c252bb8f..7fea461e77 100644
--- a/app/test-pmd/macswap.h
+++ b/app/test-pmd/macswap.h
@@ -9,7 +9,7 @@ 
 
 static inline void
 do_macswap(struct rte_mbuf *pkts[], uint16_t nb,
-		struct rte_port *txp)
+	   struct rte_port *txp)
 {
 	struct rte_ether_hdr *eth_hdr;
 	struct rte_mbuf *mb;
diff --git a/app/test-pmd/macswap_neon.h b/app/test-pmd/macswap_neon.h
index df6c260cd4..91d4cb7c2e 100644
--- a/app/test-pmd/macswap_neon.h
+++ b/app/test-pmd/macswap_neon.h
@@ -14,7 +14,7 @@ 
 
 static inline void
 do_macswap(struct rte_mbuf *pkts[], uint16_t nb,
-		struct rte_port *txp)
+	   struct rte_port *txp)
 {
 	struct rte_ether_hdr *eth_hdr[4];
 	struct rte_mbuf *mb[4];
diff --git a/app/test-pmd/macswap_sse.h b/app/test-pmd/macswap_sse.h
index 223f87a539..e17cc07be0 100644
--- a/app/test-pmd/macswap_sse.h
+++ b/app/test-pmd/macswap_sse.h
@@ -9,7 +9,7 @@ 
 
 static inline void
 do_macswap(struct rte_mbuf *pkts[], uint16_t nb,
-		struct rte_port *txp)
+	   struct rte_port *txp)
 {
 	struct rte_ether_hdr *eth_hdr[4];
 	struct rte_mbuf *mb[4];
@@ -29,7 +29,7 @@  do_macswap(struct rte_mbuf *pkts[], uint16_t nb,
 
 	ol_flags = ol_flags_init(txp->dev_conf.txmode.offloads);
 	vlan_qinq_set(pkts, nb, ol_flags,
-			txp->tx_vlan_id, txp->tx_vlan_id_outer);
+		      txp->tx_vlan_id, txp->tx_vlan_id_outer);
 
 	i = 0;
 	r = nb;
diff --git a/app/test-pmd/noisy_vnf.c b/app/test-pmd/noisy_vnf.c
index 2bf90a983c..9b33930cab 100644
--- a/app/test-pmd/noisy_vnf.c
+++ b/app/test-pmd/noisy_vnf.c
@@ -32,6 +32,18 @@ 
 #include <rte_malloc.h>
 
 #include "testpmd.h"
+#include "5tswap.h"
+#include "macfwd.h"
+#if defined(RTE_ARCH_X86)
+#include "macswap_sse.h"
+#elif defined(__ARM_NEON)
+#include "macswap_neon.h"
+#else
+#include "macswap.h"
+#endif
+
+#define NOISY_STRSIZE 256
+#define NOISY_RING "noisy_ring_%d\n"
 
 struct noisy_config {
 	struct rte_ring *f;
@@ -80,9 +92,6 @@  sim_memory_lookups(struct noisy_config *ncf, uint16_t nb_pkts)
 {
 	uint16_t i, j;
 
-	if (!ncf->do_sim)
-		return;
-
 	for (i = 0; i < nb_pkts; i++) {
 		for (j = 0; j < noisy_lkup_num_writes; j++)
 			do_write(ncf->vnf_mem);
@@ -110,15 +119,13 @@  sim_memory_lookups(struct noisy_config *ncf, uint16_t nb_pkts)
  *    out of the FIFO
  * 4. Cases 2 and 3 combined
  */
-static bool
-pkt_burst_noisy_vnf(struct fwd_stream *fs)
+static uint16_t
+noisy_eth_tx_burst(struct fwd_stream *fs, uint16_t nb_rx, struct rte_mbuf **pkts_burst)
 {
 	const uint64_t freq_khz = rte_get_timer_hz() / 1000;
 	struct noisy_config *ncf = noisy_cfg[fs->rx_port];
-	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
 	struct rte_mbuf *tmp_pkts[MAX_PKT_BURST];
 	uint16_t nb_deqd = 0;
-	uint16_t nb_rx = 0;
 	uint16_t nb_tx = 0;
 	uint16_t nb_enqd;
 	unsigned int fifo_free;
@@ -126,12 +133,16 @@  pkt_burst_noisy_vnf(struct fwd_stream *fs)
 	bool needs_flush = false;
 	uint64_t now;
 
-	nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
-	if (unlikely(nb_rx == 0))
-		goto flush;
+	if (unlikely(nb_rx == 0)) {
+		if (!ncf->do_buffering)
+			goto end;
+		else
+			goto flush;
+	}
 
 	if (!ncf->do_buffering) {
-		sim_memory_lookups(ncf, nb_rx);
+		if (ncf->do_sim)
+			sim_memory_lookups(ncf, nb_rx);
 		nb_tx = common_fwd_stream_transmit(fs, pkts_burst, nb_rx);
 		goto end;
 	}
@@ -150,7 +161,8 @@  pkt_burst_noisy_vnf(struct fwd_stream *fs)
 			nb_tx = common_fwd_stream_transmit(fs, tmp_pkts, nb_deqd);
 	}
 
-	sim_memory_lookups(ncf, nb_enqd);
+	if (ncf->do_sim)
+		sim_memory_lookups(ncf, nb_enqd);
 
 flush:
 	if (ncf->do_flush) {
@@ -169,11 +181,64 @@  pkt_burst_noisy_vnf(struct fwd_stream *fs)
 		ncf->prev_time = rte_get_timer_cycles();
 	}
 end:
+	return nb_tx;
+}
+
+static bool
+pkt_burst_io(struct fwd_stream *fs)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	uint16_t nb_rx;
+	uint16_t nb_tx;
+
+	nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
+	nb_tx = noisy_eth_tx_burst(fs, nb_rx, pkts_burst);
+
 	return nb_rx > 0 || nb_tx > 0;
 }
 
-#define NOISY_STRSIZE 256
-#define NOISY_RING "noisy_ring_%d\n"
+static bool
+pkt_burst_mac(struct fwd_stream *fs)
+{
+	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
+	uint16_t nb_rx;
+	uint16_t nb_tx;
+
+	nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
+	if (likely(nb_rx != 0))
+		do_macfwd(pkts_burst, nb_rx, fs);
+	nb_tx = noisy_eth_tx_burst(fs, nb_rx, pkts_burst);
+
+	return nb_rx > 0 || nb_tx > 0;
+}
+static bool
+pkt_burst_macswap(struct fwd_stream *fs)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	uint16_t nb_rx;
+	uint16_t nb_tx;
+
+	nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
+	if (likely(nb_rx != 0))
+		do_macswap(pkts_burst, nb_rx, &ports[fs->tx_port]);
+	nb_tx = noisy_eth_tx_burst(fs, nb_rx, pkts_burst);
+
+	return nb_rx > 0 || nb_tx > 0;
+}
+static bool
+pkt_brust_5tswap(struct fwd_stream *fs)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	uint16_t nb_rx;
+	uint16_t nb_tx;
+
+	nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
+	if (likely(nb_rx != 0))
+		do_5tswap(pkts_burst, nb_rx, fs);
+	nb_tx = noisy_eth_tx_burst(fs, nb_rx, pkts_burst);
+
+	return nb_rx > 0 || nb_tx > 0;
+}
 
 static void
 noisy_fwd_end(portid_t pi)
@@ -226,6 +291,15 @@  noisy_fwd_begin(portid_t pi)
 			 "--noisy-lkup-memory-size must be > 0\n");
 	}
 
+	if (noisy_fwd_mode == NOISY_FWD_MODE_IO)
+		noisy_vnf_engine.packet_fwd = pkt_burst_io;
+	else if (noisy_fwd_mode == NOISY_FWD_MODE_MAC)
+		noisy_vnf_engine.packet_fwd = pkt_burst_mac;
+	else if (noisy_fwd_mode == NOISY_FWD_MODE_MACSWAP)
+		noisy_vnf_engine.packet_fwd = pkt_burst_macswap;
+	else if (noisy_fwd_mode == NOISY_FWD_MODE_5TSWAP)
+		noisy_vnf_engine.packet_fwd = pkt_brust_5tswap;
+
 	return 0;
 }
 
@@ -233,6 +307,6 @@  struct fwd_engine noisy_vnf_engine = {
 	.fwd_mode_name  = "noisy",
 	.port_fwd_begin = noisy_fwd_begin,
 	.port_fwd_end   = noisy_fwd_end,
-	.stream_init    = common_fwd_stream_init,
-	.packet_fwd     = pkt_burst_noisy_vnf,
+	.stream_init	= common_fwd_stream_init,
+	.packet_fwd     = pkt_burst_io,
 };
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 3b37809baf..551714cce4 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -196,6 +196,7 @@  usage(char* progname)
 	printf("  --noisy-lkup-num-writes=N: do N random writes per packet\n");
 	printf("  --noisy-lkup-num-reads=N: do N random reads per packet\n");
 	printf("  --noisy-lkup-num-reads-writes=N: do N random reads and writes per packet\n");
+	printf("  --noisy-fwd-mode=mode: set the fwd mode\n");
 	printf("  --no-iova-contig: mempool memory can be IOVA non contiguous. "
 	       "valid only with --mp-alloc=anon\n");
 	printf("  --rx-mq-mode=0xX: hexadecimal bitmask of RX mq mode can be "
@@ -704,6 +705,7 @@  launch_args_parse(int argc, char** argv)
 		{ "noisy-lkup-num-writes",	1, 0, 0 },
 		{ "noisy-lkup-num-reads",	1, 0, 0 },
 		{ "noisy-lkup-num-reads-writes", 1, 0, 0 },
+		{ "noisy-fwd-mode",             1, 0, 0 },
 		{ "no-iova-contig",             0, 0, 0 },
 		{ "rx-mq-mode",                 1, 0, 0 },
 		{ "record-core-cycles",         0, 0, 0 },
@@ -1444,6 +1446,21 @@  launch_args_parse(int argc, char** argv)
 					rte_exit(EXIT_FAILURE,
 						 "noisy-lkup-num-reads-writes must be >= 0\n");
 			}
+			if (!strcmp(lgopts[opt_idx].name,
+				    "noisy-fwd-mode")) {
+				if (!strcmp(optarg, "io"))
+					noisy_fwd_mode = NOISY_FWD_MODE_IO;
+				else if (!strcmp(optarg, "mac"))
+					noisy_fwd_mode = NOISY_FWD_MODE_MAC;
+				else if (!strcmp(optarg, "macswap"))
+					noisy_fwd_mode = NOISY_FWD_MODE_MACSWAP;
+				else if (!strcmp(optarg, "5tswap"))
+					noisy_fwd_mode = NOISY_FWD_MODE_5TSWAP;
+				else
+					rte_exit(EXIT_FAILURE, "noisy-fwd-mode %s invalid -"
+						 " must be a valid noisy-fwd-mode value\n",
+						 optarg);
+			}
 			if (!strcmp(lgopts[opt_idx].name, "no-iova-contig"))
 				mempool_flags = RTE_MEMPOOL_F_NO_IOVA_CONTIG;
 
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 5cb6f92523..92784873ff 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -364,6 +364,11 @@  uint64_t noisy_lkup_num_reads;
  */
 uint64_t noisy_lkup_num_reads_writes;
 
+/*
+ * Configurable forwarding mode in VNF simulation.
+ */
+int noisy_fwd_mode;
+
 /*
  * Receive Side Scaling (RSS) configuration.
  */
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index bdfbfd36d3..f70397ad26 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -116,6 +116,13 @@  enum {
 	QUEUE_JOB_TYPE_ACTION_QUERY,
 };
 
+enum {
+	NOISY_FWD_MODE_IO,
+	NOISY_FWD_MODE_MAC,
+	NOISY_FWD_MODE_MACSWAP,
+	NOISY_FWD_MODE_5TSWAP
+};
+
 /**
  * The data structure associated with RX and TX packet burst statistics
  * that are recorded for each forwarding stream.
@@ -561,6 +568,7 @@  extern uint64_t noisy_lkup_mem_sz;
 extern uint64_t noisy_lkup_num_writes;
 extern uint64_t noisy_lkup_num_reads;
 extern uint64_t noisy_lkup_num_reads_writes;
+extern int noisy_fwd_mode;
 
 extern uint8_t dcb_config;
 
diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
index 57b23241cf..fcca3e8921 100644
--- a/doc/guides/testpmd_app_ug/run_app.rst
+++ b/doc/guides/testpmd_app_ug/run_app.rst
@@ -519,6 +519,15 @@  The command line options are:
     Set the number of r/w accesses to be done in noisy neighbor simulation memory buffer to N.
     Only available with the noisy forwarding mode. The default value is 0.
 
+*   ``--noisy-fwd-mode=mode``
+
+    Set the noisy vnf forwarding mode where ``mode`` is one of the following::
+
+       io (the default)
+       mac
+       macswap
+       5tswap
+
 *   ``--no-iova-contig``
 
     Enable to create mempool which is not IOVA contiguous. Valid only with --mp-alloc=anon.