From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 7D648A00C2; Tue, 3 Jan 2023 03:30:39 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 3425240693; Tue, 3 Jan 2023 03:30:39 +0100 (CET) Received: from chinatelecom.cn (prt-mail.chinatelecom.cn [42.123.76.220]) by mails.dpdk.org (Postfix) with ESMTP id 6C1FC40689 for ; Tue, 3 Jan 2023 03:30:35 +0100 (CET) HMM_SOURCE_IP: 172.18.0.48:42718.656936018 HMM_ATTACHE_NUM: 0000 HMM_SOURCE_TYPE: SMTP Received: from clientip-101.43.140.16 (unknown [172.18.0.48]) by chinatelecom.cn (HERMES) with SMTP id 0DC312800C2; Tue, 3 Jan 2023 10:30:28 +0800 (CST) X-189-SAVE-TO-SEND: +wushaohua@chinatelecom.cn Received: from ([101.43.140.16]) by app0024 with ESMTP id f7ebcf956b3c4c0a9d6ee9d2fffac710 for dev@dpdk.org; Tue, 03 Jan 2023 10:30:31 CST X-Transaction-ID: f7ebcf956b3c4c0a9d6ee9d2fffac710 X-Real-From: wushaohua@chinatelecom.cn X-Receive-IP: 101.43.140.16 X-MEDUSA-Status: 0 Sender: wushaohua@chinatelecom.cn From: wushaohua@chinatelecom.cn To: dev@dpdk.org Cc: aman.deep.singh@intel.com, yuying.zhang@intel.com, wushaohua@chinatelecom.cn Subject: [PATCH] app/testpmd:add vxlan txonly Date: Tue, 3 Jan 2023 10:30:27 +0800 Message-Id: <20230103023027.1893801-1-wushaohua@chinatelecom.cn> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Shaohua Wu Add the vxlan packet sending module to actively send vxlan packets using a common network adapter. The default vni is 1000. example: ./dpdk-testpmd -l 32-47 -n 16 --file-prefix pg0 -- -i --rxq=16 --txq=16 --rxd=1024 --txd=1024 --txpkts=64 --burst=64 --mbuf-size=4096 --nb-cores=15 --underlay_tx_only --underlay-eth-peer=0,f0:00:00:00:00:66 --eth-peer=0,08:c0:eb:3e:87:af --utx-ip=11.0.0.1,11.0.0.2 --tx-ip=30.0.0.1,30.0.0.2 --forward-mode=tuntxonly --txonly-multi-flow Signed-off-by: Shaohua Wu --- app/test-pmd/cmdline.c | 47 ++++ app/test-pmd/config.c | 15 ++ app/test-pmd/meson.build | 1 + app/test-pmd/parameters.c | 44 ++++ app/test-pmd/testpmd.c | 26 +- app/test-pmd/testpmd.h | 11 +- app/test-pmd/txonly.c | 4 + app/test-pmd/vxlan.c | 534 ++++++++++++++++++++++++++++++++++++++ app/test-pmd/vxlan.h | 23 ++ 9 files changed, 700 insertions(+), 5 deletions(-) create mode 100644 app/test-pmd/vxlan.c create mode 100644 app/test-pmd/vxlan.h diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index b32dc8bfd4..a82214a6b1 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -12621,6 +12621,52 @@ static cmdline_parse_inst_t cmd_show_port_flow_transfer_proxy = { } }; +struct cmd_underlay_eth_peer_result { + cmdline_fixed_string_t set; + cmdline_fixed_string_t underlay_eth_peer; + portid_t port_id; + cmdline_fixed_string_t underlay_peer_addr; +}; + +static void cmd_set_underlay_eth_peer_parsed(void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ + struct cmd_underlay_eth_peer_result *res = parsed_result; + + if (test_done == 0) { + fprintf(stderr, "Please stop forwarding first\n"); + return; + } + if (!strcmp(res->underlay_eth_peer, "underlay-eth-peer")) { + set_fwd_underlay_eth_peer(res->port_id, res->underlay_peer_addr); + fwd_config_setup(); + } +} + +static cmdline_parse_token_string_t cmd_underlay_eth_peer_set = + TOKEN_STRING_INITIALIZER(struct cmd_underlay_eth_peer_result, set, "set"); +static cmdline_parse_token_string_t cmd_underlay_eth_peer = + TOKEN_STRING_INITIALIZER(struct cmd_underlay_eth_peer_result, underlay_eth_peer, "underlay-eth-peer"); +static cmdline_parse_token_num_t cmd_underlay_eth_peer_port_id = + TOKEN_NUM_INITIALIZER(struct cmd_underlay_eth_peer_result, port_id, + RTE_UINT16); +static cmdline_parse_token_string_t cmd_underlay_eth_peer_addr = + TOKEN_STRING_INITIALIZER(struct cmd_underlay_eth_peer_result, underlay_peer_addr, NULL); + +static cmdline_parse_inst_t cmd_set_fwd_underlay_eth_peer = { + .f = cmd_set_underlay_eth_peer_parsed, + .data = NULL, + .help_str = "set underlay-eth-peer ", + .tokens = { + (void *)&cmd_underlay_eth_peer_set, + (void *)&cmd_underlay_eth_peer, + (void *)&cmd_underlay_eth_peer_port_id, + (void *)&cmd_underlay_eth_peer_addr, + NULL, + }, +}; + /* ******************************************************************************** */ /* list of instructions */ @@ -12851,6 +12897,7 @@ static cmdline_parse_ctx_t builtin_ctx[] = { (cmdline_parse_inst_t *)&cmd_show_capability, (cmdline_parse_inst_t *)&cmd_set_flex_is_pattern, (cmdline_parse_inst_t *)&cmd_set_flex_spec_pattern, + (cmdline_parse_inst_t *)&cmd_set_fwd_underlay_eth_peer, NULL, }; diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index acccb6b035..af878314bf 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -4769,6 +4769,21 @@ set_fwd_eth_peer(portid_t port_id, char *peer_addr) } peer_eth_addrs[port_id] = new_peer_addr; } +void +set_fwd_underlay_eth_peer(portid_t port_id, char *peer_addr) +{ + struct rte_ether_addr new_peer_addr; + if (!rte_eth_dev_is_valid_port(port_id)) { + fprintf(stderr, "Error: Invalid port number %i\n", port_id); + return; + } + if (rte_ether_unformat_addr(peer_addr, &new_peer_addr) < 0) { + fprintf(stderr, "Error: Invalid ethernet address: %s\n", + peer_addr); + return; + } + peer_underlay_eth_addrs[port_id] = new_peer_addr; +} int set_fwd_lcores_list(unsigned int *lcorelist, unsigned int nb_lc) diff --git a/app/test-pmd/meson.build b/app/test-pmd/meson.build index 8488efc138..5f0de21996 100644 --- a/app/test-pmd/meson.build +++ b/app/test-pmd/meson.build @@ -26,6 +26,7 @@ sources = files( 'testpmd.c', 'txonly.c', 'util.c', + 'vxlan.c' ) if dpdk_conf.has('RTE_HAS_JANSSON') diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index d597c209ba..ca152f0294 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -603,6 +603,7 @@ launch_args_parse(int argc, char** argv) { "auto-start", 0, 0, 0 }, { "eth-peers-configfile", 1, 0, 0 }, { "eth-peer", 1, 0, 0 }, + { "underlay-eth-peer", 1, 0, 0 }, #endif { "tx-first", 0, 0, 0 }, { "stats-period", 1, 0, 0 }, @@ -693,6 +694,8 @@ launch_args_parse(int argc, char** argv) { "mp-alloc", 1, 0, 0 }, { "tx-ip", 1, 0, 0 }, { "tx-udp", 1, 0, 0 }, + { "utx-ip", 1, 0, 0 }, + { "underlay_tx_only", 0, 0, 0 }, { "noisy-tx-sw-buffer-size", 1, 0, 0 }, { "noisy-tx-sw-buffer-flushtime", 1, 0, 0 }, { "noisy-lkup-memory", 1, 0, 0 }, @@ -803,6 +806,47 @@ launch_args_parse(int argc, char** argv) nb_peer_eth_addrs++; } #endif + if (!strcmp(lgopts[opt_idx].name, "underlay-eth-peer")) { + char *port_end; + + errno = 0; + n = strtoul(optarg, &port_end, 10); + if (errno != 0 || port_end == optarg || *port_end++ != ',') + rte_exit(EXIT_FAILURE, + "Invalid underlay-eth-peer: %s", optarg); + if (n >= RTE_MAX_ETHPORTS) + rte_exit(EXIT_FAILURE, + "eth-peer: port %d >= RTE_MAX_ETHPORTS(%d)\n", + n, RTE_MAX_ETHPORTS); + + if (rte_ether_unformat_addr(port_end, + &peer_underlay_eth_addrs[n]) < 0) + rte_exit(EXIT_FAILURE, + "Invalid ethernet address: %s\n", + port_end); + } + if (!strcmp(lgopts[opt_idx].name, "utx-ip")) { + struct in_addr in; + char *end; + + end = strchr(optarg, ','); + if (end == optarg || !end) + rte_exit(EXIT_FAILURE, + "Invalid tx-sip: %s", optarg); + + *end++ = 0; + if (inet_pton(AF_INET, optarg, &in) == 0) + rte_exit(EXIT_FAILURE, + "Invalid source IP address: %s\n", + optarg); + underlay_tx_ip_src_addr = rte_be_to_cpu_32(in.s_addr); + + if (inet_pton(AF_INET, end, &in) == 0) + rte_exit(EXIT_FAILURE, + "Invalid destination IP address: %s\n", + optarg); + underlay_tx_ip_dst_addr = rte_be_to_cpu_32(in.s_addr); + } if (!strcmp(lgopts[opt_idx].name, "tx-ip")) { struct in_addr in; char *end; diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 134d79a555..5d177fa02e 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -156,7 +156,10 @@ uint8_t txring_numa[RTE_MAX_ETHPORTS]; * ports. */ struct rte_ether_addr peer_eth_addrs[RTE_MAX_ETHPORTS]; -portid_t nb_peer_eth_addrs = 0; +struct rte_ether_addr peer_underlay_eth_addrs[RTE_MAX_ETHPORTS]; +portid_t nb_peer_eth_addrs; +portid_t nb_underlay_peer_eth_addr; +bool is_underlay_tx_only; /* * Probed Target Environment. @@ -194,6 +197,7 @@ struct fwd_engine * fwd_engines[] = { &flow_gen_engine, &rx_only_engine, &tx_only_engine, + &tun_tx_only_engine, &csum_fwd_engine, &icmp_echo_engine, &noisy_vnf_engine, @@ -257,6 +261,7 @@ uint8_t multi_rx_mempool; /**< Enables multi-rx-mempool feature */ uint16_t tx_pkt_length = TXONLY_DEF_PACKET_LEN; /**< TXONLY packet length. */ uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT] = { TXONLY_DEF_PACKET_LEN, + VXLAN_TXONLY_DEF_PACKET_LEN, }; uint8_t tx_pkt_nb_segs = 1; /**< Number of segments in TXONLY packets */ @@ -759,6 +764,8 @@ set_def_peer_eth_addrs(void) for (i = 0; i < RTE_MAX_ETHPORTS; i++) { peer_eth_addrs[i].addr_bytes[0] = RTE_ETHER_LOCAL_ADMIN_ADDR; peer_eth_addrs[i].addr_bytes[5] = i; + peer_underlay_eth_addrs[i].addr_bytes[0] = RTE_ETHER_LOCAL_ADMIN_ADDR; + peer_underlay_eth_addrs[i].addr_bytes[5] = i; } } @@ -2309,7 +2316,10 @@ run_one_txonly_burst_on_core(void *fwd_arg) fwd_lc = (struct fwd_lcore *) fwd_arg; tmp_lcore = *fwd_lc; tmp_lcore.stopped = 1; - run_pkt_fwd_on_lcore(&tmp_lcore, tx_only_engine.packet_fwd); + if (is_underlay_tx_only) + run_pkt_fwd_on_lcore(&tmp_lcore, tun_tx_only_engine.packet_fwd); + else + run_pkt_fwd_on_lcore(&tmp_lcore, tx_only_engine.packet_fwd); return 0; } @@ -2394,7 +2404,11 @@ start_packet_forwarding(int with_tx_first) } if (with_tx_first) { - port_fwd_begin = tx_only_engine.port_fwd_begin; + if (is_underlay_tx_only) { + port_fwd_begin = tun_tx_only_engine.port_fwd_begin; + } else { + port_fwd_begin = tx_only_engine.port_fwd_begin; + } if (port_fwd_begin != NULL) { for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++) { if (port_fwd_begin(fwd_ports_ids[i])) { @@ -2420,7 +2434,11 @@ start_packet_forwarding(int with_tx_first) run_one_txonly_burst_on_core); rte_eal_mp_wait_lcore(); } - port_fwd_end = tx_only_engine.port_fwd_end; + if (is_underlay_tx_only) { + port_fwd_end = tun_tx_only_engine.port_fwd_end; + } else { + port_fwd_end = tx_only_engine.port_fwd_end; + } if (port_fwd_end != NULL) { for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++) (*port_fwd_end)(fwd_ports_ids[i]); diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 7d24d25970..eb749736e8 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -423,6 +423,7 @@ extern struct fwd_engine mac_swap_engine; extern struct fwd_engine flow_gen_engine; extern struct fwd_engine rx_only_engine; extern struct fwd_engine tx_only_engine; +extern struct fwd_engine tun_tx_only_engine; extern struct fwd_engine csum_fwd_engine; extern struct fwd_engine icmp_echo_engine; extern struct fwd_engine noisy_vnf_engine; @@ -598,6 +599,7 @@ extern uint8_t multi_rx_mempool; /**< Enables multi-rx-mempool feature. */ * Configuration of packet segments used by the "txonly" processing engine. */ #define TXONLY_DEF_PACKET_LEN 64 +#define VXLAN_TXONLY_DEF_PACKET_LEN 128 extern uint16_t tx_pkt_length; /**< Length of TXONLY packet */ extern uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT]; /**< Seg. lengths */ extern uint8_t tx_pkt_nb_segs; /**< Number of segments in TX packets */ @@ -630,9 +632,15 @@ extern int8_t tx_wthresh; extern uint16_t tx_udp_src_port; extern uint16_t tx_udp_dst_port; +extern uint16_t underlay_tx_udp_src_port; +extern uint16_t underlay_tx_udp_dst_port; + extern uint32_t tx_ip_src_addr; extern uint32_t tx_ip_dst_addr; +extern uint32_t underlay_tx_ip_src_addr; +extern uint32_t underlay_tx_ip_dst_addr; + extern struct fwd_config cur_fwd_config; extern struct fwd_engine *cur_fwd_eng; extern uint32_t retry_enabled; @@ -644,6 +652,7 @@ extern uint16_t geneve_udp_port; /**< UDP port of tunnel GENEVE. */ extern portid_t nb_peer_eth_addrs; /**< Number of peer ethernet addresses. */ extern struct rte_ether_addr peer_eth_addrs[RTE_MAX_ETHPORTS]; +extern struct rte_ether_addr peer_underlay_eth_addrs[RTE_MAX_ETHPORTS]; extern uint32_t burst_tx_delay_time; /**< Burst tx delay time(us) for mac-retry. */ extern uint32_t burst_tx_retry_num; /**< Burst tx retry number for mac-retry. */ @@ -892,7 +901,7 @@ int init_fwd_streams(void); void update_fwd_ports(portid_t new_pid); void set_fwd_eth_peer(portid_t port_id, char *peer_addr); - +void set_fwd_underlay_eth_peer(portid_t port_id, char *peer_addr); void port_mtu_set(portid_t port_id, uint16_t mtu); int port_action_handle_create(portid_t port_id, uint32_t id, const struct rte_flow_indir_action_conf *conf, diff --git a/app/test-pmd/txonly.c b/app/test-pmd/txonly.c index 021624952d..9bc04722a0 100644 --- a/app/test-pmd/txonly.c +++ b/app/test-pmd/txonly.c @@ -48,10 +48,14 @@ struct tx_timestamp { /* use RFC863 Discard Protocol */ uint16_t tx_udp_src_port = 9; uint16_t tx_udp_dst_port = 9; +uint16_t underlay_tx_udp_src_port = 9; +uint16_t underlay_tx_udp_dst_port = 4789; /* use RFC5735 / RFC2544 reserved network test addresses */ uint32_t tx_ip_src_addr = (198U << 24) | (18 << 16) | (0 << 8) | 1; uint32_t tx_ip_dst_addr = (198U << 24) | (18 << 16) | (0 << 8) | 2; +uint32_t underlay_tx_ip_src_addr = (198U << 24) | (18 << 16) | (0 << 8) | 1; +uint32_t underlay_tx_ip_dst_addr = (198U << 24) | (18 << 16) | (0 << 8) | 2; #define IP_DEFTTL 64 /* from RFC 1340. */ diff --git a/app/test-pmd/vxlan.c b/app/test-pmd/vxlan.c new file mode 100644 index 0000000000..52e7b1b486 --- /dev/null +++ b/app/test-pmd/vxlan.c @@ -0,0 +1,534 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vxlan.h" +#include "testpmd.h" +struct tx_timestamp { + rte_be32_t signature; + rte_be16_t pkt_idx; + rte_be16_t queue_idx; + rte_be64_t ts; +}; +uint16_t tun_tx_pkt_length = VXLAN_TXONLY_DEF_PACKET_LEN; +static struct rte_ipv4_hdr pkt_ip_hdr; /**< IP header of transmitted packets. */ +RTE_DEFINE_PER_LCORE(uint8_t, __ip_var); /**< IP address variation */ +static struct rte_udp_hdr pkt_udp_hdr; /**< UDP header of tx packets. */ +struct encap_vxlan_ipv4_vlan_data pkt_vxlan_hdr; +static uint64_t timestamp_mask; /**< Timestamp dynamic flag mask */ +static int32_t timestamp_off; /**< Timestamp dynamic field offset */ +static bool timestamp_enable; /**< Timestamp enable */ +static uint64_t timestamp_initial[RTE_MAX_ETHPORTS]; + +static void +copy_buf_to_pkt_segs(void *buf, unsigned int len, + struct rte_mbuf *pkt, unsigned int offset) +{ + struct rte_mbuf *seg; + void *seg_buf; + unsigned int copy_len; + + seg = pkt; + while (offset >= seg->data_len) { + offset -= seg->data_len; + seg = seg->next; + } + copy_len = seg->data_len - offset; + seg_buf = rte_pktmbuf_mtod_offset(seg, char *, offset); + while (len > copy_len) { + rte_memcpy(seg_buf, buf, (size_t) copy_len); + len -= copy_len; + buf = ((char *) buf + copy_len); + seg = seg->next; + seg_buf = rte_pktmbuf_mtod(seg, char *); + copy_len = seg->data_len; + } + rte_memcpy(seg_buf, buf, (size_t) len); +} + +static inline void +copy_buf_to_pkt(void *buf, unsigned int len, + struct rte_mbuf *pkt, unsigned int offset) +{ + if (offset + len <= pkt->data_len) { + rte_memcpy(rte_pktmbuf_mtod_offset(pkt, + char *, offset), + buf, (size_t) len); + return; + } + copy_buf_to_pkt_segs(buf, len, pkt, offset); +} + +static void +set_innter_eth_hdr_apply(struct rte_ipv4_hdr *ip_hdr, + struct rte_udp_hdr *udp_hdr, + uint16_t pkt_data_len) +{ + uint16_t *ptr16; + uint32_t ip_cksum; + uint16_t pkt_len; + /* + * Initialize UDP header. + */ + pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_udp_hdr)); + udp_hdr->src_port = rte_cpu_to_be_16(tx_udp_src_port); + udp_hdr->dst_port = rte_cpu_to_be_16(tx_udp_dst_port); + udp_hdr->dgram_len = RTE_CPU_TO_BE_16(pkt_len); + udp_hdr->dgram_cksum = 0; /* No UDP checksum. */ + + /* + * Initialize IP header. + */ + pkt_len = (uint16_t) (pkt_len + sizeof(struct rte_ipv4_hdr)); + ip_hdr->version_ihl = RTE_IPV4_VHL_DEF; + ip_hdr->type_of_service = 0; + ip_hdr->fragment_offset = 0; + ip_hdr->time_to_live = 64; + ip_hdr->next_proto_id = IPPROTO_UDP; + ip_hdr->packet_id = 0; + ip_hdr->total_length = RTE_CPU_TO_BE_16(pkt_len); + ip_hdr->src_addr = rte_cpu_to_be_32(tx_ip_src_addr); + ip_hdr->dst_addr = rte_cpu_to_be_32(tx_ip_dst_addr); + + /* + * Compute IP header checksum. + */ + ptr16 = (unaligned_uint16_t *) ip_hdr; + ip_cksum = 0; + ip_cksum += ptr16[0]; ip_cksum += ptr16[1]; + ip_cksum += ptr16[2]; ip_cksum += ptr16[3]; + ip_cksum += ptr16[4]; + ip_cksum += ptr16[6]; ip_cksum += ptr16[7]; + ip_cksum += ptr16[8]; ip_cksum += ptr16[9]; + + /* + * Reduce 32 bit checksum to 16 bits and complement it. + */ + ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) + + (ip_cksum & 0x0000FFFF); + if (ip_cksum > 65535) + ip_cksum -= 65535; + ip_cksum = (~ip_cksum) & 0x0000FFFF; + if (ip_cksum == 0) + ip_cksum = 0xFFFF; + ip_hdr->hdr_checksum = (uint16_t) ip_cksum; +} + +static void +setup_pkt_encap_vlan_vxlan_apply( + struct encap_vxlan_ipv4_vlan_data *vxlan_hdr, + uint16_t pkt_data_len) +{ + uint16_t pkt_len; + + vxlan_hdr->ether.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN); + + /*vxlan head*/ + vxlan_hdr->vxlan.vx_vni = htonl(1000<<8); /*vni */ + vxlan_hdr->vxlan.vx_flags = 0x08; /*vni valid*/ + + /*udp*/ + pkt_len = sizeof(struct rte_udp_hdr) + sizeof(struct rte_vxlan_hdr) + pkt_data_len; + vxlan_hdr->udp.dst_port = htons(underlay_tx_udp_dst_port); + vxlan_hdr->udp.src_port = htons(underlay_tx_udp_src_port); + vxlan_hdr->udp.dgram_len = htons(pkt_len); + + pkt_len += sizeof(struct rte_ipv4_hdr); + /* IPv4*/ + vxlan_hdr->ipv4.version_ihl = 0x45; + vxlan_hdr->ipv4.type_of_service = 0; + vxlan_hdr->ipv4.total_length = rte_cpu_to_be_16(pkt_len); /* not pre-computed */ + vxlan_hdr->ipv4.packet_id = 0; + vxlan_hdr->ipv4.fragment_offset = 0; + vxlan_hdr->ipv4.time_to_live = 64; + vxlan_hdr->ipv4.next_proto_id = IPPROTO_UDP; + vxlan_hdr->ipv4.hdr_checksum = rte_ipv4_cksum(&vxlan_hdr->ipv4); + vxlan_hdr->ipv4.src_addr = rte_cpu_to_be_32(underlay_tx_ip_src_addr); + vxlan_hdr->ipv4.dst_addr = rte_cpu_to_be_32(underlay_tx_ip_dst_addr); + + + /* VLAN */ + vxlan_hdr->vlan.vlan_tci = rte_cpu_to_be_16(0); /*vlan*/ + vxlan_hdr->vlan.eth_proto = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4); + ; +} + +static int +underlay_tx_only_begin(portid_t pi) +{ + uint16_t pkt_hdr_len, pkt_data_len, payload_head_len; + int dynf; + + pkt_hdr_len = sizeof(struct encap_vxlan_ipv4_vlan_data); + payload_head_len = (uint16_t)(sizeof(struct rte_ether_hdr) + + sizeof(struct rte_ipv4_hdr) + + sizeof(struct rte_udp_hdr)); + pkt_data_len = tun_tx_pkt_length - pkt_hdr_len; + + if ((tx_pkt_split == TX_PKT_SPLIT_RND || txonly_multi_flow) && + tx_pkt_seg_lengths[1] < pkt_hdr_len) { + TESTPMD_LOG(ERR, + "Random segment number or multiple flow is enabled, " + "but tx_pkt_seg_lengths[0] %u < %u (needed)\n", + tx_pkt_seg_lengths[1], pkt_hdr_len); + return -EINVAL; + } + + setup_pkt_encap_vlan_vxlan_apply(&pkt_vxlan_hdr, pkt_data_len); + pkt_data_len = tun_tx_pkt_length - pkt_hdr_len - payload_head_len; + set_innter_eth_hdr_apply(&pkt_ip_hdr, &pkt_udp_hdr, pkt_data_len); + + timestamp_enable = false; + timestamp_mask = 0; + timestamp_off = -1; + dynf = rte_mbuf_dynflag_lookup + (RTE_MBUF_DYNFLAG_TX_TIMESTAMP_NAME, NULL); + if (dynf >= 0) + timestamp_mask = 1ULL << dynf; + dynf = rte_mbuf_dynfield_lookup + (RTE_MBUF_DYNFIELD_TIMESTAMP_NAME, NULL); + if (dynf >= 0) + timestamp_off = dynf; + timestamp_enable = tx_pkt_times_inter && + timestamp_mask && + timestamp_off >= 0 && + !rte_eth_read_clock(pi, ×tamp_initial[pi]); + + if (timestamp_enable) { + pkt_hdr_len += sizeof(struct tx_timestamp); + + if (tx_pkt_split == TX_PKT_SPLIT_RND) { + if (tx_pkt_seg_lengths[1] < pkt_hdr_len) { + TESTPMD_LOG(ERR, + "Time stamp and random segment number are enabled, " + "but tx_pkt_seg_lengths[0] %u < %u (needed)\n", + tx_pkt_seg_lengths[0], pkt_hdr_len); + return -EINVAL; + } + } else { + uint16_t total = 0; + uint8_t i; + + for (i = 1; i < 2; i++) { + total += tx_pkt_seg_lengths[i]; + if (total >= pkt_hdr_len) + break; + } + + if (total < pkt_hdr_len) { + TESTPMD_LOG(ERR, + "Not enough Tx segment space for time stamp info, " + "total %u < %u (needed)\n", + total, pkt_hdr_len); + return -EINVAL; + } + } + } + + /* Make sure all settings are visible on forwarding cores.*/ + rte_wmb(); + return 0; +} + + +static inline bool +pkt_burst_vxlan_prepare(struct rte_mbuf *pkt, struct rte_mempool *mbp, + struct rte_ether_hdr *eth_hdr, const uint16_t vlan_tci, + const uint16_t vlan_tci_outer, const uint64_t ol_flags, + const uint16_t idx, struct encap_vxlan_ipv4_vlan_data *vxlan, + struct fwd_stream *fs) +{ + struct rte_mbuf *pkt_segs[RTE_MAX_SEGS_PER_PKT]; + struct rte_mbuf *pkt_seg; + uint32_t nb_segs, pkt_len, off = 0; + uint8_t i; + + if (unlikely(tx_pkt_split == TX_PKT_SPLIT_RND)) + nb_segs = rte_rand() % tx_pkt_nb_segs + 1; + else + nb_segs = tx_pkt_nb_segs; + + if (nb_segs > 1) { + if (rte_mempool_get_bulk(mbp, (void **)pkt_segs, nb_segs - 1)) + return false; + } + + rte_pktmbuf_reset_headroom(pkt); + pkt->data_len = tx_pkt_seg_lengths[1]; + pkt->ol_flags &= RTE_MBUF_F_EXTERNAL; + pkt->ol_flags |= ol_flags; + pkt->vlan_tci = vlan_tci; + pkt->vlan_tci_outer = vlan_tci_outer; + pkt->l2_len = sizeof(struct rte_ether_hdr); + pkt->l3_len = sizeof(struct rte_ipv4_hdr); + + pkt_len = pkt->data_len; + pkt_seg = pkt; + for (i = 1; i < nb_segs; i++) { + pkt_seg->next = pkt_segs[i - 1]; + pkt_seg = pkt_seg->next; + pkt_seg->data_len = tx_pkt_seg_lengths[i]; + pkt_len += pkt_seg->data_len; + } + pkt_seg->next = NULL; /* Last segment of packet. */ + + copy_buf_to_pkt(vxlan, sizeof(*vxlan), pkt, 0); + off = sizeof(struct encap_vxlan_ipv4_vlan_data); + /* + * Copy headers in first packet segment(s). + */ + copy_buf_to_pkt(eth_hdr, sizeof(*eth_hdr), pkt, off); + off += sizeof(struct rte_ether_hdr); + copy_buf_to_pkt(&pkt_ip_hdr, sizeof(pkt_ip_hdr), pkt, + off); + + if (txonly_multi_flow) { + uint8_t ip_var = RTE_PER_LCORE(__ip_var); + struct rte_ipv4_hdr *ip_hdr; + uint32_t addr; + + ip_hdr = rte_pktmbuf_mtod_offset(pkt, + struct rte_ipv4_hdr *, + off); + + /* + * Generate multiple flows by varying IP src addr. This + * enables packets are well distributed by RSS in + * receiver side if any and txonly mode can be a decent + * packet generator for developer's quick performance + * regression test. + */ + addr = (tx_ip_dst_addr | (ip_var++ << 8)) + rte_lcore_id(); + ip_hdr->src_addr = rte_cpu_to_be_32(addr); + RTE_PER_LCORE(__ip_var) = ip_var; + } + off += sizeof(pkt_ip_hdr); + copy_buf_to_pkt(&pkt_udp_hdr, sizeof(pkt_udp_hdr), pkt, off); + off += sizeof(pkt_udp_hdr); + + if (unlikely(timestamp_enable)) { + uint64_t skew = fs->ts_skew; + struct tx_timestamp timestamp_mark; + + if (unlikely(!skew)) { + struct rte_eth_dev_info dev_info; + unsigned int txqs_n; + uint64_t phase; + int ret; + + ret = eth_dev_info_get_print_err(fs->tx_port, &dev_info); + if (ret != 0) { + TESTPMD_LOG(ERR, + "Failed to get device info for port %d," + "could not finish timestamp init", + fs->tx_port); + return false; + } + txqs_n = dev_info.nb_tx_queues; + phase = tx_pkt_times_inter * fs->tx_queue / + (txqs_n ? txqs_n : 1); + /* + * Initialize the scheduling time phase shift + * depending on queue index. + */ + skew = timestamp_initial[fs->tx_port] + + tx_pkt_times_inter + phase; + fs->ts_skew = skew; + } + timestamp_mark.pkt_idx = rte_cpu_to_be_16(idx); + timestamp_mark.queue_idx = rte_cpu_to_be_16(fs->tx_queue); + timestamp_mark.signature = rte_cpu_to_be_32(0xBEEFC0DE); + if (unlikely(!idx)) { + skew += tx_pkt_times_inter; + pkt->ol_flags |= timestamp_mask; + *RTE_MBUF_DYNFIELD + (pkt, timestamp_off, uint64_t *) = skew; + fs->ts_skew = skew; + timestamp_mark.ts = rte_cpu_to_be_64(skew); + } else if (tx_pkt_times_intra) { + skew += tx_pkt_times_intra; + pkt->ol_flags |= timestamp_mask; + *RTE_MBUF_DYNFIELD + (pkt, timestamp_off, uint64_t *) = skew; + fs->ts_skew = skew; + timestamp_mark.ts = rte_cpu_to_be_64(skew); + } else { + timestamp_mark.ts = RTE_BE64(0); + } + copy_buf_to_pkt(×tamp_mark, sizeof(timestamp_mark), pkt, + sizeof(struct encap_vxlan_ipv4_vlan_data) + + sizeof(struct rte_ether_hdr) + + sizeof(struct rte_ipv4_hdr) + + sizeof(pkt_udp_hdr)); + } + /* + * Complete first mbuf of packet and append it to the + * burst of packets to be transmitted. + */ + pkt->nb_segs = nb_segs; + pkt->pkt_len = pkt_len; + + return true; +} + +/* + * Transmit a burst of multi-segments packets. + */ +static void +pkt_burst_transmit(struct fwd_stream *fs) +{ + struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; + struct rte_port *txp; + struct rte_mbuf *pkt; + struct rte_mempool *mbp; + struct rte_ether_hdr eth_hdr; + uint16_t nb_tx; + uint16_t nb_pkt; + uint16_t vlan_tci, vlan_tci_outer; + uint32_t retry; + uint64_t ol_flags = 0; + uint64_t tx_offloads; + uint64_t start_tsc = 0; + + get_start_cycles(&start_tsc); + + mbp = current_fwd_lcore()->mbp; + txp = &ports[fs->tx_port]; + tx_offloads = txp->dev_conf.txmode.offloads; + vlan_tci = txp->tx_vlan_id; + vlan_tci_outer = txp->tx_vlan_id_outer; + 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; + + rte_ether_addr_copy(&peer_underlay_eth_addrs[fs->peer_addr], &pkt_vxlan_hdr.ether.dst_addr); + rte_ether_addr_copy(&ports[fs->tx_port].eth_addr, &pkt_vxlan_hdr.ether.src_addr); + + /* + * Initialize Ethernet header. + */ + rte_ether_addr_copy(&peer_eth_addrs[fs->peer_addr], ð_hdr.dst_addr); + rte_ether_addr_copy(&ports[fs->tx_port].eth_addr, ð_hdr.src_addr); + eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4); + + if (rte_mempool_get_bulk(mbp, (void **)pkts_burst, + nb_pkt_per_burst) == 0) { + for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) { + if (unlikely(!pkt_burst_vxlan_prepare( + pkts_burst[nb_pkt], mbp, ð_hdr, + vlan_tci, vlan_tci_outer, ol_flags, + nb_pkt, &pkt_vxlan_hdr, fs))) { + rte_mempool_put_bulk(mbp, + (void **)&pkts_burst[nb_pkt], + nb_pkt_per_burst - nb_pkt); + break; + } + } + } else { + for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) { + pkt = rte_mbuf_raw_alloc(mbp); + if (pkt == NULL) + break; + if (unlikely(!pkt_burst_vxlan_prepare(pkt, mbp, ð_hdr, + vlan_tci, + vlan_tci_outer, + ol_flags, + nb_pkt, &pkt_vxlan_hdr, + fs))) { + rte_pktmbuf_free(pkt); + break; + } + pkts_burst[nb_pkt] = pkt; + } + } + + if (nb_pkt == 0) + return; + + nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_pkt); + + /* + * Retry if necessary + */ + if (unlikely(nb_tx < nb_pkt) && fs->retry_enabled) { + retry = 0; + while (nb_tx < nb_pkt && 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_pkt - nb_tx); + } + } + fs->tx_packets += nb_tx; + + if (txonly_multi_flow) + RTE_PER_LCORE(__ip_var) -= nb_pkt - nb_tx; + + inc_tx_burst_stats(fs, nb_tx); + if (unlikely(nb_tx < nb_pkt)) { + if (verbose_level > 0 && fs->fwd_dropped == 0) + printf("port %d tx_queue %d - drop " + "(nb_pkt:%u - nb_tx:%u)=%u packets\n", + fs->tx_port, fs->tx_queue, + (unsigned int) nb_pkt, + (unsigned int) nb_tx, + (unsigned int) (nb_pkt - nb_tx)); + fs->fwd_dropped += (nb_pkt - nb_tx); + do { + rte_pktmbuf_free(pkts_burst[nb_tx]); + } while (++nb_tx < nb_pkt); + } + + get_end_cycles(fs, start_tsc); +} +static void +tx_only_stream_init(struct fwd_stream *fs) +{ + fs->disabled = ports[fs->tx_port].txq[fs->tx_queue].state == + RTE_ETH_QUEUE_STATE_STOPPED; +} + + +struct fwd_engine tun_tx_only_engine = { + .fwd_mode_name = "tuntxonly", + .port_fwd_begin = underlay_tx_only_begin, + .port_fwd_end = NULL, + .stream_init = tx_only_stream_init, + .packet_fwd = pkt_burst_transmit, +}; + + + + diff --git a/app/test-pmd/vxlan.h b/app/test-pmd/vxlan.h new file mode 100644 index 0000000000..f4cc031d92 --- /dev/null +++ b/app/test-pmd/vxlan.h @@ -0,0 +1,23 @@ +#ifndef __VXLAN_H +#define __VXLAN_H +#include + + + +struct encap_vxlan_ipv4_vlan_data { + struct rte_ether_hdr ether; + struct rte_vlan_hdr vlan; + struct rte_ipv4_hdr ipv4; + struct rte_udp_hdr udp; + struct rte_vxlan_hdr vxlan; +} __rte_packed __rte_aligned(2); + +struct encap_vxlan_ipv4_data { + struct rte_ether_hdr ether; + struct rte_ipv4_hdr ipv4; + struct rte_udp_hdr udp; + struct rte_vxlan_hdr vxlan; +} __rte_packed __rte_aligned(2); + + +#endif -- 2.30.2