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_launch.h>
55 #include <rte_per_lcore.h>
56 #include <rte_lcore.h>
57 #include <rte_atomic.h>
58 #include <rte_branch_prediction.h>
59 #include <rte_mempool.h>
61 #include <rte_interrupts.h>
63 #include <rte_ether.h>
64 #include <rte_ethdev.h>
68 #include <rte_string_fns.h>
73 /* hardcoded configuration (for now) */
74 static unsigned cfg_n_flows
= 1024;
75 static uint32_t cfg_ip_src
= IPv4(10, 254, 0, 0);
76 static uint32_t cfg_ip_dst
= IPv4(10, 253, 0, 0);
77 static uint16_t cfg_udp_src
= 1000;
78 static uint16_t cfg_udp_dst
= 1001;
79 static struct ether_addr cfg_ether_src
=
80 {{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x00 }};
81 static struct ether_addr cfg_ether_dst
=
82 {{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x01 }};
84 #define IP_DEFTTL 64 /* from RFC 1340. */
85 #define IP_VERSION 0x40
86 #define IP_HDRLEN 0x05 /* default IP header length == five 32-bits words. */
87 #define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
89 static inline uint16_t
90 ip_sum(const unaligned_uint16_t
*hdr
, int hdr_len
)
98 sum
= (sum
& 0xFFFF) + (sum
>> 16);
103 sum
= (sum
& 0xFFFF) + (sum
>> 16);
109 * Multi-flow generation mode.
111 * We originate a bunch of flows (varying destination IP addresses), and
112 * terminate receive traffic. Received traffic is simply discarded, but we
113 * still do so in order to maintain traffic statistics.
116 pkt_burst_flow_gen(struct fwd_stream
*fs
)
118 unsigned pkt_size
= tx_pkt_length
- 4; /* Adjust FCS */
119 struct rte_mbuf
*pkts_burst
[MAX_PKT_BURST
];
120 struct rte_mempool
*mbp
;
121 struct rte_mbuf
*pkt
;
122 struct ether_hdr
*eth_hdr
;
123 struct ipv4_hdr
*ip_hdr
;
124 struct udp_hdr
*udp_hdr
;
125 uint16_t vlan_tci
, vlan_tci_outer
;
126 uint64_t ol_flags
= 0;
132 uint64_t tx_offloads
;
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
;
156 tx_offloads
= ports
[fs
->tx_port
].dev_conf
.txmode
.offloads
;
157 if (tx_offloads
& DEV_TX_OFFLOAD_VLAN_INSERT
)
158 ol_flags
|= PKT_TX_VLAN_PKT
;
159 if (tx_offloads
& DEV_TX_OFFLOAD_QINQ_INSERT
)
160 ol_flags
|= PKT_TX_QINQ_PKT
;
161 if (tx_offloads
& DEV_TX_OFFLOAD_MACSEC_INSERT
)
162 ol_flags
|= PKT_TX_MACSEC
;
164 for (nb_pkt
= 0; nb_pkt
< nb_pkt_per_burst
; nb_pkt
++) {
165 pkt
= rte_mbuf_raw_alloc(mbp
);
169 pkt
->data_len
= pkt_size
;
172 /* Initialize Ethernet header. */
173 eth_hdr
= rte_pktmbuf_mtod(pkt
, struct ether_hdr
*);
174 ether_addr_copy(&cfg_ether_dst
, ð_hdr
->d_addr
);
175 ether_addr_copy(&cfg_ether_src
, ð_hdr
->s_addr
);
176 eth_hdr
->ether_type
= rte_cpu_to_be_16(ETHER_TYPE_IPv4
);
178 /* Initialize IP header. */
179 ip_hdr
= (struct ipv4_hdr
*)(eth_hdr
+ 1);
180 memset(ip_hdr
, 0, sizeof(*ip_hdr
));
181 ip_hdr
->version_ihl
= IP_VHL_DEF
;
182 ip_hdr
->type_of_service
= 0;
183 ip_hdr
->fragment_offset
= 0;
184 ip_hdr
->time_to_live
= IP_DEFTTL
;
185 ip_hdr
->next_proto_id
= IPPROTO_UDP
;
186 ip_hdr
->packet_id
= 0;
187 ip_hdr
->src_addr
= rte_cpu_to_be_32(cfg_ip_src
);
188 ip_hdr
->dst_addr
= rte_cpu_to_be_32(cfg_ip_dst
+
190 ip_hdr
->total_length
= RTE_CPU_TO_BE_16(pkt_size
-
192 ip_hdr
->hdr_checksum
= ip_sum((unaligned_uint16_t
*)ip_hdr
,
195 /* Initialize UDP header. */
196 udp_hdr
= (struct udp_hdr
*)(ip_hdr
+ 1);
197 udp_hdr
->src_port
= rte_cpu_to_be_16(cfg_udp_src
);
198 udp_hdr
->dst_port
= rte_cpu_to_be_16(cfg_udp_dst
);
199 udp_hdr
->dgram_cksum
= 0; /* No UDP checksum. */
200 udp_hdr
->dgram_len
= RTE_CPU_TO_BE_16(pkt_size
-
204 pkt
->pkt_len
= pkt_size
;
205 pkt
->ol_flags
= ol_flags
;
206 pkt
->vlan_tci
= vlan_tci
;
207 pkt
->vlan_tci_outer
= vlan_tci_outer
;
208 pkt
->l2_len
= sizeof(struct ether_hdr
);
209 pkt
->l3_len
= sizeof(struct ipv4_hdr
);
210 pkts_burst
[nb_pkt
] = pkt
;
212 next_flow
= (next_flow
+ 1) % cfg_n_flows
;
215 nb_tx
= rte_eth_tx_burst(fs
->tx_port
, fs
->tx_queue
, pkts_burst
, nb_pkt
);
219 if (unlikely(nb_tx
< nb_rx
) && fs
->retry_enabled
) {
221 while (nb_tx
< nb_rx
&& retry
++ < burst_tx_retry_num
) {
222 rte_delay_us(burst_tx_delay_time
);
223 nb_tx
+= rte_eth_tx_burst(fs
->tx_port
, fs
->tx_queue
,
224 &pkts_burst
[nb_tx
], nb_rx
- nb_tx
);
227 fs
->tx_packets
+= nb_tx
;
229 #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
230 fs
->tx_burst_stats
.pkt_burst_spread
[nb_tx
]++;
232 if (unlikely(nb_tx
< nb_pkt
)) {
233 /* Back out the flow counter. */
234 next_flow
-= (nb_pkt
- nb_tx
);
235 while (next_flow
< 0)
236 next_flow
+= cfg_n_flows
;
239 rte_pktmbuf_free(pkts_burst
[nb_tx
]);
240 } while (++nb_tx
< nb_pkt
);
242 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
243 end_tsc
= rte_rdtsc();
244 core_cycles
= (end_tsc
- start_tsc
);
245 fs
->core_cycles
= (uint64_t) (fs
->core_cycles
+ core_cycles
);
249 struct fwd_engine flow_gen_engine
= {
250 .fwd_mode_name
= "flowgen",
251 .port_fwd_begin
= NULL
,
252 .port_fwd_end
= NULL
,
253 .packet_fwd
= pkt_burst_flow_gen
,