1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2014-2020 Mellanox Technologies, Ltd
3 */
4
5 #include <stdarg.h>
6 #include <string.h>
7 #include <stdio.h>
8 #include <errno.h>
9 #include <stdint.h>
10 #include <unistd.h>
11 #include <inttypes.h>
12
13 #include <sys/queue.h>
14 #include <sys/stat.h>
15
16 #include <rte_common.h>
17 #include <rte_byteorder.h>
18 #include <rte_log.h>
19 #include <rte_debug.h>
20 #include <rte_cycles.h>
21 #include <rte_memory.h>
22 #include <rte_memcpy.h>
23 #include <rte_launch.h>
24 #include <rte_eal.h>
25 #include <rte_per_lcore.h>
26 #include <rte_lcore.h>
27 #include <rte_branch_prediction.h>
28 #include <rte_mempool.h>
29 #include <rte_mbuf.h>
30 #include <rte_interrupts.h>
31 #include <rte_ether.h>
32 #include <rte_ethdev.h>
33 #include <rte_ip.h>
34 #include <rte_tcp.h>
35 #include <rte_udp.h>
36 #include <rte_string_fns.h>
37 #include <rte_flow.h>
38
39 #include "testpmd.h"
40
41 static uint32_t cfg_ip_src = RTE_IPV4(10, 254, 0, 0);
42 static uint32_t cfg_ip_dst = RTE_IPV4(10, 253, 0, 0);
43 static uint16_t cfg_udp_src = 1000;
44 static uint16_t cfg_udp_dst = 1001;
45 static struct rte_ether_addr cfg_ether_src =
46 {{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x00 }};
47 static struct rte_ether_addr cfg_ether_dst =
48 {{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x01 }};
49
50 #define IP_DEFTTL 64 /* from RFC 1340. */
51
52 RTE_DEFINE_PER_LCORE(int, _next_flow);
53
54 /*
55 * Multi-flow generation mode.
56 *
57 * We originate a bunch of flows (varying destination IP addresses), and
58 * terminate receive traffic. Received traffic is simply discarded, but we
59 * still do so in order to maintain traffic statistics.
60 */
61 static bool
pkt_burst_flow_gen(struct fwd_stream * fs)62 pkt_burst_flow_gen(struct fwd_stream *fs)
63 {
64 unsigned pkt_size = tx_pkt_length - 4; /* Adjust FCS */
65 struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
66 struct rte_mempool *mbp;
67 struct rte_mbuf *pkt = NULL;
68 struct rte_ether_hdr *eth_hdr;
69 struct rte_ipv4_hdr *ip_hdr;
70 struct rte_udp_hdr *udp_hdr;
71 uint16_t vlan_tci, vlan_tci_outer;
72 uint64_t ol_flags = 0;
73 uint16_t nb_rx;
74 uint16_t nb_tx;
75 uint16_t nb_dropped;
76 uint16_t nb_pkt;
77 uint16_t nb_clones = nb_pkt_flowgen_clones;
78 uint64_t tx_offloads;
79 int next_flow = RTE_PER_LCORE(_next_flow);
80
81 /* Receive a burst of packets and discard them. */
82 nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
83
84 rte_pktmbuf_free_bulk(pkts_burst, nb_rx);
85
86 mbp = current_fwd_lcore()->mbp;
87 vlan_tci = ports[fs->tx_port].tx_vlan_id;
88 vlan_tci_outer = ports[fs->tx_port].tx_vlan_id_outer;
89
90 tx_offloads = ports[fs->tx_port].dev_conf.txmode.offloads;
91 if (tx_offloads & RTE_ETH_TX_OFFLOAD_VLAN_INSERT)
92 ol_flags |= RTE_MBUF_F_TX_VLAN;
93 if (tx_offloads & RTE_ETH_TX_OFFLOAD_QINQ_INSERT)
94 ol_flags |= RTE_MBUF_F_TX_QINQ;
95 if (tx_offloads & RTE_ETH_TX_OFFLOAD_MACSEC_INSERT)
96 ol_flags |= RTE_MBUF_F_TX_MACSEC;
97
98 for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
99 if (!nb_pkt || !nb_clones) {
100 nb_clones = nb_pkt_flowgen_clones;
101 /* Logic limitation */
102 if (nb_clones > nb_pkt_per_burst)
103 nb_clones = nb_pkt_per_burst;
104
105 pkt = rte_mbuf_raw_alloc(mbp);
106 if (!pkt)
107 break;
108
109 pkt->data_len = pkt_size;
110 pkt->next = NULL;
111
112 /* Initialize Ethernet header. */
113 eth_hdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
114 rte_ether_addr_copy(&cfg_ether_dst, ð_hdr->dst_addr);
115 rte_ether_addr_copy(&cfg_ether_src, ð_hdr->src_addr);
116 eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
117
118 /* Initialize IP header. */
119 ip_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1);
120 memset(ip_hdr, 0, sizeof(*ip_hdr));
121 ip_hdr->version_ihl = RTE_IPV4_VHL_DEF;
122 ip_hdr->type_of_service = 0;
123 ip_hdr->fragment_offset = 0;
124 ip_hdr->time_to_live = IP_DEFTTL;
125 ip_hdr->next_proto_id = IPPROTO_UDP;
126 ip_hdr->packet_id = 0;
127 ip_hdr->src_addr = rte_cpu_to_be_32(cfg_ip_src);
128 ip_hdr->dst_addr = rte_cpu_to_be_32(cfg_ip_dst +
129 next_flow);
130 ip_hdr->total_length = RTE_CPU_TO_BE_16(pkt_size -
131 sizeof(*eth_hdr));
132 ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr);
133
134 /* Initialize UDP header. */
135 udp_hdr = (struct rte_udp_hdr *)(ip_hdr + 1);
136 udp_hdr->src_port = rte_cpu_to_be_16(cfg_udp_src);
137 udp_hdr->dst_port = rte_cpu_to_be_16(cfg_udp_dst);
138 udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
139 udp_hdr->dgram_len = RTE_CPU_TO_BE_16(pkt_size -
140 sizeof(*eth_hdr) -
141 sizeof(*ip_hdr));
142 pkt->nb_segs = 1;
143 pkt->pkt_len = pkt_size;
144 pkt->ol_flags &= RTE_MBUF_F_EXTERNAL;
145 pkt->ol_flags |= ol_flags;
146 pkt->vlan_tci = vlan_tci;
147 pkt->vlan_tci_outer = vlan_tci_outer;
148 pkt->l2_len = sizeof(struct rte_ether_hdr);
149 pkt->l3_len = sizeof(struct rte_ipv4_hdr);
150 } else {
151 nb_clones--;
152 rte_mbuf_refcnt_update(pkt, 1);
153 }
154 pkts_burst[nb_pkt] = pkt;
155
156 if (++next_flow >= nb_flows_flowgen)
157 next_flow = 0;
158 }
159
160 nb_tx = common_fwd_stream_transmit(fs, pkts_burst, nb_pkt);
161 nb_dropped = nb_pkt - nb_tx;
162 if (unlikely(nb_dropped > 0)) {
163 /* Back out the flow counter. */
164 next_flow -= nb_dropped;
165 while (next_flow < 0)
166 next_flow += nb_flows_flowgen;
167 }
168
169 RTE_PER_LCORE(_next_flow) = next_flow;
170
171 return true;
172 }
173
174 static int
flowgen_begin(portid_t pi)175 flowgen_begin(portid_t pi)
176 {
177 printf(" number of flows for port %u: %d\n", pi, nb_flows_flowgen);
178 return 0;
179 }
180
181 struct fwd_engine flow_gen_engine = {
182 .fwd_mode_name = "flowgen",
183 .port_fwd_begin = flowgen_begin,
184 .stream_init = common_fwd_stream_init,
185 .packet_fwd = pkt_burst_flow_gen,
186 };
187