4 * Copyright(c) 2010-2013 Tilera Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
43 #include <sys/queue.h>
46 #include <rte_common.h>
47 #include <rte_byteorder.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>
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>
63 #include <rte_interrupts.h>
65 #include <rte_ether.h>
66 #include <rte_ethdev.h>
70 #include <rte_string_fns.h>
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 }};
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)
90 static inline uint16_t
91 ip_sum(const unaligned_uint16_t
*hdr
, int hdr_len
)
99 sum
= (sum
& 0xFFFF) + (sum
>> 16);
104 sum
= (sum
& 0xFFFF) + (sum
>> 16);
110 * Multi-flow generation mode.
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.
117 pkt_burst_flow_gen(struct fwd_stream
*fs
)
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
;
133 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
136 uint64_t core_cycles
;
138 static int next_flow
= 0;
140 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
141 start_tsc
= rte_rdtsc();
144 /* Receive a burst of packets and discard them. */
145 nb_rx
= rte_eth_rx_burst(fs
->rx_port
, fs
->rx_queue
, pkts_burst
,
147 fs
->rx_packets
+= nb_rx
;
149 for (i
= 0; i
< nb_rx
; i
++)
150 rte_pktmbuf_free(pkts_burst
[i
]);
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
;
157 for (nb_pkt
= 0; nb_pkt
< nb_pkt_per_burst
; nb_pkt
++) {
158 pkt
= rte_mbuf_raw_alloc(mbp
);
162 pkt
->data_len
= pkt_size
;
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
);
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
+
183 ip_hdr
->total_length
= RTE_CPU_TO_BE_16(pkt_size
-
185 ip_hdr
->hdr_checksum
= ip_sum((unaligned_uint16_t
*)ip_hdr
,
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
-
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
;
205 next_flow
= (next_flow
+ 1) % cfg_n_flows
;
208 nb_tx
= rte_eth_tx_burst(fs
->tx_port
, fs
->tx_queue
, pkts_burst
, nb_pkt
);
212 if (unlikely(nb_tx
< nb_rx
) && fs
->retry_enabled
) {
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
);
220 fs
->tx_packets
+= nb_tx
;
222 #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
223 fs
->tx_burst_stats
.pkt_burst_spread
[nb_tx
]++;
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
;
232 rte_pktmbuf_free(pkts_burst
[nb_tx
]);
233 } while (++nb_tx
< nb_pkt
);
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
);
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
,