From 2564abda35db93ff75dd78d8e231c212ebb8cfc9 Mon Sep 17 00:00:00 2001 From: Shiri Kuzin Date: Thu, 2 Jul 2020 18:16:14 +0300 Subject: [PATCH] app/testpmd: add 5-tuple swap forwarding engine The new 5-tuple swap engine swaps: source and destination mac address, source and destination address in ipv4/ipv6, source and destination port in UDP/TCP. The forwarding engine will parse each layer and swap it, and will stop when the next layer doesn't match. The mentioned headers of ICMP/ARP/Multicast packets will be swapped as well according to matching layers. usage: --forward-mode=5tswap Signed-off-by: Shiri Kuzin Acked-by: Matan Azrad Reviewed-by: Ferruh Yigit --- app/test-pmd/5tswap.c | 208 ++++++++++++++++++++ app/test-pmd/Makefile | 1 + app/test-pmd/meson.build | 3 +- app/test-pmd/parameters.c | 2 + app/test-pmd/testpmd.c | 1 + app/test-pmd/testpmd.h | 1 + doc/guides/rel_notes/release_20_08.rst | 6 + doc/guides/testpmd_app_ug/run_app.rst | 1 + doc/guides/testpmd_app_ug/testpmd_funcs.rst | 10 +- 9 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 app/test-pmd/5tswap.c diff --git a/app/test-pmd/5tswap.c b/app/test-pmd/5tswap.c new file mode 100644 index 0000000000..972f6b93b3 --- /dev/null +++ b/app/test-pmd/5tswap.c @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright 2014-2020 Mellanox Technologies, Ltd + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#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(ð_hdr->d_addr, &addr); + rte_ether_addr_copy(ð_hdr->s_addr, ð_hdr->d_addr); + rte_ether_addr_copy(&addr, ð_hdr->s_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; +} + +/* + * 5 tuple swap forwarding mode: Swap the source and the destination of layers + * 2,3,4. Swaps source and destination for MAC, IPv4/IPv6, UDP/TCP. + * Parses each layer and swaps it. When the next layer doesn't match it stops. + */ +static void +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; + uint16_t nb_tx; + uint32_t retry; + + 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; + +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + uint64_t start_tsc; + uint64_t end_tsc; + uint64_t core_cycles; +#endif + +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + start_tsc = rte_rdtsc(); +#endif + + /* + * Receive a burst of packets and forward them. + */ + nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst, + nb_pkt_per_burst); + if (unlikely(nb_rx == 0)) + return; + +#ifdef RTE_TEST_PMD_RECORD_BURST_STATS + fs->rx_burst_stats.pkt_burst_spread[nb_rx]++; +#endif + + fs->rx_packets += nb_rx; + 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 = (h.ipv4->version_ihl & 0x0f) * 4; + 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); + } + nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx); + /* + * Retry if necessary + */ + if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) { + retry = 0; + while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) { + rte_delay_us(burst_tx_delay_time); + nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue, + &pkts_burst[nb_tx], nb_rx - nb_tx); + } + } + fs->tx_packets += nb_tx; +#ifdef RTE_TEST_PMD_RECORD_BURST_STATS + fs->tx_burst_stats.pkt_burst_spread[nb_tx]++; +#endif + if (unlikely(nb_tx < nb_rx)) { + fs->fwd_dropped += (nb_rx - nb_tx); + do { + rte_pktmbuf_free(pkts_burst[nb_tx]); + } while (++nb_tx < nb_rx); + } +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + end_tsc = rte_rdtsc(); + core_cycles = (end_tsc - start_tsc); + fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles); +#endif +} + +struct fwd_engine five_tuple_swap_fwd_engine = { + .fwd_mode_name = "5tswap", + .port_fwd_begin = NULL, + .port_fwd_end = NULL, + .packet_fwd = pkt_burst_5tuple_swap, +}; diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile index 4eab42f186..e739797f8a 100644 --- a/app/test-pmd/Makefile +++ b/app/test-pmd/Makefile @@ -33,6 +33,7 @@ SRCS-y += txonly.c SRCS-y += csumonly.c SRCS-y += icmpecho.c SRCS-y += noisy_vnf.c +SRCS-y += 5tswap.c SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c SRCS-$(CONFIG_RTE_LIBRTE_BPF) += bpf_cmd.c SRCS-y += util.c diff --git a/app/test-pmd/meson.build b/app/test-pmd/meson.build index 750fe3bfdb..ea56e547bb 100644 --- a/app/test-pmd/meson.build +++ b/app/test-pmd/meson.build @@ -4,7 +4,8 @@ # override default name to drop the hyphen name = 'testpmd' cflags += '-Wno-deprecated-declarations' -sources = files('cmdline.c', +sources = files('5tswap.c', + 'cmdline.c', 'cmdline_flow.c', 'cmdline_mtr.c', 'cmdline_tm.c', diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index f761e14707..7cb0e3d6ec 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -147,6 +147,8 @@ usage(char* progname) "is default).\n"); printf(" --forward-mode=N: set forwarding mode (N: %s).\n", list_pkt_forwarding_modes()); + printf(" --forward-mode=5tswap: set forwarding mode to " + "swap L2,L3,L4 for MAC, IPv4/IPv6 and TCP/UDP only.\n"); printf(" --rss-ip: set RSS functions to IPv4/IPv6 only .\n"); printf(" --rss-udp: set RSS functions to IPv4/IPv6 + UDP.\n"); printf(" --rxq=N: set the number of RX queues per port to N.\n"); diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 626cb7b2d9..7842c3b781 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -179,6 +179,7 @@ struct fwd_engine * fwd_engines[] = { &csum_fwd_engine, &icmp_echo_engine, &noisy_vnf_engine, + &five_tuple_swap_fwd_engine, #ifdef RTE_LIBRTE_IEEE1588 &ieee1588_fwd_engine, #endif diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 2d0409f4fb..25a12b14f2 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -247,6 +247,7 @@ extern struct fwd_engine tx_only_engine; extern struct fwd_engine csum_fwd_engine; extern struct fwd_engine icmp_echo_engine; extern struct fwd_engine noisy_vnf_engine; +extern struct fwd_engine five_tuple_swap_fwd_engine; #ifdef RTE_LIBRTE_IEEE1588 extern struct fwd_engine ieee1588_fwd_engine; #endif diff --git a/doc/guides/rel_notes/release_20_08.rst b/doc/guides/rel_notes/release_20_08.rst index 2ca12fa5ca..3e07ee6223 100644 --- a/doc/guides/rel_notes/release_20_08.rst +++ b/doc/guides/rel_notes/release_20_08.rst @@ -199,6 +199,12 @@ New Features which are used to access packet data in a safe manner. Currently JIT support for these instructions is implemented for x86 only. +* **Added new testpmd forward mode.** + + Added new ``5tswap`` forward mode to testpmd. + the ``5tswap`` swaps source and destination in layers 2,3,4 + for ipv4 and ipv6 in L3 and UDP and TCP in L4. + * **Added flow performance test application.** Added new application to test ``rte_flow`` performance, including: diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst index f169604752..d1e4ee3e7a 100644 --- a/doc/guides/testpmd_app_ug/run_app.rst +++ b/doc/guides/testpmd_app_ug/run_app.rst @@ -248,6 +248,7 @@ The command line options are: ieee1588 tm noisy + 5tswap * ``--rss-ip`` diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst index 5cbcf78a13..f8cfb02e38 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -300,7 +300,7 @@ set fwd Set the packet forwarding mode:: testpmd> set fwd (io|mac|macswap|flowgen| \ - rxonly|txonly|csum|icmpecho|noisy) (""|retry) + rxonly|txonly|csum|icmpecho|noisy|5tswap) (""|retry) ``retry`` can be specified for forwarding engines except ``rx_only``. @@ -335,6 +335,14 @@ The available information categories are: Simulate more realistic behavior of a guest machine engaged in receiving and sending packets performing Virtual Network Function (VNF). +* ``5tswap``: Swap the source and destination of L2,L3,L4 if they exist. + + L2 swaps the source address and destination address of Ethernet, as same as ``macswap``. + + L3 swaps the source address and destination address of IP (v4 and v6). + + L4 swaps the source port and destination port of transport layer (TCP and UDP). + Example:: testpmd> set fwd rxonly -- 2.20.1