test: fix TCP header initialization
[dpdk.git] / app / test / packet_burst_generator.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4
5 #include <rte_byteorder.h>
6 #include <rte_mbuf.h>
7 #include <rte_ip.h>
8
9 #include "packet_burst_generator.h"
10
11 #define UDP_SRC_PORT 1024
12 #define UDP_DST_PORT 1024
13
14
15 #define IP_DEFTTL  64   /* from RFC 1340. */
16
17 static void
18 copy_buf_to_pkt_segs(void *buf, unsigned len, struct rte_mbuf *pkt,
19                 unsigned offset)
20 {
21         struct rte_mbuf *seg;
22         void *seg_buf;
23         unsigned copy_len;
24
25         seg = pkt;
26         while (offset >= seg->data_len) {
27                 offset -= seg->data_len;
28                 seg = seg->next;
29         }
30         copy_len = seg->data_len - offset;
31         seg_buf = rte_pktmbuf_mtod_offset(seg, char *, offset);
32         while (len > copy_len) {
33                 rte_memcpy(seg_buf, buf, (size_t) copy_len);
34                 len -= copy_len;
35                 buf = ((char *) buf + copy_len);
36                 seg = seg->next;
37                 seg_buf = rte_pktmbuf_mtod(seg, void *);
38         }
39         rte_memcpy(seg_buf, buf, (size_t) len);
40 }
41
42 static inline void
43 copy_buf_to_pkt(void *buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
44 {
45         if (offset + len <= pkt->data_len) {
46                 rte_memcpy(rte_pktmbuf_mtod_offset(pkt, char *, offset), buf,
47                            (size_t) len);
48                 return;
49         }
50         copy_buf_to_pkt_segs(buf, len, pkt, offset);
51 }
52
53 void
54 initialize_eth_header(struct rte_ether_hdr *eth_hdr,
55                 struct rte_ether_addr *src_mac,
56                 struct rte_ether_addr *dst_mac, uint16_t ether_type,
57                 uint8_t vlan_enabled, uint16_t van_id)
58 {
59         rte_ether_addr_copy(dst_mac, &eth_hdr->d_addr);
60         rte_ether_addr_copy(src_mac, &eth_hdr->s_addr);
61
62         if (vlan_enabled) {
63                 struct rte_vlan_hdr *vhdr = (struct rte_vlan_hdr *)(
64                         (uint8_t *)eth_hdr + sizeof(struct rte_ether_hdr));
65
66                 eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
67
68                 vhdr->eth_proto =  rte_cpu_to_be_16(ether_type);
69                 vhdr->vlan_tci = van_id;
70         } else {
71                 eth_hdr->ether_type = rte_cpu_to_be_16(ether_type);
72         }
73 }
74
75 void
76 initialize_arp_header(struct rte_arp_hdr *arp_hdr,
77                 struct rte_ether_addr *src_mac,
78                 struct rte_ether_addr *dst_mac,
79                 uint32_t src_ip, uint32_t dst_ip,
80                 uint32_t opcode)
81 {
82         arp_hdr->arp_hardware = rte_cpu_to_be_16(RTE_ARP_HRD_ETHER);
83         arp_hdr->arp_protocol = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
84         arp_hdr->arp_hlen = RTE_ETHER_ADDR_LEN;
85         arp_hdr->arp_plen = sizeof(uint32_t);
86         arp_hdr->arp_opcode = rte_cpu_to_be_16(opcode);
87         rte_ether_addr_copy(src_mac, &arp_hdr->arp_data.arp_sha);
88         arp_hdr->arp_data.arp_sip = src_ip;
89         rte_ether_addr_copy(dst_mac, &arp_hdr->arp_data.arp_tha);
90         arp_hdr->arp_data.arp_tip = dst_ip;
91 }
92
93 uint16_t
94 initialize_udp_header(struct rte_udp_hdr *udp_hdr, uint16_t src_port,
95                 uint16_t dst_port, uint16_t pkt_data_len)
96 {
97         uint16_t pkt_len;
98
99         pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_udp_hdr));
100
101         udp_hdr->src_port = rte_cpu_to_be_16(src_port);
102         udp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
103         udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len);
104         udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
105
106         return pkt_len;
107 }
108
109 uint16_t
110 initialize_tcp_header(struct rte_tcp_hdr *tcp_hdr, uint16_t src_port,
111                 uint16_t dst_port, uint16_t pkt_data_len)
112 {
113         uint16_t pkt_len;
114
115         pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_tcp_hdr));
116
117         memset(tcp_hdr, 0, sizeof(struct rte_tcp_hdr));
118         tcp_hdr->src_port = rte_cpu_to_be_16(src_port);
119         tcp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
120         tcp_hdr->data_off = (sizeof(struct rte_tcp_hdr) << 2) & 0xF0;
121
122         return pkt_len;
123 }
124
125 uint16_t
126 initialize_sctp_header(struct rte_sctp_hdr *sctp_hdr, uint16_t src_port,
127                 uint16_t dst_port, uint16_t pkt_data_len)
128 {
129         uint16_t pkt_len;
130
131         pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_udp_hdr));
132
133         sctp_hdr->src_port = rte_cpu_to_be_16(src_port);
134         sctp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
135         sctp_hdr->tag = 0;
136         sctp_hdr->cksum = 0; /* No SCTP checksum. */
137
138         return pkt_len;
139 }
140
141 uint16_t
142 initialize_ipv6_header(struct rte_ipv6_hdr *ip_hdr, uint8_t *src_addr,
143                 uint8_t *dst_addr, uint16_t pkt_data_len)
144 {
145         ip_hdr->vtc_flow = 0;
146         ip_hdr->payload_len = pkt_data_len;
147         ip_hdr->proto = IPPROTO_UDP;
148         ip_hdr->hop_limits = IP_DEFTTL;
149
150         rte_memcpy(ip_hdr->src_addr, src_addr, sizeof(ip_hdr->src_addr));
151         rte_memcpy(ip_hdr->dst_addr, dst_addr, sizeof(ip_hdr->dst_addr));
152
153         return (uint16_t) (pkt_data_len + sizeof(struct rte_ipv6_hdr));
154 }
155
156 uint16_t
157 initialize_ipv4_header(struct rte_ipv4_hdr *ip_hdr, uint32_t src_addr,
158                 uint32_t dst_addr, uint16_t pkt_data_len)
159 {
160         uint16_t pkt_len;
161         unaligned_uint16_t *ptr16;
162         uint32_t ip_cksum;
163
164         /*
165          * Initialize IP header.
166          */
167         pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_ipv4_hdr));
168
169         ip_hdr->version_ihl   = RTE_IPV4_VHL_DEF;
170         ip_hdr->type_of_service   = 0;
171         ip_hdr->fragment_offset = 0;
172         ip_hdr->time_to_live   = IP_DEFTTL;
173         ip_hdr->next_proto_id = IPPROTO_UDP;
174         ip_hdr->packet_id = 0;
175         ip_hdr->total_length   = rte_cpu_to_be_16(pkt_len);
176         ip_hdr->src_addr = rte_cpu_to_be_32(src_addr);
177         ip_hdr->dst_addr = rte_cpu_to_be_32(dst_addr);
178
179         /*
180          * Compute IP header checksum.
181          */
182         ptr16 = (unaligned_uint16_t *)ip_hdr;
183         ip_cksum = 0;
184         ip_cksum += ptr16[0]; ip_cksum += ptr16[1];
185         ip_cksum += ptr16[2]; ip_cksum += ptr16[3];
186         ip_cksum += ptr16[4];
187         ip_cksum += ptr16[6]; ip_cksum += ptr16[7];
188         ip_cksum += ptr16[8]; ip_cksum += ptr16[9];
189
190         /*
191          * Reduce 32 bit checksum to 16 bits and complement it.
192          */
193         ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) +
194                 (ip_cksum & 0x0000FFFF);
195         ip_cksum %= 65536;
196         ip_cksum = (~ip_cksum) & 0x0000FFFF;
197         if (ip_cksum == 0)
198                 ip_cksum = 0xFFFF;
199         ip_hdr->hdr_checksum = (uint16_t) ip_cksum;
200
201         return pkt_len;
202 }
203
204 uint16_t
205 initialize_ipv4_header_proto(struct rte_ipv4_hdr *ip_hdr, uint32_t src_addr,
206                 uint32_t dst_addr, uint16_t pkt_data_len, uint8_t proto)
207 {
208         uint16_t pkt_len;
209         unaligned_uint16_t *ptr16;
210         uint32_t ip_cksum;
211
212         /*
213          * Initialize IP header.
214          */
215         pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_ipv4_hdr));
216
217         ip_hdr->version_ihl   = RTE_IPV4_VHL_DEF;
218         ip_hdr->type_of_service   = 0;
219         ip_hdr->fragment_offset = 0;
220         ip_hdr->time_to_live   = IP_DEFTTL;
221         ip_hdr->next_proto_id = proto;
222         ip_hdr->packet_id = 0;
223         ip_hdr->total_length   = rte_cpu_to_be_16(pkt_len);
224         ip_hdr->src_addr = rte_cpu_to_be_32(src_addr);
225         ip_hdr->dst_addr = rte_cpu_to_be_32(dst_addr);
226
227         /*
228          * Compute IP header checksum.
229          */
230         ptr16 = (unaligned_uint16_t *)ip_hdr;
231         ip_cksum = 0;
232         ip_cksum += ptr16[0]; ip_cksum += ptr16[1];
233         ip_cksum += ptr16[2]; ip_cksum += ptr16[3];
234         ip_cksum += ptr16[4];
235         ip_cksum += ptr16[6]; ip_cksum += ptr16[7];
236         ip_cksum += ptr16[8]; ip_cksum += ptr16[9];
237
238         /*
239          * Reduce 32 bit checksum to 16 bits and complement it.
240          */
241         ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) +
242                 (ip_cksum & 0x0000FFFF);
243         ip_cksum %= 65536;
244         ip_cksum = (~ip_cksum) & 0x0000FFFF;
245         if (ip_cksum == 0)
246                 ip_cksum = 0xFFFF;
247         ip_hdr->hdr_checksum = (uint16_t) ip_cksum;
248
249         return pkt_len;
250 }
251
252 /*
253  * The maximum number of segments per packet is used when creating
254  * scattered transmit packets composed of a list of mbufs.
255  */
256 #define RTE_MAX_SEGS_PER_PKT 255 /**< pkt.nb_segs is a 8-bit unsigned char. */
257
258
259 int
260 generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst,
261                 struct rte_ether_hdr *eth_hdr, uint8_t vlan_enabled,
262                 void *ip_hdr, uint8_t ipv4, struct rte_udp_hdr *udp_hdr,
263                 int nb_pkt_per_burst, uint8_t pkt_len, uint8_t nb_pkt_segs)
264 {
265         int i, nb_pkt = 0;
266         size_t eth_hdr_size;
267
268         struct rte_mbuf *pkt_seg;
269         struct rte_mbuf *pkt;
270
271         for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
272                 pkt = rte_pktmbuf_alloc(mp);
273                 if (pkt == NULL) {
274 nomore_mbuf:
275                         if (nb_pkt == 0)
276                                 return -1;
277                         break;
278                 }
279
280                 pkt->data_len = pkt_len;
281                 pkt_seg = pkt;
282                 for (i = 1; i < nb_pkt_segs; i++) {
283                         pkt_seg->next = rte_pktmbuf_alloc(mp);
284                         if (pkt_seg->next == NULL) {
285                                 pkt->nb_segs = i;
286                                 rte_pktmbuf_free(pkt);
287                                 goto nomore_mbuf;
288                         }
289                         pkt_seg = pkt_seg->next;
290                         pkt_seg->data_len = pkt_len;
291                 }
292                 pkt_seg->next = NULL; /* Last segment of packet. */
293
294                 /*
295                  * Copy headers in first packet segment(s).
296                  */
297                 if (vlan_enabled)
298                         eth_hdr_size = sizeof(struct rte_ether_hdr) +
299                                 sizeof(struct rte_vlan_hdr);
300                 else
301                         eth_hdr_size = sizeof(struct rte_ether_hdr);
302
303                 copy_buf_to_pkt(eth_hdr, eth_hdr_size, pkt, 0);
304
305                 if (ipv4) {
306                         copy_buf_to_pkt(ip_hdr, sizeof(struct rte_ipv4_hdr),
307                                 pkt, eth_hdr_size);
308                         copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt,
309                                 eth_hdr_size + sizeof(struct rte_ipv4_hdr));
310                 } else {
311                         copy_buf_to_pkt(ip_hdr, sizeof(struct rte_ipv6_hdr),
312                                 pkt, eth_hdr_size);
313                         copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt,
314                                 eth_hdr_size + sizeof(struct rte_ipv6_hdr));
315                 }
316
317                 /*
318                  * Complete first mbuf of packet and append it to the
319                  * burst of packets to be transmitted.
320                  */
321                 pkt->nb_segs = nb_pkt_segs;
322                 pkt->pkt_len = pkt_len;
323                 pkt->l2_len = eth_hdr_size;
324
325                 if (ipv4) {
326                         pkt->vlan_tci  = RTE_ETHER_TYPE_IPV4;
327                         pkt->l3_len = sizeof(struct rte_ipv4_hdr);
328                 } else {
329                         pkt->vlan_tci  = RTE_ETHER_TYPE_IPV6;
330                         pkt->l3_len = sizeof(struct rte_ipv6_hdr);
331                 }
332
333                 pkts_burst[nb_pkt] = pkt;
334         }
335
336         return nb_pkt;
337 }
338
339 int
340 generate_packet_burst_proto(struct rte_mempool *mp,
341                 struct rte_mbuf **pkts_burst, struct rte_ether_hdr *eth_hdr,
342                 uint8_t vlan_enabled, void *ip_hdr,
343                 uint8_t ipv4, uint8_t proto, void *proto_hdr,
344                 int nb_pkt_per_burst, uint8_t pkt_len, uint8_t nb_pkt_segs)
345 {
346         int i, nb_pkt = 0;
347         size_t eth_hdr_size;
348
349         struct rte_mbuf *pkt_seg;
350         struct rte_mbuf *pkt;
351
352         for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
353                 pkt = rte_pktmbuf_alloc(mp);
354                 if (pkt == NULL) {
355 nomore_mbuf:
356                         if (nb_pkt == 0)
357                                 return -1;
358                         break;
359                 }
360
361                 pkt->data_len = pkt_len;
362                 pkt_seg = pkt;
363                 for (i = 1; i < nb_pkt_segs; i++) {
364                         pkt_seg->next = rte_pktmbuf_alloc(mp);
365                         if (pkt_seg->next == NULL) {
366                                 pkt->nb_segs = i;
367                                 rte_pktmbuf_free(pkt);
368                                 goto nomore_mbuf;
369                         }
370                         pkt_seg = pkt_seg->next;
371                         pkt_seg->data_len = pkt_len;
372                 }
373                 pkt_seg->next = NULL; /* Last segment of packet. */
374
375                 /*
376                  * Copy headers in first packet segment(s).
377                  */
378                 if (vlan_enabled)
379                         eth_hdr_size = sizeof(struct rte_ether_hdr) +
380                                 sizeof(struct rte_vlan_hdr);
381                 else
382                         eth_hdr_size = sizeof(struct rte_ether_hdr);
383
384                 copy_buf_to_pkt(eth_hdr, eth_hdr_size, pkt, 0);
385
386                 if (ipv4) {
387                         copy_buf_to_pkt(ip_hdr, sizeof(struct rte_ipv4_hdr),
388                                         pkt, eth_hdr_size);
389                         switch (proto) {
390                         case IPPROTO_UDP:
391                                 copy_buf_to_pkt(proto_hdr,
392                                         sizeof(struct rte_udp_hdr), pkt,
393                                         eth_hdr_size +
394                                                 sizeof(struct rte_ipv4_hdr));
395                                 break;
396                         case IPPROTO_TCP:
397                                 copy_buf_to_pkt(proto_hdr,
398                                         sizeof(struct rte_tcp_hdr), pkt,
399                                         eth_hdr_size +
400                                                 sizeof(struct rte_ipv4_hdr));
401                                 break;
402                         case IPPROTO_SCTP:
403                                 copy_buf_to_pkt(proto_hdr,
404                                         sizeof(struct rte_sctp_hdr), pkt,
405                                         eth_hdr_size +
406                                                 sizeof(struct rte_ipv4_hdr));
407                                 break;
408                         default:
409                                 break;
410                         }
411                 } else {
412                         copy_buf_to_pkt(ip_hdr, sizeof(struct rte_ipv6_hdr),
413                                         pkt, eth_hdr_size);
414                         switch (proto) {
415                         case IPPROTO_UDP:
416                                 copy_buf_to_pkt(proto_hdr,
417                                         sizeof(struct rte_udp_hdr), pkt,
418                                         eth_hdr_size +
419                                                 sizeof(struct rte_ipv6_hdr));
420                                 break;
421                         case IPPROTO_TCP:
422                                 copy_buf_to_pkt(proto_hdr,
423                                         sizeof(struct rte_tcp_hdr), pkt,
424                                         eth_hdr_size +
425                                                 sizeof(struct rte_ipv6_hdr));
426                                 break;
427                         case IPPROTO_SCTP:
428                                 copy_buf_to_pkt(proto_hdr,
429                                         sizeof(struct rte_sctp_hdr), pkt,
430                                         eth_hdr_size +
431                                                 sizeof(struct rte_ipv6_hdr));
432                                 break;
433                         default:
434                                 break;
435                         }
436                 }
437
438                 /*
439                  * Complete first mbuf of packet and append it to the
440                  * burst of packets to be transmitted.
441                  */
442                 pkt->nb_segs = nb_pkt_segs;
443                 pkt->pkt_len = pkt_len;
444                 pkt->l2_len = eth_hdr_size;
445
446                 if (ipv4) {
447                         pkt->vlan_tci  = RTE_ETHER_TYPE_IPV4;
448                         pkt->l3_len = sizeof(struct rte_ipv4_hdr);
449                 } else {
450                         pkt->vlan_tci  = RTE_ETHER_TYPE_IPV6;
451                         pkt->l3_len = sizeof(struct rte_ipv6_hdr);
452                 }
453
454                 pkts_burst[nb_pkt] = pkt;
455         }
456
457         return nb_pkt;
458 }