xref: /dpdk/app/test/packet_burst_generator.c (revision f9e1d67f237a00cf94feb4413e3d978fdd632052)
1a9de470cSBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2a9de470cSBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
3a9de470cSBruce Richardson  */
4a9de470cSBruce Richardson 
5a9de470cSBruce Richardson #include <rte_byteorder.h>
6a9de470cSBruce Richardson #include <rte_mbuf.h>
75fde1a75SReshma Pattan #include <rte_ip.h>
8987d40a0SJie Zhou #include <rte_os_shim.h>
9a9de470cSBruce Richardson 
10a9de470cSBruce Richardson #include "packet_burst_generator.h"
11a9de470cSBruce Richardson 
12a9de470cSBruce Richardson #define UDP_SRC_PORT 1024
13a9de470cSBruce Richardson #define UDP_DST_PORT 1024
14a9de470cSBruce Richardson 
15a9de470cSBruce Richardson 
16a9de470cSBruce Richardson #define IP_DEFTTL  64   /* from RFC 1340. */
17a9de470cSBruce Richardson 
18a9de470cSBruce Richardson static void
19a9de470cSBruce Richardson copy_buf_to_pkt_segs(void *buf, unsigned len, struct rte_mbuf *pkt,
20a9de470cSBruce Richardson 		unsigned offset)
21a9de470cSBruce Richardson {
22a9de470cSBruce Richardson 	struct rte_mbuf *seg;
23a9de470cSBruce Richardson 	void *seg_buf;
24a9de470cSBruce Richardson 	unsigned copy_len;
25a9de470cSBruce Richardson 
26a9de470cSBruce Richardson 	seg = pkt;
27a9de470cSBruce Richardson 	while (offset >= seg->data_len) {
28a9de470cSBruce Richardson 		offset -= seg->data_len;
29a9de470cSBruce Richardson 		seg = seg->next;
30a9de470cSBruce Richardson 	}
31a9de470cSBruce Richardson 	copy_len = seg->data_len - offset;
32a9de470cSBruce Richardson 	seg_buf = rte_pktmbuf_mtod_offset(seg, char *, offset);
33a9de470cSBruce Richardson 	while (len > copy_len) {
34a9de470cSBruce Richardson 		rte_memcpy(seg_buf, buf, (size_t) copy_len);
35a9de470cSBruce Richardson 		len -= copy_len;
36a9de470cSBruce Richardson 		buf = ((char *) buf + copy_len);
37a9de470cSBruce Richardson 		seg = seg->next;
38a9de470cSBruce Richardson 		seg_buf = rte_pktmbuf_mtod(seg, void *);
39a9de470cSBruce Richardson 	}
40a9de470cSBruce Richardson 	rte_memcpy(seg_buf, buf, (size_t) len);
41a9de470cSBruce Richardson }
42a9de470cSBruce Richardson 
43a9de470cSBruce Richardson static inline void
44a9de470cSBruce Richardson copy_buf_to_pkt(void *buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
45a9de470cSBruce Richardson {
46a9de470cSBruce Richardson 	if (offset + len <= pkt->data_len) {
47a9de470cSBruce Richardson 		rte_memcpy(rte_pktmbuf_mtod_offset(pkt, char *, offset), buf,
48a9de470cSBruce Richardson 			   (size_t) len);
49a9de470cSBruce Richardson 		return;
50a9de470cSBruce Richardson 	}
51a9de470cSBruce Richardson 	copy_buf_to_pkt_segs(buf, len, pkt, offset);
52a9de470cSBruce Richardson }
53a9de470cSBruce Richardson 
54a9de470cSBruce Richardson void
556d13ea8eSOlivier Matz initialize_eth_header(struct rte_ether_hdr *eth_hdr,
566d13ea8eSOlivier Matz 		struct rte_ether_addr *src_mac,
576d13ea8eSOlivier Matz 		struct rte_ether_addr *dst_mac, uint16_t ether_type,
58a9de470cSBruce Richardson 		uint8_t vlan_enabled, uint16_t van_id)
59a9de470cSBruce Richardson {
6004d43857SDmitry Kozlyuk 	rte_ether_addr_copy(dst_mac, &eth_hdr->dst_addr);
6104d43857SDmitry Kozlyuk 	rte_ether_addr_copy(src_mac, &eth_hdr->src_addr);
62a9de470cSBruce Richardson 
63a9de470cSBruce Richardson 	if (vlan_enabled) {
646d13ea8eSOlivier Matz 		struct rte_vlan_hdr *vhdr = (struct rte_vlan_hdr *)(
656d13ea8eSOlivier Matz 			(uint8_t *)eth_hdr + sizeof(struct rte_ether_hdr));
66a9de470cSBruce Richardson 
6735b2d13fSOlivier Matz 		eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
68a9de470cSBruce Richardson 
69a9de470cSBruce Richardson 		vhdr->eth_proto =  rte_cpu_to_be_16(ether_type);
70a9de470cSBruce Richardson 		vhdr->vlan_tci = van_id;
71a9de470cSBruce Richardson 	} else {
72a9de470cSBruce Richardson 		eth_hdr->ether_type = rte_cpu_to_be_16(ether_type);
73a9de470cSBruce Richardson 	}
74a9de470cSBruce Richardson }
75a9de470cSBruce Richardson 
76a9de470cSBruce Richardson void
776d13ea8eSOlivier Matz initialize_arp_header(struct rte_arp_hdr *arp_hdr,
786d13ea8eSOlivier Matz 		struct rte_ether_addr *src_mac,
796d13ea8eSOlivier Matz 		struct rte_ether_addr *dst_mac,
806d13ea8eSOlivier Matz 		uint32_t src_ip, uint32_t dst_ip,
81a9de470cSBruce Richardson 		uint32_t opcode)
82a9de470cSBruce Richardson {
83e482e0faSOlivier Matz 	arp_hdr->arp_hardware = rte_cpu_to_be_16(RTE_ARP_HRD_ETHER);
840c9da755SDavid Marchand 	arp_hdr->arp_protocol = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
8535b2d13fSOlivier Matz 	arp_hdr->arp_hlen = RTE_ETHER_ADDR_LEN;
86f2745bfeSOlivier Matz 	arp_hdr->arp_plen = sizeof(uint32_t);
87f2745bfeSOlivier Matz 	arp_hdr->arp_opcode = rte_cpu_to_be_16(opcode);
88538da7a1SOlivier Matz 	rte_ether_addr_copy(src_mac, &arp_hdr->arp_data.arp_sha);
89a9de470cSBruce Richardson 	arp_hdr->arp_data.arp_sip = src_ip;
90538da7a1SOlivier Matz 	rte_ether_addr_copy(dst_mac, &arp_hdr->arp_data.arp_tha);
91a9de470cSBruce Richardson 	arp_hdr->arp_data.arp_tip = dst_ip;
92a9de470cSBruce Richardson }
93a9de470cSBruce Richardson 
94a9de470cSBruce Richardson uint16_t
95e73e3547SOlivier Matz initialize_udp_header(struct rte_udp_hdr *udp_hdr, uint16_t src_port,
96a9de470cSBruce Richardson 		uint16_t dst_port, uint16_t pkt_data_len)
97a9de470cSBruce Richardson {
98a9de470cSBruce Richardson 	uint16_t pkt_len;
99a9de470cSBruce Richardson 
100e73e3547SOlivier Matz 	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_udp_hdr));
101a9de470cSBruce Richardson 
102a9de470cSBruce Richardson 	udp_hdr->src_port = rte_cpu_to_be_16(src_port);
103a9de470cSBruce Richardson 	udp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
104a9de470cSBruce Richardson 	udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len);
105a9de470cSBruce Richardson 	udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
106a9de470cSBruce Richardson 
107a9de470cSBruce Richardson 	return pkt_len;
108a9de470cSBruce Richardson }
109a9de470cSBruce Richardson 
110a9de470cSBruce Richardson uint16_t
111f41b5156SOlivier Matz initialize_tcp_header(struct rte_tcp_hdr *tcp_hdr, uint16_t src_port,
112a9de470cSBruce Richardson 		uint16_t dst_port, uint16_t pkt_data_len)
113a9de470cSBruce Richardson {
114a9de470cSBruce Richardson 	uint16_t pkt_len;
115a9de470cSBruce Richardson 
116f41b5156SOlivier Matz 	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_tcp_hdr));
117a9de470cSBruce Richardson 
118f41b5156SOlivier Matz 	memset(tcp_hdr, 0, sizeof(struct rte_tcp_hdr));
119a9de470cSBruce Richardson 	tcp_hdr->src_port = rte_cpu_to_be_16(src_port);
120a9de470cSBruce Richardson 	tcp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
1219fdba327SLance Richardson 	tcp_hdr->data_off = (sizeof(struct rte_tcp_hdr) << 2) & 0xF0;
122a9de470cSBruce Richardson 
123a9de470cSBruce Richardson 	return pkt_len;
124a9de470cSBruce Richardson }
125a9de470cSBruce Richardson 
126a9de470cSBruce Richardson uint16_t
12709d9ae1aSOlivier Matz initialize_sctp_header(struct rte_sctp_hdr *sctp_hdr, uint16_t src_port,
128a9de470cSBruce Richardson 		uint16_t dst_port, uint16_t pkt_data_len)
129a9de470cSBruce Richardson {
130a9de470cSBruce Richardson 	uint16_t pkt_len;
131a9de470cSBruce Richardson 
132e73e3547SOlivier Matz 	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_udp_hdr));
133a9de470cSBruce Richardson 
134a9de470cSBruce Richardson 	sctp_hdr->src_port = rte_cpu_to_be_16(src_port);
135a9de470cSBruce Richardson 	sctp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
136a9de470cSBruce Richardson 	sctp_hdr->tag = 0;
137a9de470cSBruce Richardson 	sctp_hdr->cksum = 0; /* No SCTP checksum. */
138a9de470cSBruce Richardson 
139a9de470cSBruce Richardson 	return pkt_len;
140a9de470cSBruce Richardson }
141a9de470cSBruce Richardson 
142a9de470cSBruce Richardson uint16_t
143a7c528e5SOlivier Matz initialize_ipv6_header(struct rte_ipv6_hdr *ip_hdr, uint8_t *src_addr,
144a9de470cSBruce Richardson 		uint8_t *dst_addr, uint16_t pkt_data_len)
145a9de470cSBruce Richardson {
146a906371dSLance Richardson 	ip_hdr->vtc_flow = rte_cpu_to_be_32(0x60000000); /* Set version to 6. */
147a906371dSLance Richardson 	ip_hdr->payload_len = rte_cpu_to_be_16(pkt_data_len);
148a9de470cSBruce Richardson 	ip_hdr->proto = IPPROTO_UDP;
149a9de470cSBruce Richardson 	ip_hdr->hop_limits = IP_DEFTTL;
150a9de470cSBruce Richardson 
15189b5642dSRobin Jarry 	rte_memcpy(&ip_hdr->src_addr, src_addr, sizeof(ip_hdr->src_addr));
15289b5642dSRobin Jarry 	rte_memcpy(&ip_hdr->dst_addr, dst_addr, sizeof(ip_hdr->dst_addr));
153a9de470cSBruce Richardson 
154a7c528e5SOlivier Matz 	return (uint16_t) (pkt_data_len + sizeof(struct rte_ipv6_hdr));
155a9de470cSBruce Richardson }
156a9de470cSBruce Richardson 
157a9de470cSBruce Richardson uint16_t
158a7c528e5SOlivier Matz initialize_ipv4_header(struct rte_ipv4_hdr *ip_hdr, uint32_t src_addr,
159a9de470cSBruce Richardson 		uint32_t dst_addr, uint16_t pkt_data_len)
160a9de470cSBruce Richardson {
161a9de470cSBruce Richardson 	uint16_t pkt_len;
162a9de470cSBruce Richardson 
163a9de470cSBruce Richardson 	/*
164a9de470cSBruce Richardson 	 * Initialize IP header.
165a9de470cSBruce Richardson 	 */
166a7c528e5SOlivier Matz 	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_ipv4_hdr));
167a9de470cSBruce Richardson 
1685fde1a75SReshma Pattan 	ip_hdr->version_ihl   = RTE_IPV4_VHL_DEF;
169a9de470cSBruce Richardson 	ip_hdr->type_of_service   = 0;
170a9de470cSBruce Richardson 	ip_hdr->fragment_offset = 0;
171a9de470cSBruce Richardson 	ip_hdr->time_to_live   = IP_DEFTTL;
172a9de470cSBruce Richardson 	ip_hdr->next_proto_id = IPPROTO_UDP;
173a9de470cSBruce Richardson 	ip_hdr->packet_id = 0;
174a9de470cSBruce Richardson 	ip_hdr->total_length   = rte_cpu_to_be_16(pkt_len);
175a9de470cSBruce Richardson 	ip_hdr->src_addr = rte_cpu_to_be_32(src_addr);
176a9de470cSBruce Richardson 	ip_hdr->dst_addr = rte_cpu_to_be_32(dst_addr);
177a9de470cSBruce Richardson 
178*f9e1d67fSBruce Richardson 	ip_hdr->hdr_checksum = rte_ipv4_cksum_simple(ip_hdr);
179a9de470cSBruce Richardson 
180a9de470cSBruce Richardson 	return pkt_len;
181a9de470cSBruce Richardson }
182a9de470cSBruce Richardson 
183a9de470cSBruce Richardson uint16_t
184a7c528e5SOlivier Matz initialize_ipv4_header_proto(struct rte_ipv4_hdr *ip_hdr, uint32_t src_addr,
185a9de470cSBruce Richardson 		uint32_t dst_addr, uint16_t pkt_data_len, uint8_t proto)
186a9de470cSBruce Richardson {
187a9de470cSBruce Richardson 	uint16_t pkt_len;
188a9de470cSBruce Richardson 
189a9de470cSBruce Richardson 	/*
190a9de470cSBruce Richardson 	 * Initialize IP header.
191a9de470cSBruce Richardson 	 */
192a7c528e5SOlivier Matz 	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_ipv4_hdr));
193a9de470cSBruce Richardson 
1945fde1a75SReshma Pattan 	ip_hdr->version_ihl   = RTE_IPV4_VHL_DEF;
195a9de470cSBruce Richardson 	ip_hdr->type_of_service   = 0;
196a9de470cSBruce Richardson 	ip_hdr->fragment_offset = 0;
197a9de470cSBruce Richardson 	ip_hdr->time_to_live   = IP_DEFTTL;
198a9de470cSBruce Richardson 	ip_hdr->next_proto_id = proto;
199a9de470cSBruce Richardson 	ip_hdr->packet_id = 0;
200a9de470cSBruce Richardson 	ip_hdr->total_length   = rte_cpu_to_be_16(pkt_len);
201a9de470cSBruce Richardson 	ip_hdr->src_addr = rte_cpu_to_be_32(src_addr);
202a9de470cSBruce Richardson 	ip_hdr->dst_addr = rte_cpu_to_be_32(dst_addr);
203*f9e1d67fSBruce Richardson 	ip_hdr->hdr_checksum = rte_ipv4_cksum_simple(ip_hdr);
204a9de470cSBruce Richardson 
205a9de470cSBruce Richardson 	return pkt_len;
206a9de470cSBruce Richardson }
207a9de470cSBruce Richardson 
208a9de470cSBruce Richardson /*
209a9de470cSBruce Richardson  * The maximum number of segments per packet is used when creating
210a9de470cSBruce Richardson  * scattered transmit packets composed of a list of mbufs.
211a9de470cSBruce Richardson  */
212a9de470cSBruce Richardson #define RTE_MAX_SEGS_PER_PKT 255 /**< pkt.nb_segs is a 8-bit unsigned char. */
213a9de470cSBruce Richardson 
214a9de470cSBruce Richardson 
215a9de470cSBruce Richardson int
216a9de470cSBruce Richardson generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst,
2176d13ea8eSOlivier Matz 		struct rte_ether_hdr *eth_hdr, uint8_t vlan_enabled,
218e73e3547SOlivier Matz 		void *ip_hdr, uint8_t ipv4, struct rte_udp_hdr *udp_hdr,
2196d13ea8eSOlivier Matz 		int nb_pkt_per_burst, uint8_t pkt_len, uint8_t nb_pkt_segs)
220a9de470cSBruce Richardson {
221b88b8af2SZhuobin Huang 	const uint8_t pkt_seg_data_len = pkt_len / nb_pkt_segs;
222a9de470cSBruce Richardson 	struct rte_mbuf *pkt_seg;
223a9de470cSBruce Richardson 	struct rte_mbuf *pkt;
224b88b8af2SZhuobin Huang 	size_t eth_hdr_size;
225b88b8af2SZhuobin Huang 	int i, nb_pkt = 0;
226a9de470cSBruce Richardson 
227a9de470cSBruce Richardson 	for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
228a9de470cSBruce Richardson 		pkt = rte_pktmbuf_alloc(mp);
229a9de470cSBruce Richardson 		if (pkt == NULL) {
230a9de470cSBruce Richardson nomore_mbuf:
231a9de470cSBruce Richardson 			if (nb_pkt == 0)
232a9de470cSBruce Richardson 				return -1;
233a9de470cSBruce Richardson 			break;
234a9de470cSBruce Richardson 		}
235a9de470cSBruce Richardson 
236b88b8af2SZhuobin Huang 		pkt->data_len = pkt_seg_data_len;
237a9de470cSBruce Richardson 		pkt_seg = pkt;
238a9de470cSBruce Richardson 		for (i = 1; i < nb_pkt_segs; i++) {
239a9de470cSBruce Richardson 			pkt_seg->next = rte_pktmbuf_alloc(mp);
240a9de470cSBruce Richardson 			if (pkt_seg->next == NULL) {
241a9de470cSBruce Richardson 				pkt->nb_segs = i;
242a9de470cSBruce Richardson 				rte_pktmbuf_free(pkt);
243a9de470cSBruce Richardson 				goto nomore_mbuf;
244a9de470cSBruce Richardson 			}
245a9de470cSBruce Richardson 			pkt_seg = pkt_seg->next;
246b88b8af2SZhuobin Huang 			if (i != nb_pkt_segs - 1)
247b88b8af2SZhuobin Huang 				pkt_seg->data_len = pkt_seg_data_len;
248b88b8af2SZhuobin Huang 			else
249b88b8af2SZhuobin Huang 				pkt_seg->data_len = pkt_seg_data_len + pkt_len % nb_pkt_segs;
250a9de470cSBruce Richardson 		}
251a9de470cSBruce Richardson 		pkt_seg->next = NULL; /* Last segment of packet. */
252a9de470cSBruce Richardson 
253a9de470cSBruce Richardson 		/*
254a9de470cSBruce Richardson 		 * Copy headers in first packet segment(s).
255a9de470cSBruce Richardson 		 */
256a9de470cSBruce Richardson 		if (vlan_enabled)
2576d13ea8eSOlivier Matz 			eth_hdr_size = sizeof(struct rte_ether_hdr) +
2586d13ea8eSOlivier Matz 				sizeof(struct rte_vlan_hdr);
259a9de470cSBruce Richardson 		else
2606d13ea8eSOlivier Matz 			eth_hdr_size = sizeof(struct rte_ether_hdr);
261a9de470cSBruce Richardson 
262a9de470cSBruce Richardson 		copy_buf_to_pkt(eth_hdr, eth_hdr_size, pkt, 0);
263a9de470cSBruce Richardson 
264a9de470cSBruce Richardson 		if (ipv4) {
265a7c528e5SOlivier Matz 			copy_buf_to_pkt(ip_hdr, sizeof(struct rte_ipv4_hdr),
266a7c528e5SOlivier Matz 				pkt, eth_hdr_size);
267a7c528e5SOlivier Matz 			copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt,
268a7c528e5SOlivier Matz 				eth_hdr_size + sizeof(struct rte_ipv4_hdr));
269a9de470cSBruce Richardson 		} else {
270a7c528e5SOlivier Matz 			copy_buf_to_pkt(ip_hdr, sizeof(struct rte_ipv6_hdr),
271a7c528e5SOlivier Matz 				pkt, eth_hdr_size);
272a7c528e5SOlivier Matz 			copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt,
273a7c528e5SOlivier Matz 				eth_hdr_size + sizeof(struct rte_ipv6_hdr));
274a9de470cSBruce Richardson 		}
275a9de470cSBruce Richardson 
276a9de470cSBruce Richardson 		/*
277a9de470cSBruce Richardson 		 * Complete first mbuf of packet and append it to the
278a9de470cSBruce Richardson 		 * burst of packets to be transmitted.
279a9de470cSBruce Richardson 		 */
280a9de470cSBruce Richardson 		pkt->nb_segs = nb_pkt_segs;
281a9de470cSBruce Richardson 		pkt->pkt_len = pkt_len;
282a9de470cSBruce Richardson 		pkt->l2_len = eth_hdr_size;
283a9de470cSBruce Richardson 
284a9de470cSBruce Richardson 		if (ipv4) {
2850c9da755SDavid Marchand 			pkt->vlan_tci  = RTE_ETHER_TYPE_IPV4;
286a7c528e5SOlivier Matz 			pkt->l3_len = sizeof(struct rte_ipv4_hdr);
287a9de470cSBruce Richardson 		} else {
2880c9da755SDavid Marchand 			pkt->vlan_tci  = RTE_ETHER_TYPE_IPV6;
289a7c528e5SOlivier Matz 			pkt->l3_len = sizeof(struct rte_ipv6_hdr);
290a9de470cSBruce Richardson 		}
291a9de470cSBruce Richardson 
292a9de470cSBruce Richardson 		pkts_burst[nb_pkt] = pkt;
293a9de470cSBruce Richardson 	}
294a9de470cSBruce Richardson 
295a9de470cSBruce Richardson 	return nb_pkt;
296a9de470cSBruce Richardson }
297a9de470cSBruce Richardson 
298a9de470cSBruce Richardson int
299a9de470cSBruce Richardson generate_packet_burst_proto(struct rte_mempool *mp,
3006d13ea8eSOlivier Matz 		struct rte_mbuf **pkts_burst, struct rte_ether_hdr *eth_hdr,
3016d13ea8eSOlivier Matz 		uint8_t vlan_enabled, void *ip_hdr,
302a9de470cSBruce Richardson 		uint8_t ipv4, uint8_t proto, void *proto_hdr,
303a9de470cSBruce Richardson 		int nb_pkt_per_burst, uint8_t pkt_len, uint8_t nb_pkt_segs)
304a9de470cSBruce Richardson {
305b88b8af2SZhuobin Huang 	const uint8_t pkt_seg_data_len = pkt_len / nb_pkt_segs;
306a9de470cSBruce Richardson 	struct rte_mbuf *pkt_seg;
307a9de470cSBruce Richardson 	struct rte_mbuf *pkt;
308b88b8af2SZhuobin Huang 	size_t eth_hdr_size;
309b88b8af2SZhuobin Huang 	int i, nb_pkt = 0;
310a9de470cSBruce Richardson 
311a9de470cSBruce Richardson 	for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
312a9de470cSBruce Richardson 		pkt = rte_pktmbuf_alloc(mp);
313a9de470cSBruce Richardson 		if (pkt == NULL) {
314a9de470cSBruce Richardson nomore_mbuf:
315a9de470cSBruce Richardson 			if (nb_pkt == 0)
316a9de470cSBruce Richardson 				return -1;
317a9de470cSBruce Richardson 			break;
318a9de470cSBruce Richardson 		}
319a9de470cSBruce Richardson 
320b88b8af2SZhuobin Huang 		pkt->data_len = pkt_seg_data_len;
321a9de470cSBruce Richardson 		pkt_seg = pkt;
322a9de470cSBruce Richardson 		for (i = 1; i < nb_pkt_segs; i++) {
323a9de470cSBruce Richardson 			pkt_seg->next = rte_pktmbuf_alloc(mp);
324a9de470cSBruce Richardson 			if (pkt_seg->next == NULL) {
325a9de470cSBruce Richardson 				pkt->nb_segs = i;
326a9de470cSBruce Richardson 				rte_pktmbuf_free(pkt);
327a9de470cSBruce Richardson 				goto nomore_mbuf;
328a9de470cSBruce Richardson 			}
329a9de470cSBruce Richardson 			pkt_seg = pkt_seg->next;
330b88b8af2SZhuobin Huang 			if (i != nb_pkt_segs - 1)
331b88b8af2SZhuobin Huang 				pkt_seg->data_len = pkt_seg_data_len;
332b88b8af2SZhuobin Huang 			else
333b88b8af2SZhuobin Huang 				pkt_seg->data_len = pkt_seg_data_len + pkt_len % nb_pkt_segs;
334a9de470cSBruce Richardson 		}
335a9de470cSBruce Richardson 		pkt_seg->next = NULL; /* Last segment of packet. */
336a9de470cSBruce Richardson 
337a9de470cSBruce Richardson 		/*
338a9de470cSBruce Richardson 		 * Copy headers in first packet segment(s).
339a9de470cSBruce Richardson 		 */
340a9de470cSBruce Richardson 		if (vlan_enabled)
3416d13ea8eSOlivier Matz 			eth_hdr_size = sizeof(struct rte_ether_hdr) +
3426d13ea8eSOlivier Matz 				sizeof(struct rte_vlan_hdr);
343a9de470cSBruce Richardson 		else
3446d13ea8eSOlivier Matz 			eth_hdr_size = sizeof(struct rte_ether_hdr);
345a9de470cSBruce Richardson 
346a9de470cSBruce Richardson 		copy_buf_to_pkt(eth_hdr, eth_hdr_size, pkt, 0);
347a9de470cSBruce Richardson 
348a9de470cSBruce Richardson 		if (ipv4) {
349a7c528e5SOlivier Matz 			copy_buf_to_pkt(ip_hdr, sizeof(struct rte_ipv4_hdr),
350a7c528e5SOlivier Matz 					pkt, eth_hdr_size);
351a9de470cSBruce Richardson 			switch (proto) {
352a9de470cSBruce Richardson 			case IPPROTO_UDP:
353a9de470cSBruce Richardson 				copy_buf_to_pkt(proto_hdr,
354e73e3547SOlivier Matz 					sizeof(struct rte_udp_hdr), pkt,
355a7c528e5SOlivier Matz 					eth_hdr_size +
356a7c528e5SOlivier Matz 						sizeof(struct rte_ipv4_hdr));
357a9de470cSBruce Richardson 				break;
358a9de470cSBruce Richardson 			case IPPROTO_TCP:
359a9de470cSBruce Richardson 				copy_buf_to_pkt(proto_hdr,
360f41b5156SOlivier Matz 					sizeof(struct rte_tcp_hdr), pkt,
361a7c528e5SOlivier Matz 					eth_hdr_size +
362a7c528e5SOlivier Matz 						sizeof(struct rte_ipv4_hdr));
363a9de470cSBruce Richardson 				break;
364a9de470cSBruce Richardson 			case IPPROTO_SCTP:
365a9de470cSBruce Richardson 				copy_buf_to_pkt(proto_hdr,
36609d9ae1aSOlivier Matz 					sizeof(struct rte_sctp_hdr), pkt,
367a7c528e5SOlivier Matz 					eth_hdr_size +
368a7c528e5SOlivier Matz 						sizeof(struct rte_ipv4_hdr));
369a9de470cSBruce Richardson 				break;
370a9de470cSBruce Richardson 			default:
371a9de470cSBruce Richardson 				break;
372a9de470cSBruce Richardson 			}
373a9de470cSBruce Richardson 		} else {
374a7c528e5SOlivier Matz 			copy_buf_to_pkt(ip_hdr, sizeof(struct rte_ipv6_hdr),
375a7c528e5SOlivier Matz 					pkt, eth_hdr_size);
376a9de470cSBruce Richardson 			switch (proto) {
377a9de470cSBruce Richardson 			case IPPROTO_UDP:
378a9de470cSBruce Richardson 				copy_buf_to_pkt(proto_hdr,
379e73e3547SOlivier Matz 					sizeof(struct rte_udp_hdr), pkt,
380a7c528e5SOlivier Matz 					eth_hdr_size +
381a7c528e5SOlivier Matz 						sizeof(struct rte_ipv6_hdr));
382a9de470cSBruce Richardson 				break;
383a9de470cSBruce Richardson 			case IPPROTO_TCP:
384a9de470cSBruce Richardson 				copy_buf_to_pkt(proto_hdr,
385f41b5156SOlivier Matz 					sizeof(struct rte_tcp_hdr), pkt,
386a7c528e5SOlivier Matz 					eth_hdr_size +
387a7c528e5SOlivier Matz 						sizeof(struct rte_ipv6_hdr));
388a9de470cSBruce Richardson 				break;
389a9de470cSBruce Richardson 			case IPPROTO_SCTP:
390a9de470cSBruce Richardson 				copy_buf_to_pkt(proto_hdr,
39109d9ae1aSOlivier Matz 					sizeof(struct rte_sctp_hdr), pkt,
392a7c528e5SOlivier Matz 					eth_hdr_size +
393a7c528e5SOlivier Matz 						sizeof(struct rte_ipv6_hdr));
394a9de470cSBruce Richardson 				break;
395a9de470cSBruce Richardson 			default:
396a9de470cSBruce Richardson 				break;
397a9de470cSBruce Richardson 			}
398a9de470cSBruce Richardson 		}
399a9de470cSBruce Richardson 
400a9de470cSBruce Richardson 		/*
401a9de470cSBruce Richardson 		 * Complete first mbuf of packet and append it to the
402a9de470cSBruce Richardson 		 * burst of packets to be transmitted.
403a9de470cSBruce Richardson 		 */
404a9de470cSBruce Richardson 		pkt->nb_segs = nb_pkt_segs;
405a9de470cSBruce Richardson 		pkt->pkt_len = pkt_len;
406a9de470cSBruce Richardson 		pkt->l2_len = eth_hdr_size;
407a9de470cSBruce Richardson 
408a9de470cSBruce Richardson 		if (ipv4) {
4090c9da755SDavid Marchand 			pkt->vlan_tci  = RTE_ETHER_TYPE_IPV4;
410a7c528e5SOlivier Matz 			pkt->l3_len = sizeof(struct rte_ipv4_hdr);
411a9de470cSBruce Richardson 		} else {
4120c9da755SDavid Marchand 			pkt->vlan_tci  = RTE_ETHER_TYPE_IPV6;
413a7c528e5SOlivier Matz 			pkt->l3_len = sizeof(struct rte_ipv6_hdr);
414a9de470cSBruce Richardson 		}
415a9de470cSBruce Richardson 
416a9de470cSBruce Richardson 		pkts_burst[nb_pkt] = pkt;
417a9de470cSBruce Richardson 	}
418a9de470cSBruce Richardson 
419a9de470cSBruce Richardson 	return nb_pkt;
420a9de470cSBruce Richardson }
421