first public release
[dpdk.git] / app / test-pmd / csumonly.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 Intel 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 Intel 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  *  version: DPDK.L.1.2.3-3
34  */
35
36 #include <stdarg.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_tailq.h>
56 #include <rte_eal.h>
57 #include <rte_per_lcore.h>
58 #include <rte_lcore.h>
59 #include <rte_atomic.h>
60 #include <rte_branch_prediction.h>
61 #include <rte_ring.h>
62 #include <rte_memory.h>
63 #include <rte_mempool.h>
64 #include <rte_mbuf.h>
65 #include <rte_memcpy.h>
66 #include <rte_interrupts.h>
67 #include <rte_pci.h>
68 #include <rte_ether.h>
69 #include <rte_ethdev.h>
70 #include <rte_ip.h>
71 #include <rte_tcp.h>
72 #include <rte_udp.h>
73 #include <rte_sctp.h>
74 #include <rte_prefetch.h>
75 #include <rte_string_fns.h>
76 #include "testpmd.h"
77
78
79
80 #define IP_DEFTTL  64   /* from RFC 1340. */
81 #define IP_VERSION 0x40
82 #define IP_HDRLEN  0x05 /* default IP header length == five 32-bits words. */
83 #define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
84
85 /* Pseudo Header for IPv4/UDP/TCP checksum */
86 struct psd_header {
87         uint32_t src_addr; /* IP address of source host. */
88         uint32_t dst_addr; /* IP address of destination host(s). */
89         uint8_t  zero;     /* zero. */
90         uint8_t  proto;    /* L4 protocol type. */
91         uint16_t len;      /* L4 length. */
92 } __attribute__((__packed__));
93
94
95 /* Pseudo Header for IPv6/UDP/TCP checksum */
96 struct ipv6_psd_header {
97         uint8_t src_addr[16]; /* IP address of source host. */
98         uint8_t dst_addr[16]; /* IP address of destination host(s). */
99         uint32_t len;         /* L4 length. */
100         uint8_t  zero[3];     /* zero. */
101         uint8_t  proto;       /* L4 protocol. */
102 } __attribute__((__packed__));
103
104
105 static inline uint16_t
106 get_16b_sum(uint16_t *ptr16, uint32_t nr)
107 {
108         uint32_t sum = 0;
109         while (nr > 1)
110         {
111                 sum +=*ptr16;
112                 nr -= sizeof(uint16_t);
113                 ptr16++;
114                 if (sum > UINT16_MAX)
115                         sum -= UINT16_MAX;
116         }
117
118         /* If length is in odd bytes */
119         if (nr)
120                 sum += *((uint8_t*)ptr16);
121
122         sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
123         sum &= 0x0ffff;
124         return (uint16_t)sum;
125 }
126
127 static inline uint16_t
128 get_ipv4_cksum(struct ipv4_hdr *ipv4_hdr)
129 {
130         uint16_t cksum;
131         cksum = get_16b_sum((uint16_t*)ipv4_hdr, sizeof(struct ipv4_hdr));
132         return (uint16_t)((cksum == 0xffff)?cksum:~cksum);
133 }
134
135
136 static inline
137 uint16_t get_ipv4_psd_sum (struct ipv4_hdr * ip_hdr)
138 {
139         struct psd_header psd_hdr;
140         psd_hdr.src_addr = ip_hdr->src_addr;
141         psd_hdr.dst_addr = ip_hdr->dst_addr;
142         psd_hdr.zero     = 0;
143         psd_hdr.proto    = ip_hdr->next_proto_id;
144         psd_hdr.len      = rte_cpu_to_be_16((uint16_t)(rte_be_to_cpu_16(ip_hdr->total_length)
145                                 - sizeof(struct ipv4_hdr)));
146         return get_16b_sum((uint16_t*)&psd_hdr, sizeof(struct psd_header));
147 }
148
149 static inline
150 uint16_t get_ipv6_psd_sum (struct ipv6_hdr * ip_hdr)
151 {
152         struct ipv6_psd_header psd_hdr;
153         rte_memcpy(psd_hdr.src_addr, ip_hdr->src_addr, sizeof(ip_hdr->src_addr)
154                         + sizeof(ip_hdr->dst_addr));
155
156         psd_hdr.zero[0]   = 0;
157         psd_hdr.zero[1]   = 0;
158         psd_hdr.zero[2]   = 0;
159         psd_hdr.proto     = ip_hdr->proto;
160         psd_hdr.len       = ip_hdr->payload_len;
161
162         return get_16b_sum((uint16_t*)&psd_hdr, sizeof(struct ipv6_psd_header));
163 }
164
165 static inline uint16_t
166 get_ipv4_udptcp_checksum(struct ipv4_hdr *ipv4_hdr, uint16_t *l4_hdr)
167 {
168         uint32_t cksum;
169         uint32_t l4_len;
170
171         l4_len = rte_be_to_cpu_16(ipv4_hdr->total_length) - sizeof(struct ipv4_hdr);
172
173         cksum = get_16b_sum(l4_hdr, l4_len);
174         cksum += get_ipv4_psd_sum(ipv4_hdr);
175
176         cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
177         cksum = (~cksum) & 0xffff;
178         if (cksum == 0)
179                 cksum = 0xffff;
180         return (uint16_t)cksum;
181
182 }
183
184 static inline uint16_t
185 get_ipv6_udptcp_checksum(struct ipv6_hdr *ipv6_hdr, uint16_t *l4_hdr)
186 {
187         uint32_t cksum;
188         uint32_t l4_len;
189
190         l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len);
191
192         cksum = get_16b_sum(l4_hdr, l4_len);
193         cksum += get_ipv6_psd_sum(ipv6_hdr);
194
195         cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
196         cksum = (~cksum) & 0xffff;
197         if (cksum == 0)
198                 cksum = 0xffff;
199
200         return (uint16_t)cksum;
201 }
202
203
204 /*
205  * Forwarding of packets. Change the checksum field with HW or SW methods
206  * The HW/SW method selection depends on the ol_flags on every packet
207  */
208 static void
209 pkt_burst_checksum_forward(struct fwd_stream *fs)
210 {
211         struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
212         struct rte_port  *txp;
213         struct rte_mbuf  *mb;
214         struct ether_hdr *eth_hdr;
215         struct ipv4_hdr  *ipv4_hdr;
216         struct ipv6_hdr  *ipv6_hdr;
217         struct udp_hdr   *udp_hdr;
218         struct tcp_hdr   *tcp_hdr;
219         struct sctp_hdr  *sctp_hdr;
220
221         uint16_t nb_rx;
222         uint16_t nb_tx;
223         uint16_t i;
224         uint16_t ol_flags;
225         uint16_t pkt_ol_flags;
226         uint16_t tx_ol_flags;
227         uint16_t l4_proto;
228         uint8_t  l2_len;
229         uint8_t  l3_len;
230
231         uint32_t rx_bad_ip_csum;
232         uint32_t rx_bad_l4_csum;
233
234 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
235         uint64_t start_tsc;
236         uint64_t end_tsc;
237         uint64_t core_cycles;
238 #endif
239
240 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
241         start_tsc = rte_rdtsc();
242 #endif
243
244         /*
245          * Receive a burst of packets and forward them.
246          */
247         nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
248                                  nb_pkt_per_burst);
249         if (unlikely(nb_rx == 0))
250                 return;
251
252 #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
253         fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
254 #endif
255         fs->rx_packets += nb_rx;
256         rx_bad_ip_csum = 0;
257         rx_bad_l4_csum = 0;
258
259         txp = &ports[fs->tx_port];
260         tx_ol_flags = txp->tx_ol_flags;
261
262         for (i = 0; i < nb_rx; i++) {
263
264                 mb = pkts_burst[i];
265                 l2_len  = sizeof(struct ether_hdr);
266                 pkt_ol_flags = mb->ol_flags;
267                 ol_flags = (uint16_t) (pkt_ol_flags & (~PKT_TX_L4_MASK));
268
269                 eth_hdr = (struct ether_hdr *) mb->pkt.data;
270                 if (rte_be_to_cpu_16(eth_hdr->ether_type) == ETHER_TYPE_VLAN) {
271                         /* Only allow single VLAN label here */
272                         l2_len  += sizeof(struct vlan_hdr);
273                 }
274
275                 /* Update the L3/L4 checksum error packet count  */
276                 rx_bad_ip_csum += (uint16_t) ((pkt_ol_flags & PKT_RX_IP_CKSUM_BAD) != 0);
277                 rx_bad_l4_csum += (uint16_t) ((pkt_ol_flags & PKT_RX_L4_CKSUM_BAD) != 0);
278
279                 /*
280                  * Simplify the protocol parsing
281                  * Assuming the incoming packets format as
282                  *      Ethernet2 + optional single VLAN
283                  *      + ipv4 or ipv6
284                  *      + udp or tcp or sctp or others
285                  */
286                 if (pkt_ol_flags & PKT_RX_IPV4_HDR) {
287
288                         /* Do not support ipv4 option field */
289                         l3_len = sizeof(struct ipv4_hdr) ;
290
291                         ipv4_hdr = (struct ipv4_hdr *) (rte_pktmbuf_mtod(mb,
292                                         unsigned char *) + l2_len);
293
294                         l4_proto = ipv4_hdr->next_proto_id;
295
296                         /* Do not delete, this is required by HW*/
297                         ipv4_hdr->hdr_checksum = 0;
298
299                         if (tx_ol_flags & 0x1) {
300                                 /* HW checksum */
301                                 ol_flags |= PKT_TX_IP_CKSUM;
302                         }
303                         else {
304                                 /* SW checksum calculation */
305                                 ipv4_hdr->src_addr++;
306                                 ipv4_hdr->hdr_checksum = get_ipv4_cksum(ipv4_hdr);
307                         }
308
309                         if (l4_proto == IPPROTO_UDP) {
310                                 udp_hdr = (struct udp_hdr*) (rte_pktmbuf_mtod(mb,
311                                                 unsigned char *) + l2_len + l3_len);
312                                 if (tx_ol_flags & 0x2) {
313                                         /* HW Offload */
314                                         ol_flags |= PKT_TX_UDP_CKSUM;
315                                         /* Pseudo header sum need be set properly */
316                                         udp_hdr->dgram_cksum = get_ipv4_psd_sum(ipv4_hdr);
317                                 }
318                                 else {
319                                         /* SW Implementation, clear checksum field first */
320                                         udp_hdr->dgram_cksum = 0;
321                                         udp_hdr->dgram_cksum = get_ipv4_udptcp_checksum(ipv4_hdr,
322                                                         (uint16_t*)udp_hdr);
323                                 }
324                         }
325                         else if (l4_proto == IPPROTO_TCP){
326                                 tcp_hdr = (struct tcp_hdr*) (rte_pktmbuf_mtod(mb,
327                                                 unsigned char *) + l2_len + l3_len);
328                                 if (tx_ol_flags & 0x4) {
329                                         ol_flags |= PKT_TX_TCP_CKSUM;
330                                         tcp_hdr->cksum = get_ipv4_psd_sum(ipv4_hdr);
331                                 }
332                                 else {
333                                         tcp_hdr->cksum = 0;
334                                         tcp_hdr->cksum = get_ipv4_udptcp_checksum(ipv4_hdr,
335                                                         (uint16_t*)tcp_hdr);
336                                 }
337                         }
338                         else if (l4_proto == IPPROTO_SCTP) {
339                                 sctp_hdr = (struct sctp_hdr*) (rte_pktmbuf_mtod(mb,
340                                                 unsigned char *) + l2_len + l3_len);
341
342                                 if (tx_ol_flags & 0x8) {
343                                         ol_flags |= PKT_TX_SCTP_CKSUM;
344                                         sctp_hdr->cksum = 0;
345
346                                         /* Sanity check, only number of 4 bytes supported */
347                                         if ((rte_be_to_cpu_16(ipv4_hdr->total_length) % 4) != 0)
348                                                 printf("sctp payload must be a multiple "
349                                                         "of 4 bytes for checksum offload");
350                                 }
351                                 else {
352                                         sctp_hdr->cksum = 0;
353                                         /* CRC32c sample code available in RFC3309 */
354                                 }
355                         }
356                         /* End of L4 Handling*/
357                 }
358
359                 else {
360                         ipv6_hdr = (struct ipv6_hdr *) (rte_pktmbuf_mtod(mb,
361                                         unsigned char *) + l2_len);
362                         l3_len = sizeof(struct ipv6_hdr) ;
363                         l4_proto = ipv6_hdr->proto;
364
365                         if (l4_proto == IPPROTO_UDP) {
366                                 udp_hdr = (struct udp_hdr*) (rte_pktmbuf_mtod(mb,
367                                                 unsigned char *) + l2_len + l3_len);
368                                 if (tx_ol_flags & 0x2) {
369                                         /* HW Offload */
370                                         ol_flags |= PKT_TX_UDP_CKSUM;
371                                         udp_hdr->dgram_cksum = get_ipv6_psd_sum(ipv6_hdr);
372                                 }
373                                 else {
374                                         /* SW Implementation */
375                                         /* checksum field need be clear first */
376                                         udp_hdr->dgram_cksum = 0;
377                                         udp_hdr->dgram_cksum = get_ipv6_udptcp_checksum(ipv6_hdr,
378                                                         (uint16_t*)udp_hdr);
379                                 }
380                         }
381                         else if (l4_proto == IPPROTO_TCP) {
382                                 tcp_hdr = (struct tcp_hdr*) (rte_pktmbuf_mtod(mb,
383                                                 unsigned char *) + l2_len + l3_len);
384                                 if (tx_ol_flags & 0x4) {
385                                         ol_flags |= PKT_TX_TCP_CKSUM;
386                                         tcp_hdr->cksum = get_ipv6_psd_sum(ipv6_hdr);
387                                 }
388                                 else {
389                                         tcp_hdr->cksum = 0;
390                                         tcp_hdr->cksum = get_ipv6_udptcp_checksum(ipv6_hdr,
391                                                         (uint16_t*)tcp_hdr);
392                                 }
393                         }
394                         else if (l4_proto == IPPROTO_SCTP) {
395                                 sctp_hdr = (struct sctp_hdr*) (rte_pktmbuf_mtod(mb,
396                                                 unsigned char *) + l2_len + l3_len);
397
398                                 if (tx_ol_flags & 0x8) {
399                                         ol_flags |= PKT_TX_SCTP_CKSUM;
400                                         sctp_hdr->cksum = 0;
401                                         /* Sanity check, only number of 4 bytes supported by HW */
402                                         if ((rte_be_to_cpu_16(ipv6_hdr->payload_len) % 4) != 0)
403                                                 printf("sctp payload must be a multiple "
404                                                         "of 4 bytes for checksum offload");
405                                 }
406                                 else {
407                                         /* CRC32c sample code available in RFC3309 */
408                                         sctp_hdr->cksum = 0;
409                                 }
410                         } else {
411                                 printf("Test flow control for 1G PMD \n");
412                         }
413                         /* End of L4 Handling*/
414                 }
415
416                 /* Combine the packet header write. VLAN is not consider here */
417                 mb->pkt.l2_len = l2_len;
418                 mb->pkt.l3_len = l3_len;
419                 mb->ol_flags = ol_flags;
420         }
421         nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx);
422         fs->tx_packets += nb_tx;
423         fs->rx_bad_ip_csum += rx_bad_ip_csum;
424         fs->rx_bad_l4_csum += rx_bad_l4_csum;
425
426 #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
427         fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
428 #endif
429         if (unlikely(nb_tx < nb_rx)) {
430                 fs->fwd_dropped += (nb_rx - nb_tx);
431                 do {
432                         rte_pktmbuf_free(pkts_burst[nb_tx]);
433                 } while (++nb_tx < nb_rx);
434         }
435 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
436         end_tsc = rte_rdtsc();
437         core_cycles = (end_tsc - start_tsc);
438         fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
439 #endif
440 }
441
442
443 struct fwd_engine csum_fwd_engine = {
444         .fwd_mode_name  = "csum",
445         .port_fwd_begin = NULL,
446         .port_fwd_end   = NULL,
447         .packet_fwd     = pkt_burst_checksum_forward,
448 };
449