]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*- |
2 | * BSD LICENSE | |
3 | * | |
4 | * Copyright(c) 2010-2013 Tilera Corporation. All rights reserved. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * | |
11 | * * Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * * Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in | |
15 | * the documentation and/or other materials provided with the | |
16 | * distribution. | |
17 | * * Neither the name of Tilera Corporation nor the names of its | |
18 | * contributors may be used to endorse or promote products derived | |
19 | * from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
25 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
27 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | * | |
33 | */ | |
34 | ||
35 | #include <stdarg.h> | |
36 | #include <string.h> | |
37 | #include <stdio.h> | |
38 | #include <errno.h> | |
39 | #include <stdint.h> | |
40 | #include <unistd.h> | |
41 | #include <inttypes.h> | |
42 | ||
43 | #include <sys/queue.h> | |
44 | #include <sys/stat.h> | |
45 | ||
46 | #include <rte_common.h> | |
47 | #include <rte_byteorder.h> | |
48 | #include <rte_log.h> | |
49 | #include <rte_debug.h> | |
50 | #include <rte_cycles.h> | |
51 | #include <rte_memory.h> | |
52 | #include <rte_memcpy.h> | |
53 | #include <rte_memzone.h> | |
54 | #include <rte_launch.h> | |
55 | #include <rte_eal.h> | |
56 | #include <rte_per_lcore.h> | |
57 | #include <rte_lcore.h> | |
58 | #include <rte_atomic.h> | |
59 | #include <rte_branch_prediction.h> | |
60 | #include <rte_memory.h> | |
61 | #include <rte_mempool.h> | |
62 | #include <rte_mbuf.h> | |
63 | #include <rte_interrupts.h> | |
64 | #include <rte_pci.h> | |
65 | #include <rte_ether.h> | |
66 | #include <rte_ethdev.h> | |
67 | #include <rte_ip.h> | |
68 | #include <rte_tcp.h> | |
69 | #include <rte_udp.h> | |
70 | #include <rte_string_fns.h> | |
71 | ||
72 | #include "testpmd.h" | |
73 | ||
74 | /* hardcoded configuration (for now) */ | |
75 | static unsigned cfg_n_flows = 1024; | |
76 | static uint32_t cfg_ip_src = IPv4(10, 254, 0, 0); | |
77 | static uint32_t cfg_ip_dst = IPv4(10, 253, 0, 0); | |
78 | static uint16_t cfg_udp_src = 1000; | |
79 | static uint16_t cfg_udp_dst = 1001; | |
80 | static struct ether_addr cfg_ether_src = | |
81 | {{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x00 }}; | |
82 | static struct ether_addr cfg_ether_dst = | |
83 | {{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x01 }}; | |
84 | ||
85 | #define IP_DEFTTL 64 /* from RFC 1340. */ | |
86 | #define IP_VERSION 0x40 | |
87 | #define IP_HDRLEN 0x05 /* default IP header length == five 32-bits words. */ | |
88 | #define IP_VHL_DEF (IP_VERSION | IP_HDRLEN) | |
89 | ||
90 | static inline uint16_t | |
91 | ip_sum(const unaligned_uint16_t *hdr, int hdr_len) | |
92 | { | |
93 | uint32_t sum = 0; | |
94 | ||
95 | while (hdr_len > 1) | |
96 | { | |
97 | sum += *hdr++; | |
98 | if (sum & 0x80000000) | |
99 | sum = (sum & 0xFFFF) + (sum >> 16); | |
100 | hdr_len -= 2; | |
101 | } | |
102 | ||
103 | while (sum >> 16) | |
104 | sum = (sum & 0xFFFF) + (sum >> 16); | |
105 | ||
106 | return ~sum; | |
107 | } | |
108 | ||
109 | /* | |
110 | * Multi-flow generation mode. | |
111 | * | |
112 | * We originate a bunch of flows (varying destination IP addresses), and | |
113 | * terminate receive traffic. Received traffic is simply discarded, but we | |
114 | * still do so in order to maintain traffic statistics. | |
115 | */ | |
116 | static void | |
117 | pkt_burst_flow_gen(struct fwd_stream *fs) | |
118 | { | |
119 | unsigned pkt_size = tx_pkt_length - 4; /* Adjust FCS */ | |
120 | struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; | |
121 | struct rte_mempool *mbp; | |
122 | struct rte_mbuf *pkt; | |
123 | struct ether_hdr *eth_hdr; | |
124 | struct ipv4_hdr *ip_hdr; | |
125 | struct udp_hdr *udp_hdr; | |
126 | uint16_t vlan_tci, vlan_tci_outer; | |
127 | uint16_t ol_flags; | |
128 | uint16_t nb_rx; | |
129 | uint16_t nb_tx; | |
130 | uint16_t nb_pkt; | |
131 | uint16_t i; | |
132 | uint32_t retry; | |
133 | #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES | |
134 | uint64_t start_tsc; | |
135 | uint64_t end_tsc; | |
136 | uint64_t core_cycles; | |
137 | #endif | |
138 | static int next_flow = 0; | |
139 | ||
140 | #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES | |
141 | start_tsc = rte_rdtsc(); | |
142 | #endif | |
143 | ||
144 | /* Receive a burst of packets and discard them. */ | |
145 | nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst, | |
146 | nb_pkt_per_burst); | |
147 | fs->rx_packets += nb_rx; | |
148 | ||
149 | for (i = 0; i < nb_rx; i++) | |
150 | rte_pktmbuf_free(pkts_burst[i]); | |
151 | ||
152 | mbp = current_fwd_lcore()->mbp; | |
153 | vlan_tci = ports[fs->tx_port].tx_vlan_id; | |
154 | vlan_tci_outer = ports[fs->tx_port].tx_vlan_id_outer; | |
155 | ol_flags = ports[fs->tx_port].tx_ol_flags; | |
156 | ||
157 | for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) { | |
158 | pkt = rte_mbuf_raw_alloc(mbp); | |
159 | if (!pkt) | |
160 | break; | |
161 | ||
162 | pkt->data_len = pkt_size; | |
163 | pkt->next = NULL; | |
164 | ||
165 | /* Initialize Ethernet header. */ | |
166 | eth_hdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *); | |
167 | ether_addr_copy(&cfg_ether_dst, ð_hdr->d_addr); | |
168 | ether_addr_copy(&cfg_ether_src, ð_hdr->s_addr); | |
169 | eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); | |
170 | ||
171 | /* Initialize IP header. */ | |
172 | ip_hdr = (struct ipv4_hdr *)(eth_hdr + 1); | |
173 | memset(ip_hdr, 0, sizeof(*ip_hdr)); | |
174 | ip_hdr->version_ihl = IP_VHL_DEF; | |
175 | ip_hdr->type_of_service = 0; | |
176 | ip_hdr->fragment_offset = 0; | |
177 | ip_hdr->time_to_live = IP_DEFTTL; | |
178 | ip_hdr->next_proto_id = IPPROTO_UDP; | |
179 | ip_hdr->packet_id = 0; | |
180 | ip_hdr->src_addr = rte_cpu_to_be_32(cfg_ip_src); | |
181 | ip_hdr->dst_addr = rte_cpu_to_be_32(cfg_ip_dst + | |
182 | next_flow); | |
183 | ip_hdr->total_length = RTE_CPU_TO_BE_16(pkt_size - | |
184 | sizeof(*eth_hdr)); | |
185 | ip_hdr->hdr_checksum = ip_sum((unaligned_uint16_t *)ip_hdr, | |
186 | sizeof(*ip_hdr)); | |
187 | ||
188 | /* Initialize UDP header. */ | |
189 | udp_hdr = (struct udp_hdr *)(ip_hdr + 1); | |
190 | udp_hdr->src_port = rte_cpu_to_be_16(cfg_udp_src); | |
191 | udp_hdr->dst_port = rte_cpu_to_be_16(cfg_udp_dst); | |
192 | udp_hdr->dgram_cksum = 0; /* No UDP checksum. */ | |
193 | udp_hdr->dgram_len = RTE_CPU_TO_BE_16(pkt_size - | |
194 | sizeof(*eth_hdr) - | |
195 | sizeof(*ip_hdr)); | |
196 | pkt->nb_segs = 1; | |
197 | pkt->pkt_len = pkt_size; | |
198 | pkt->ol_flags = ol_flags; | |
199 | pkt->vlan_tci = vlan_tci; | |
200 | pkt->vlan_tci_outer = vlan_tci_outer; | |
201 | pkt->l2_len = sizeof(struct ether_hdr); | |
202 | pkt->l3_len = sizeof(struct ipv4_hdr); | |
203 | pkts_burst[nb_pkt] = pkt; | |
204 | ||
205 | next_flow = (next_flow + 1) % cfg_n_flows; | |
206 | } | |
207 | ||
208 | nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_pkt); | |
209 | /* | |
210 | * Retry if necessary | |
211 | */ | |
212 | if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) { | |
213 | retry = 0; | |
214 | while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) { | |
215 | rte_delay_us(burst_tx_delay_time); | |
216 | nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue, | |
217 | &pkts_burst[nb_tx], nb_rx - nb_tx); | |
218 | } | |
219 | } | |
220 | fs->tx_packets += nb_tx; | |
221 | ||
222 | #ifdef RTE_TEST_PMD_RECORD_BURST_STATS | |
223 | fs->tx_burst_stats.pkt_burst_spread[nb_tx]++; | |
224 | #endif | |
225 | if (unlikely(nb_tx < nb_pkt)) { | |
226 | /* Back out the flow counter. */ | |
227 | next_flow -= (nb_pkt - nb_tx); | |
228 | while (next_flow < 0) | |
229 | next_flow += cfg_n_flows; | |
230 | ||
231 | do { | |
232 | rte_pktmbuf_free(pkts_burst[nb_tx]); | |
233 | } while (++nb_tx < nb_pkt); | |
234 | } | |
235 | #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES | |
236 | end_tsc = rte_rdtsc(); | |
237 | core_cycles = (end_tsc - start_tsc); | |
238 | fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles); | |
239 | #endif | |
240 | } | |
241 | ||
242 | struct fwd_engine flow_gen_engine = { | |
243 | .fwd_mode_name = "flowgen", | |
244 | .port_fwd_begin = NULL, | |
245 | .port_fwd_end = NULL, | |
246 | .packet_fwd = pkt_burst_flow_gen, | |
247 | }; |