xref: /dpdk/app/test/packet_burst_generator.c (revision b19f366c)
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 }
459