1// SPDX-License-Identifier: GPL-2.0
2/*
3 * This testsuite provides conformance testing for GRO coalescing.
4 *
5 * Test cases:
6 * 1.data
7 *  Data packets of the same size and same header setup with correct
8 *  sequence numbers coalesce. The one exception being the last data
9 *  packet coalesced: it can be smaller than the rest and coalesced
10 *  as long as it is in the same flow.
11 * 2.ack
12 *  Pure ACK does not coalesce.
13 * 3.flags
14 *  Specific test cases: no packets with PSH, SYN, URG, RST set will
15 *  be coalesced.
16 * 4.tcp
17 *  Packets with incorrect checksum, non-consecutive seqno and
18 *  different TCP header options shouldn't coalesce. Nit: given that
19 *  some extension headers have paddings, such as timestamp, headers
20 *  that are padding differently would not be coalesced.
21 * 5.ip:
22 *  Packets with different (ECN, TTL, TOS) header, ip options or
23 *  ip fragments (ipv6) shouldn't coalesce.
24 * 6.large:
25 *  Packets larger than GRO_MAX_SIZE packets shouldn't coalesce.
26 *
27 * MSS is defined as 4096 - header because if it is too small
28 * (i.e. 1500 MTU - header), it will result in many packets,
29 * increasing the "large" test case's flakiness. This is because
30 * due to time sensitivity in the coalescing window, the receiver
31 * may not coalesce all of the packets.
32 *
33 * Note the timing issue applies to all of the test cases, so some
34 * flakiness is to be expected.
35 *
36 */
37
38#define _GNU_SOURCE
39
40#include <arpa/inet.h>
41#include <errno.h>
42#include <error.h>
43#include <getopt.h>
44#include <linux/filter.h>
45#include <linux/if_packet.h>
46#include <linux/ipv6.h>
47#include <net/ethernet.h>
48#include <net/if.h>
49#include <netinet/in.h>
50#include <netinet/ip.h>
51#include <netinet/ip6.h>
52#include <netinet/tcp.h>
53#include <stdbool.h>
54#include <stddef.h>
55#include <stdio.h>
56#include <stdarg.h>
57#include <string.h>
58#include <unistd.h>
59
60#include "../kselftest.h"
61
62#define DPORT 8000
63#define SPORT 1500
64#define PAYLOAD_LEN 100
65#define NUM_PACKETS 4
66#define START_SEQ 100
67#define START_ACK 100
68#define ETH_P_NONE 0
69#define TOTAL_HDR_LEN (ETH_HLEN + sizeof(struct ipv6hdr) + sizeof(struct tcphdr))
70#define MSS (4096 - sizeof(struct tcphdr) - sizeof(struct ipv6hdr))
71#define MAX_PAYLOAD (IP_MAXPACKET - sizeof(struct tcphdr) - sizeof(struct ipv6hdr))
72#define NUM_LARGE_PKT (MAX_PAYLOAD / MSS)
73#define MAX_HDR_LEN (ETH_HLEN + sizeof(struct ipv6hdr) + sizeof(struct tcphdr))
74#define MIN_EXTHDR_SIZE 8
75#define EXT_PAYLOAD_1 "\x00\x00\x00\x00\x00\x00"
76#define EXT_PAYLOAD_2 "\x11\x11\x11\x11\x11\x11"
77
78#define ipv6_optlen(p)  (((p)->hdrlen+1) << 3) /* calculate IPv6 extension header len */
79#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
80
81static const char *addr6_src = "fdaa::2";
82static const char *addr6_dst = "fdaa::1";
83static const char *addr4_src = "192.168.1.200";
84static const char *addr4_dst = "192.168.1.100";
85static int proto = -1;
86static uint8_t src_mac[ETH_ALEN], dst_mac[ETH_ALEN];
87static char *testname = "data";
88static char *ifname = "eth0";
89static char *smac = "aa:00:00:00:00:02";
90static char *dmac = "aa:00:00:00:00:01";
91static bool verbose;
92static bool tx_socket = true;
93static int tcp_offset = -1;
94static int total_hdr_len = -1;
95static int ethhdr_proto = -1;
96
97static void vlog(const char *fmt, ...)
98{
99	va_list args;
100
101	if (verbose) {
102		va_start(args, fmt);
103		vfprintf(stderr, fmt, args);
104		va_end(args);
105	}
106}
107
108static void setup_sock_filter(int fd)
109{
110	const int dport_off = tcp_offset + offsetof(struct tcphdr, dest);
111	const int ethproto_off = offsetof(struct ethhdr, h_proto);
112	int optlen = 0;
113	int ipproto_off, opt_ipproto_off;
114	int next_off;
115
116	if (proto == PF_INET)
117		next_off = offsetof(struct iphdr, protocol);
118	else
119		next_off = offsetof(struct ipv6hdr, nexthdr);
120	ipproto_off = ETH_HLEN + next_off;
121
122	if (strcmp(testname, "ip") == 0) {
123		if (proto == PF_INET)
124			optlen = sizeof(struct ip_timestamp);
125		else {
126			BUILD_BUG_ON(sizeof(struct ip6_hbh) > MIN_EXTHDR_SIZE);
127			BUILD_BUG_ON(sizeof(struct ip6_dest) > MIN_EXTHDR_SIZE);
128			BUILD_BUG_ON(sizeof(struct ip6_frag) > MIN_EXTHDR_SIZE);
129
130			/* same size for HBH and Fragment extension header types */
131			optlen = MIN_EXTHDR_SIZE;
132			opt_ipproto_off = ETH_HLEN + sizeof(struct ipv6hdr)
133				+ offsetof(struct ip6_ext, ip6e_nxt);
134		}
135	}
136
137	/* this filter validates the following:
138	 *	- packet is IPv4/IPv6 according to the running test.
139	 *	- packet is TCP. Also handles the case of one extension header and then TCP.
140	 *	- checks the packet tcp dport equals to DPORT. Also handles the case of one
141	 *	  extension header and then TCP.
142	 */
143	struct sock_filter filter[] = {
144			BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, ethproto_off),
145			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ntohs(ethhdr_proto), 0, 9),
146			BPF_STMT(BPF_LD  + BPF_B   + BPF_ABS, ipproto_off),
147			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_TCP, 2, 0),
148			BPF_STMT(BPF_LD  + BPF_B   + BPF_ABS, opt_ipproto_off),
149			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_TCP, 0, 5),
150			BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, dport_off),
151			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DPORT, 2, 0),
152			BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, dport_off + optlen),
153			BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DPORT, 0, 1),
154			BPF_STMT(BPF_RET + BPF_K, 0xFFFFFFFF),
155			BPF_STMT(BPF_RET + BPF_K, 0),
156	};
157
158	struct sock_fprog bpf = {
159		.len = ARRAY_SIZE(filter),
160		.filter = filter,
161	};
162
163	if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)) < 0)
164		error(1, errno, "error setting filter");
165}
166
167static uint32_t checksum_nofold(void *data, size_t len, uint32_t sum)
168{
169	uint16_t *words = data;
170	int i;
171
172	for (i = 0; i < len / 2; i++)
173		sum += words[i];
174	if (len & 1)
175		sum += ((char *)data)[len - 1];
176	return sum;
177}
178
179static uint16_t checksum_fold(void *data, size_t len, uint32_t sum)
180{
181	sum = checksum_nofold(data, len, sum);
182	while (sum > 0xFFFF)
183		sum = (sum & 0xFFFF) + (sum >> 16);
184	return ~sum;
185}
186
187static uint16_t tcp_checksum(void *buf, int payload_len)
188{
189	struct pseudo_header6 {
190		struct in6_addr saddr;
191		struct in6_addr daddr;
192		uint16_t protocol;
193		uint16_t payload_len;
194	} ph6;
195	struct pseudo_header4 {
196		struct in_addr saddr;
197		struct in_addr daddr;
198		uint16_t protocol;
199		uint16_t payload_len;
200	} ph4;
201	uint32_t sum = 0;
202
203	if (proto == PF_INET6) {
204		if (inet_pton(AF_INET6, addr6_src, &ph6.saddr) != 1)
205			error(1, errno, "inet_pton6 source ip pseudo");
206		if (inet_pton(AF_INET6, addr6_dst, &ph6.daddr) != 1)
207			error(1, errno, "inet_pton6 dest ip pseudo");
208		ph6.protocol = htons(IPPROTO_TCP);
209		ph6.payload_len = htons(sizeof(struct tcphdr) + payload_len);
210
211		sum = checksum_nofold(&ph6, sizeof(ph6), 0);
212	} else if (proto == PF_INET) {
213		if (inet_pton(AF_INET, addr4_src, &ph4.saddr) != 1)
214			error(1, errno, "inet_pton source ip pseudo");
215		if (inet_pton(AF_INET, addr4_dst, &ph4.daddr) != 1)
216			error(1, errno, "inet_pton dest ip pseudo");
217		ph4.protocol = htons(IPPROTO_TCP);
218		ph4.payload_len = htons(sizeof(struct tcphdr) + payload_len);
219
220		sum = checksum_nofold(&ph4, sizeof(ph4), 0);
221	}
222
223	return checksum_fold(buf, sizeof(struct tcphdr) + payload_len, sum);
224}
225
226static void read_MAC(uint8_t *mac_addr, char *mac)
227{
228	if (sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
229		   &mac_addr[0], &mac_addr[1], &mac_addr[2],
230		   &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6)
231		error(1, 0, "sscanf");
232}
233
234static void fill_datalinklayer(void *buf)
235{
236	struct ethhdr *eth = buf;
237
238	memcpy(eth->h_dest, dst_mac, ETH_ALEN);
239	memcpy(eth->h_source, src_mac, ETH_ALEN);
240	eth->h_proto = ethhdr_proto;
241}
242
243static void fill_networklayer(void *buf, int payload_len)
244{
245	struct ipv6hdr *ip6h = buf;
246	struct iphdr *iph = buf;
247
248	if (proto == PF_INET6) {
249		memset(ip6h, 0, sizeof(*ip6h));
250
251		ip6h->version = 6;
252		ip6h->payload_len = htons(sizeof(struct tcphdr) + payload_len);
253		ip6h->nexthdr = IPPROTO_TCP;
254		ip6h->hop_limit = 8;
255		if (inet_pton(AF_INET6, addr6_src, &ip6h->saddr) != 1)
256			error(1, errno, "inet_pton source ip6");
257		if (inet_pton(AF_INET6, addr6_dst, &ip6h->daddr) != 1)
258			error(1, errno, "inet_pton dest ip6");
259	} else if (proto == PF_INET) {
260		memset(iph, 0, sizeof(*iph));
261
262		iph->version = 4;
263		iph->ihl = 5;
264		iph->ttl = 8;
265		iph->protocol	= IPPROTO_TCP;
266		iph->tot_len = htons(sizeof(struct tcphdr) +
267				payload_len + sizeof(struct iphdr));
268		iph->frag_off = htons(0x4000); /* DF = 1, MF = 0 */
269		if (inet_pton(AF_INET, addr4_src, &iph->saddr) != 1)
270			error(1, errno, "inet_pton source ip");
271		if (inet_pton(AF_INET, addr4_dst, &iph->daddr) != 1)
272			error(1, errno, "inet_pton dest ip");
273		iph->check = checksum_fold(buf, sizeof(struct iphdr), 0);
274	}
275}
276
277static void fill_transportlayer(void *buf, int seq_offset, int ack_offset,
278				int payload_len, int fin)
279{
280	struct tcphdr *tcph = buf;
281
282	memset(tcph, 0, sizeof(*tcph));
283
284	tcph->source = htons(SPORT);
285	tcph->dest = htons(DPORT);
286	tcph->seq = ntohl(START_SEQ + seq_offset);
287	tcph->ack_seq = ntohl(START_ACK + ack_offset);
288	tcph->ack = 1;
289	tcph->fin = fin;
290	tcph->doff = 5;
291	tcph->window = htons(TCP_MAXWIN);
292	tcph->urg_ptr = 0;
293	tcph->check = tcp_checksum(tcph, payload_len);
294}
295
296static void write_packet(int fd, char *buf, int len, struct sockaddr_ll *daddr)
297{
298	int ret = -1;
299
300	ret = sendto(fd, buf, len, 0, (struct sockaddr *)daddr, sizeof(*daddr));
301	if (ret == -1)
302		error(1, errno, "sendto failure");
303	if (ret != len)
304		error(1, errno, "sendto wrong length");
305}
306
307static void create_packet(void *buf, int seq_offset, int ack_offset,
308			  int payload_len, int fin)
309{
310	memset(buf, 0, total_hdr_len);
311	memset(buf + total_hdr_len, 'a', payload_len);
312	fill_transportlayer(buf + tcp_offset, seq_offset, ack_offset,
313			    payload_len, fin);
314	fill_networklayer(buf + ETH_HLEN, payload_len);
315	fill_datalinklayer(buf);
316}
317
318/* send one extra flag, not first and not last pkt */
319static void send_flags(int fd, struct sockaddr_ll *daddr, int psh, int syn,
320		       int rst, int urg)
321{
322	static char flag_buf[MAX_HDR_LEN + PAYLOAD_LEN];
323	static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
324	int payload_len, pkt_size, flag, i;
325	struct tcphdr *tcph;
326
327	payload_len = PAYLOAD_LEN * psh;
328	pkt_size = total_hdr_len + payload_len;
329	flag = NUM_PACKETS / 2;
330
331	create_packet(flag_buf, flag * payload_len, 0, payload_len, 0);
332
333	tcph = (struct tcphdr *)(flag_buf + tcp_offset);
334	tcph->psh = psh;
335	tcph->syn = syn;
336	tcph->rst = rst;
337	tcph->urg = urg;
338	tcph->check = 0;
339	tcph->check = tcp_checksum(tcph, payload_len);
340
341	for (i = 0; i < NUM_PACKETS + 1; i++) {
342		if (i == flag) {
343			write_packet(fd, flag_buf, pkt_size, daddr);
344			continue;
345		}
346		create_packet(buf, i * PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
347		write_packet(fd, buf, total_hdr_len + PAYLOAD_LEN, daddr);
348	}
349}
350
351/* Test for data of same length, smaller than previous
352 * and of different lengths
353 */
354static void send_data_pkts(int fd, struct sockaddr_ll *daddr,
355			   int payload_len1, int payload_len2)
356{
357	static char buf[ETH_HLEN + IP_MAXPACKET];
358
359	create_packet(buf, 0, 0, payload_len1, 0);
360	write_packet(fd, buf, total_hdr_len + payload_len1, daddr);
361	create_packet(buf, payload_len1, 0, payload_len2, 0);
362	write_packet(fd, buf, total_hdr_len + payload_len2, daddr);
363}
364
365/* If incoming segments make tracked segment length exceed
366 * legal IP datagram length, do not coalesce
367 */
368static void send_large(int fd, struct sockaddr_ll *daddr, int remainder)
369{
370	static char pkts[NUM_LARGE_PKT][TOTAL_HDR_LEN + MSS];
371	static char last[TOTAL_HDR_LEN + MSS];
372	static char new_seg[TOTAL_HDR_LEN + MSS];
373	int i;
374
375	for (i = 0; i < NUM_LARGE_PKT; i++)
376		create_packet(pkts[i], i * MSS, 0, MSS, 0);
377	create_packet(last, NUM_LARGE_PKT * MSS, 0, remainder, 0);
378	create_packet(new_seg, (NUM_LARGE_PKT + 1) * MSS, 0, remainder, 0);
379
380	for (i = 0; i < NUM_LARGE_PKT; i++)
381		write_packet(fd, pkts[i], total_hdr_len + MSS, daddr);
382	write_packet(fd, last, total_hdr_len + remainder, daddr);
383	write_packet(fd, new_seg, total_hdr_len + remainder, daddr);
384}
385
386/* Pure acks and dup acks don't coalesce */
387static void send_ack(int fd, struct sockaddr_ll *daddr)
388{
389	static char buf[MAX_HDR_LEN];
390
391	create_packet(buf, 0, 0, 0, 0);
392	write_packet(fd, buf, total_hdr_len, daddr);
393	write_packet(fd, buf, total_hdr_len, daddr);
394	create_packet(buf, 0, 1, 0, 0);
395	write_packet(fd, buf, total_hdr_len, daddr);
396}
397
398static void recompute_packet(char *buf, char *no_ext, int extlen)
399{
400	struct tcphdr *tcphdr = (struct tcphdr *)(buf + tcp_offset);
401	struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN);
402	struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
403
404	memmove(buf, no_ext, total_hdr_len);
405	memmove(buf + total_hdr_len + extlen,
406		no_ext + total_hdr_len, PAYLOAD_LEN);
407
408	tcphdr->doff = tcphdr->doff + (extlen / 4);
409	tcphdr->check = 0;
410	tcphdr->check = tcp_checksum(tcphdr, PAYLOAD_LEN + extlen);
411	if (proto == PF_INET) {
412		iph->tot_len = htons(ntohs(iph->tot_len) + extlen);
413		iph->check = 0;
414		iph->check = checksum_fold(iph, sizeof(struct iphdr), 0);
415	} else {
416		ip6h->payload_len = htons(ntohs(ip6h->payload_len) + extlen);
417	}
418}
419
420static void tcp_write_options(char *buf, int kind, int ts)
421{
422	struct tcp_option_ts {
423		uint8_t kind;
424		uint8_t len;
425		uint32_t tsval;
426		uint32_t tsecr;
427	} *opt_ts = (void *)buf;
428	struct tcp_option_window {
429		uint8_t kind;
430		uint8_t len;
431		uint8_t shift;
432	} *opt_window = (void *)buf;
433
434	switch (kind) {
435	case TCPOPT_NOP:
436		buf[0] = TCPOPT_NOP;
437		break;
438	case TCPOPT_WINDOW:
439		memset(opt_window, 0, sizeof(struct tcp_option_window));
440		opt_window->kind = TCPOPT_WINDOW;
441		opt_window->len = TCPOLEN_WINDOW;
442		opt_window->shift = 0;
443		break;
444	case TCPOPT_TIMESTAMP:
445		memset(opt_ts, 0, sizeof(struct tcp_option_ts));
446		opt_ts->kind = TCPOPT_TIMESTAMP;
447		opt_ts->len = TCPOLEN_TIMESTAMP;
448		opt_ts->tsval = ts;
449		opt_ts->tsecr = 0;
450		break;
451	default:
452		error(1, 0, "unimplemented TCP option");
453		break;
454	}
455}
456
457/* TCP with options is always a permutation of {TS, NOP, NOP}.
458 * Implement different orders to verify coalescing stops.
459 */
460static void add_standard_tcp_options(char *buf, char *no_ext, int ts, int order)
461{
462	switch (order) {
463	case 0:
464		tcp_write_options(buf + total_hdr_len, TCPOPT_NOP, 0);
465		tcp_write_options(buf + total_hdr_len + 1, TCPOPT_NOP, 0);
466		tcp_write_options(buf + total_hdr_len + 2 /* two NOP opts */,
467				  TCPOPT_TIMESTAMP, ts);
468		break;
469	case 1:
470		tcp_write_options(buf + total_hdr_len, TCPOPT_NOP, 0);
471		tcp_write_options(buf + total_hdr_len + 1,
472				  TCPOPT_TIMESTAMP, ts);
473		tcp_write_options(buf + total_hdr_len + 1 + TCPOLEN_TIMESTAMP,
474				  TCPOPT_NOP, 0);
475		break;
476	case 2:
477		tcp_write_options(buf + total_hdr_len, TCPOPT_TIMESTAMP, ts);
478		tcp_write_options(buf + total_hdr_len + TCPOLEN_TIMESTAMP + 1,
479				  TCPOPT_NOP, 0);
480		tcp_write_options(buf + total_hdr_len + TCPOLEN_TIMESTAMP + 2,
481				  TCPOPT_NOP, 0);
482		break;
483	default:
484		error(1, 0, "unknown order");
485		break;
486	}
487	recompute_packet(buf, no_ext, TCPOLEN_TSTAMP_APPA);
488}
489
490/* Packets with invalid checksum don't coalesce. */
491static void send_changed_checksum(int fd, struct sockaddr_ll *daddr)
492{
493	static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
494	struct tcphdr *tcph = (struct tcphdr *)(buf + tcp_offset);
495	int pkt_size = total_hdr_len + PAYLOAD_LEN;
496
497	create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
498	write_packet(fd, buf, pkt_size, daddr);
499
500	create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
501	tcph->check = tcph->check - 1;
502	write_packet(fd, buf, pkt_size, daddr);
503}
504
505 /* Packets with non-consecutive sequence number don't coalesce.*/
506static void send_changed_seq(int fd, struct sockaddr_ll *daddr)
507{
508	static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
509	struct tcphdr *tcph = (struct tcphdr *)(buf + tcp_offset);
510	int pkt_size = total_hdr_len + PAYLOAD_LEN;
511
512	create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
513	write_packet(fd, buf, pkt_size, daddr);
514
515	create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
516	tcph->seq = ntohl(htonl(tcph->seq) + 1);
517	tcph->check = 0;
518	tcph->check = tcp_checksum(tcph, PAYLOAD_LEN);
519	write_packet(fd, buf, pkt_size, daddr);
520}
521
522 /* Packet with different timestamp option or different timestamps
523  * don't coalesce.
524  */
525static void send_changed_ts(int fd, struct sockaddr_ll *daddr)
526{
527	static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
528	static char extpkt[sizeof(buf) + TCPOLEN_TSTAMP_APPA];
529	int pkt_size = total_hdr_len + PAYLOAD_LEN + TCPOLEN_TSTAMP_APPA;
530
531	create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
532	add_standard_tcp_options(extpkt, buf, 0, 0);
533	write_packet(fd, extpkt, pkt_size, daddr);
534
535	create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
536	add_standard_tcp_options(extpkt, buf, 0, 0);
537	write_packet(fd, extpkt, pkt_size, daddr);
538
539	create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0);
540	add_standard_tcp_options(extpkt, buf, 100, 0);
541	write_packet(fd, extpkt, pkt_size, daddr);
542
543	create_packet(buf, PAYLOAD_LEN * 3, 0, PAYLOAD_LEN, 0);
544	add_standard_tcp_options(extpkt, buf, 100, 1);
545	write_packet(fd, extpkt, pkt_size, daddr);
546
547	create_packet(buf, PAYLOAD_LEN * 4, 0, PAYLOAD_LEN, 0);
548	add_standard_tcp_options(extpkt, buf, 100, 2);
549	write_packet(fd, extpkt, pkt_size, daddr);
550}
551
552/* Packet with different tcp options don't coalesce. */
553static void send_diff_opt(int fd, struct sockaddr_ll *daddr)
554{
555	static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
556	static char extpkt1[sizeof(buf) + TCPOLEN_TSTAMP_APPA];
557	static char extpkt2[sizeof(buf) + TCPOLEN_MAXSEG];
558	int extpkt1_size = total_hdr_len + PAYLOAD_LEN + TCPOLEN_TSTAMP_APPA;
559	int extpkt2_size = total_hdr_len + PAYLOAD_LEN + TCPOLEN_MAXSEG;
560
561	create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
562	add_standard_tcp_options(extpkt1, buf, 0, 0);
563	write_packet(fd, extpkt1, extpkt1_size, daddr);
564
565	create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
566	add_standard_tcp_options(extpkt1, buf, 0, 0);
567	write_packet(fd, extpkt1, extpkt1_size, daddr);
568
569	create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0);
570	tcp_write_options(extpkt2 + MAX_HDR_LEN, TCPOPT_NOP, 0);
571	tcp_write_options(extpkt2 + MAX_HDR_LEN + 1, TCPOPT_WINDOW, 0);
572	recompute_packet(extpkt2, buf, TCPOLEN_WINDOW + 1);
573	write_packet(fd, extpkt2, extpkt2_size, daddr);
574}
575
576static void add_ipv4_ts_option(void *buf, void *optpkt)
577{
578	struct ip_timestamp *ts = (struct ip_timestamp *)(optpkt + tcp_offset);
579	int optlen = sizeof(struct ip_timestamp);
580	struct iphdr *iph;
581
582	if (optlen % 4)
583		error(1, 0, "ipv4 timestamp length is not a multiple of 4B");
584
585	ts->ipt_code = IPOPT_TS;
586	ts->ipt_len = optlen;
587	ts->ipt_ptr = 5;
588	ts->ipt_flg = IPOPT_TS_TSONLY;
589
590	memcpy(optpkt, buf, tcp_offset);
591	memcpy(optpkt + tcp_offset + optlen, buf + tcp_offset,
592	       sizeof(struct tcphdr) + PAYLOAD_LEN);
593
594	iph = (struct iphdr *)(optpkt + ETH_HLEN);
595	iph->ihl = 5 + (optlen / 4);
596	iph->tot_len = htons(ntohs(iph->tot_len) + optlen);
597	iph->check = 0;
598	iph->check = checksum_fold(iph, sizeof(struct iphdr) + optlen, 0);
599}
600
601static void add_ipv6_exthdr(void *buf, void *optpkt, __u8 exthdr_type, char *ext_payload)
602{
603	struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr *)(optpkt + tcp_offset);
604	struct ipv6hdr *iph = (struct ipv6hdr *)(optpkt + ETH_HLEN);
605	char *exthdr_payload_start = (char *)(exthdr + 1);
606
607	exthdr->hdrlen = 0;
608	exthdr->nexthdr = IPPROTO_TCP;
609
610	memcpy(exthdr_payload_start, ext_payload, MIN_EXTHDR_SIZE - sizeof(*exthdr));
611
612	memcpy(optpkt, buf, tcp_offset);
613	memcpy(optpkt + tcp_offset + MIN_EXTHDR_SIZE, buf + tcp_offset,
614		sizeof(struct tcphdr) + PAYLOAD_LEN);
615
616	iph->nexthdr = exthdr_type;
617	iph->payload_len = htons(ntohs(iph->payload_len) + MIN_EXTHDR_SIZE);
618}
619
620static void send_ipv6_exthdr(int fd, struct sockaddr_ll *daddr, char *ext_data1, char *ext_data2)
621{
622	static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
623	static char exthdr_pck[sizeof(buf) + MIN_EXTHDR_SIZE];
624
625	create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
626	add_ipv6_exthdr(buf, exthdr_pck, IPPROTO_HOPOPTS, ext_data1);
627	write_packet(fd, exthdr_pck, total_hdr_len + PAYLOAD_LEN + MIN_EXTHDR_SIZE, daddr);
628
629	create_packet(buf, PAYLOAD_LEN * 1, 0, PAYLOAD_LEN, 0);
630	add_ipv6_exthdr(buf, exthdr_pck, IPPROTO_HOPOPTS, ext_data2);
631	write_packet(fd, exthdr_pck, total_hdr_len + PAYLOAD_LEN + MIN_EXTHDR_SIZE, daddr);
632}
633
634/* IPv4 options shouldn't coalesce */
635static void send_ip_options(int fd, struct sockaddr_ll *daddr)
636{
637	static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
638	static char optpkt[sizeof(buf) + sizeof(struct ip_timestamp)];
639	int optlen = sizeof(struct ip_timestamp);
640	int pkt_size = total_hdr_len + PAYLOAD_LEN + optlen;
641
642	create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
643	write_packet(fd, buf, total_hdr_len + PAYLOAD_LEN, daddr);
644
645	create_packet(buf, PAYLOAD_LEN * 1, 0, PAYLOAD_LEN, 0);
646	add_ipv4_ts_option(buf, optpkt);
647	write_packet(fd, optpkt, pkt_size, daddr);
648
649	create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0);
650	write_packet(fd, buf, total_hdr_len + PAYLOAD_LEN, daddr);
651}
652
653/*  IPv4 fragments shouldn't coalesce */
654static void send_fragment4(int fd, struct sockaddr_ll *daddr)
655{
656	static char buf[IP_MAXPACKET];
657	struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
658	int pkt_size = total_hdr_len + PAYLOAD_LEN;
659
660	create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
661	write_packet(fd, buf, pkt_size, daddr);
662
663	/* Once fragmented, packet would retain the total_len.
664	 * Tcp header is prepared as if rest of data is in follow-up frags,
665	 * but follow up frags aren't actually sent.
666	 */
667	memset(buf + total_hdr_len, 'a', PAYLOAD_LEN * 2);
668	fill_transportlayer(buf + tcp_offset, PAYLOAD_LEN, 0, PAYLOAD_LEN * 2, 0);
669	fill_networklayer(buf + ETH_HLEN, PAYLOAD_LEN);
670	fill_datalinklayer(buf);
671
672	iph->frag_off = htons(0x6000); // DF = 1, MF = 1
673	iph->check = 0;
674	iph->check = checksum_fold(iph, sizeof(struct iphdr), 0);
675	write_packet(fd, buf, pkt_size, daddr);
676}
677
678/* IPv4 packets with different ttl don't coalesce.*/
679static void send_changed_ttl(int fd, struct sockaddr_ll *daddr)
680{
681	int pkt_size = total_hdr_len + PAYLOAD_LEN;
682	static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
683	struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
684
685	create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
686	write_packet(fd, buf, pkt_size, daddr);
687
688	create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
689	iph->ttl = 7;
690	iph->check = 0;
691	iph->check = checksum_fold(iph, sizeof(struct iphdr), 0);
692	write_packet(fd, buf, pkt_size, daddr);
693}
694
695/* Packets with different tos don't coalesce.*/
696static void send_changed_tos(int fd, struct sockaddr_ll *daddr)
697{
698	int pkt_size = total_hdr_len + PAYLOAD_LEN;
699	static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
700	struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
701	struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN);
702
703	create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
704	write_packet(fd, buf, pkt_size, daddr);
705
706	create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
707	if (proto == PF_INET) {
708		iph->tos = 1;
709		iph->check = 0;
710		iph->check = checksum_fold(iph, sizeof(struct iphdr), 0);
711	} else if (proto == PF_INET6) {
712		ip6h->priority = 0xf;
713	}
714	write_packet(fd, buf, pkt_size, daddr);
715}
716
717/* Packets with different ECN don't coalesce.*/
718static void send_changed_ECN(int fd, struct sockaddr_ll *daddr)
719{
720	int pkt_size = total_hdr_len + PAYLOAD_LEN;
721	static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
722	struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
723
724	create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
725	write_packet(fd, buf, pkt_size, daddr);
726
727	create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
728	if (proto == PF_INET) {
729		buf[ETH_HLEN + 1] ^= 0x2; // ECN set to 10
730		iph->check = 0;
731		iph->check = checksum_fold(iph, sizeof(struct iphdr), 0);
732	} else {
733		buf[ETH_HLEN + 1] ^= 0x20; // ECN set to 10
734	}
735	write_packet(fd, buf, pkt_size, daddr);
736}
737
738/* IPv6 fragments and packets with extensions don't coalesce.*/
739static void send_fragment6(int fd, struct sockaddr_ll *daddr)
740{
741	static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
742	static char extpkt[MAX_HDR_LEN + PAYLOAD_LEN +
743			   sizeof(struct ip6_frag)];
744	struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN);
745	struct ip6_frag *frag = (void *)(extpkt + tcp_offset);
746	int extlen = sizeof(struct ip6_frag);
747	int bufpkt_len = total_hdr_len + PAYLOAD_LEN;
748	int extpkt_len = bufpkt_len + extlen;
749	int i;
750
751	for (i = 0; i < 2; i++) {
752		create_packet(buf, PAYLOAD_LEN * i, 0, PAYLOAD_LEN, 0);
753		write_packet(fd, buf, bufpkt_len, daddr);
754	}
755	sleep(1);
756	create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0);
757	memset(extpkt, 0, extpkt_len);
758
759	ip6h->nexthdr = IPPROTO_FRAGMENT;
760	ip6h->payload_len = htons(ntohs(ip6h->payload_len) + extlen);
761	frag->ip6f_nxt = IPPROTO_TCP;
762
763	memcpy(extpkt, buf, tcp_offset);
764	memcpy(extpkt + tcp_offset + extlen, buf + tcp_offset,
765	       sizeof(struct tcphdr) + PAYLOAD_LEN);
766	write_packet(fd, extpkt, extpkt_len, daddr);
767
768	create_packet(buf, PAYLOAD_LEN * 3, 0, PAYLOAD_LEN, 0);
769	write_packet(fd, buf, bufpkt_len, daddr);
770}
771
772static void bind_packetsocket(int fd)
773{
774	struct sockaddr_ll daddr = {};
775
776	daddr.sll_family = AF_PACKET;
777	daddr.sll_protocol = ethhdr_proto;
778	daddr.sll_ifindex = if_nametoindex(ifname);
779	if (daddr.sll_ifindex == 0)
780		error(1, errno, "if_nametoindex");
781
782	if (bind(fd, (void *)&daddr, sizeof(daddr)) < 0)
783		error(1, errno, "could not bind socket");
784}
785
786static void set_timeout(int fd)
787{
788	struct timeval timeout;
789
790	timeout.tv_sec = 3;
791	timeout.tv_usec = 0;
792	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
793		       sizeof(timeout)) < 0)
794		error(1, errno, "cannot set timeout, setsockopt failed");
795}
796
797static void check_recv_pkts(int fd, int *correct_payload,
798			    int correct_num_pkts)
799{
800	static char buffer[IP_MAXPACKET + ETH_HLEN + 1];
801	struct iphdr *iph = (struct iphdr *)(buffer + ETH_HLEN);
802	struct ipv6hdr *ip6h = (struct ipv6hdr *)(buffer + ETH_HLEN);
803	struct tcphdr *tcph;
804	bool bad_packet = false;
805	int tcp_ext_len = 0;
806	int ip_ext_len = 0;
807	int pkt_size = -1;
808	int data_len = 0;
809	int num_pkt = 0;
810	int i;
811
812	vlog("Expected {");
813	for (i = 0; i < correct_num_pkts; i++)
814		vlog("%d ", correct_payload[i]);
815	vlog("}, Total %d packets\nReceived {", correct_num_pkts);
816
817	while (1) {
818		ip_ext_len = 0;
819		pkt_size = recv(fd, buffer, IP_MAXPACKET + ETH_HLEN + 1, 0);
820		if (pkt_size < 0)
821			error(1, errno, "could not receive");
822
823		if (iph->version == 4)
824			ip_ext_len = (iph->ihl - 5) * 4;
825		else if (ip6h->version == 6 && ip6h->nexthdr != IPPROTO_TCP)
826			ip_ext_len = MIN_EXTHDR_SIZE;
827
828		tcph = (struct tcphdr *)(buffer + tcp_offset + ip_ext_len);
829
830		if (tcph->fin)
831			break;
832
833		tcp_ext_len = (tcph->doff - 5) * 4;
834		data_len = pkt_size - total_hdr_len - tcp_ext_len - ip_ext_len;
835		/* Min ethernet frame payload is 46(ETH_ZLEN - ETH_HLEN) by RFC 802.3.
836		 * Ipv4/tcp packets without at least 6 bytes of data will be padded.
837		 * Packet sockets are protocol agnostic, and will not trim the padding.
838		 */
839		if (pkt_size == ETH_ZLEN && iph->version == 4) {
840			data_len = ntohs(iph->tot_len)
841				- sizeof(struct tcphdr) - sizeof(struct iphdr);
842		}
843		vlog("%d ", data_len);
844		if (data_len != correct_payload[num_pkt]) {
845			vlog("[!=%d]", correct_payload[num_pkt]);
846			bad_packet = true;
847		}
848		num_pkt++;
849	}
850	vlog("}, Total %d packets.\n", num_pkt);
851	if (num_pkt != correct_num_pkts)
852		error(1, 0, "incorrect number of packets");
853	if (bad_packet)
854		error(1, 0, "incorrect packet geometry");
855
856	printf("Test succeeded\n\n");
857}
858
859static void gro_sender(void)
860{
861	static char fin_pkt[MAX_HDR_LEN];
862	struct sockaddr_ll daddr = {};
863	int txfd = -1;
864
865	txfd = socket(PF_PACKET, SOCK_RAW, IPPROTO_RAW);
866	if (txfd < 0)
867		error(1, errno, "socket creation");
868
869	memset(&daddr, 0, sizeof(daddr));
870	daddr.sll_ifindex = if_nametoindex(ifname);
871	if (daddr.sll_ifindex == 0)
872		error(1, errno, "if_nametoindex");
873	daddr.sll_family = AF_PACKET;
874	memcpy(daddr.sll_addr, dst_mac, ETH_ALEN);
875	daddr.sll_halen = ETH_ALEN;
876	create_packet(fin_pkt, PAYLOAD_LEN * 2, 0, 0, 1);
877
878	if (strcmp(testname, "data") == 0) {
879		send_data_pkts(txfd, &daddr, PAYLOAD_LEN, PAYLOAD_LEN);
880		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
881
882		send_data_pkts(txfd, &daddr, PAYLOAD_LEN, PAYLOAD_LEN / 2);
883		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
884
885		send_data_pkts(txfd, &daddr, PAYLOAD_LEN / 2, PAYLOAD_LEN);
886		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
887	} else if (strcmp(testname, "ack") == 0) {
888		send_ack(txfd, &daddr);
889		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
890	} else if (strcmp(testname, "flags") == 0) {
891		send_flags(txfd, &daddr, 1, 0, 0, 0);
892		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
893
894		send_flags(txfd, &daddr, 0, 1, 0, 0);
895		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
896
897		send_flags(txfd, &daddr, 0, 0, 1, 0);
898		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
899
900		send_flags(txfd, &daddr, 0, 0, 0, 1);
901		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
902	} else if (strcmp(testname, "tcp") == 0) {
903		send_changed_checksum(txfd, &daddr);
904		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
905
906		send_changed_seq(txfd, &daddr);
907		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
908
909		send_changed_ts(txfd, &daddr);
910		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
911
912		send_diff_opt(txfd, &daddr);
913		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
914	} else if (strcmp(testname, "ip") == 0) {
915		send_changed_ECN(txfd, &daddr);
916		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
917
918		send_changed_tos(txfd, &daddr);
919		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
920		if (proto == PF_INET) {
921			/* Modified packets may be received out of order.
922			 * Sleep function added to enforce test boundaries
923			 * so that fin pkts are not received prior to other pkts.
924			 */
925			sleep(1);
926			send_changed_ttl(txfd, &daddr);
927			write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
928
929			sleep(1);
930			send_ip_options(txfd, &daddr);
931			sleep(1);
932			write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
933
934			sleep(1);
935			send_fragment4(txfd, &daddr);
936			sleep(1);
937			write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
938		} else if (proto == PF_INET6) {
939			sleep(1);
940			send_fragment6(txfd, &daddr);
941			sleep(1);
942			write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
943
944			sleep(1);
945			/* send IPv6 packets with ext header with same payload */
946			send_ipv6_exthdr(txfd, &daddr, EXT_PAYLOAD_1, EXT_PAYLOAD_1);
947			sleep(1);
948			write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
949
950			sleep(1);
951			/* send IPv6 packets with ext header with different payload */
952			send_ipv6_exthdr(txfd, &daddr, EXT_PAYLOAD_1, EXT_PAYLOAD_2);
953			sleep(1);
954			write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
955		}
956	} else if (strcmp(testname, "large") == 0) {
957		/* 20 is the difference between min iphdr size
958		 * and min ipv6hdr size. Like MAX_HDR_SIZE,
959		 * MAX_PAYLOAD is defined with the larger header of the two.
960		 */
961		int offset = proto == PF_INET ? 20 : 0;
962		int remainder = (MAX_PAYLOAD + offset) % MSS;
963
964		send_large(txfd, &daddr, remainder);
965		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
966
967		send_large(txfd, &daddr, remainder + 1);
968		write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
969	} else {
970		error(1, 0, "Unknown testcase");
971	}
972
973	if (close(txfd))
974		error(1, errno, "socket close");
975}
976
977static void gro_receiver(void)
978{
979	static int correct_payload[NUM_PACKETS];
980	int rxfd = -1;
981
982	rxfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_NONE));
983	if (rxfd < 0)
984		error(1, 0, "socket creation");
985	setup_sock_filter(rxfd);
986	set_timeout(rxfd);
987	bind_packetsocket(rxfd);
988
989	memset(correct_payload, 0, sizeof(correct_payload));
990
991	if (strcmp(testname, "data") == 0) {
992		printf("pure data packet of same size: ");
993		correct_payload[0] = PAYLOAD_LEN * 2;
994		check_recv_pkts(rxfd, correct_payload, 1);
995
996		printf("large data packets followed by a smaller one: ");
997		correct_payload[0] = PAYLOAD_LEN * 1.5;
998		check_recv_pkts(rxfd, correct_payload, 1);
999
1000		printf("small data packets followed by a larger one: ");
1001		correct_payload[0] = PAYLOAD_LEN / 2;
1002		correct_payload[1] = PAYLOAD_LEN;
1003		check_recv_pkts(rxfd, correct_payload, 2);
1004	} else if (strcmp(testname, "ack") == 0) {
1005		printf("duplicate ack and pure ack: ");
1006		check_recv_pkts(rxfd, correct_payload, 3);
1007	} else if (strcmp(testname, "flags") == 0) {
1008		correct_payload[0] = PAYLOAD_LEN * 3;
1009		correct_payload[1] = PAYLOAD_LEN * 2;
1010
1011		printf("psh flag ends coalescing: ");
1012		check_recv_pkts(rxfd, correct_payload, 2);
1013
1014		correct_payload[0] = PAYLOAD_LEN * 2;
1015		correct_payload[1] = 0;
1016		correct_payload[2] = PAYLOAD_LEN * 2;
1017		printf("syn flag ends coalescing: ");
1018		check_recv_pkts(rxfd, correct_payload, 3);
1019
1020		printf("rst flag ends coalescing: ");
1021		check_recv_pkts(rxfd, correct_payload, 3);
1022
1023		printf("urg flag ends coalescing: ");
1024		check_recv_pkts(rxfd, correct_payload, 3);
1025	} else if (strcmp(testname, "tcp") == 0) {
1026		correct_payload[0] = PAYLOAD_LEN;
1027		correct_payload[1] = PAYLOAD_LEN;
1028		correct_payload[2] = PAYLOAD_LEN;
1029		correct_payload[3] = PAYLOAD_LEN;
1030
1031		printf("changed checksum does not coalesce: ");
1032		check_recv_pkts(rxfd, correct_payload, 2);
1033
1034		printf("Wrong Seq number doesn't coalesce: ");
1035		check_recv_pkts(rxfd, correct_payload, 2);
1036
1037		printf("Different timestamp doesn't coalesce: ");
1038		correct_payload[0] = PAYLOAD_LEN * 2;
1039		check_recv_pkts(rxfd, correct_payload, 4);
1040
1041		printf("Different options doesn't coalesce: ");
1042		correct_payload[0] = PAYLOAD_LEN * 2;
1043		check_recv_pkts(rxfd, correct_payload, 2);
1044	} else if (strcmp(testname, "ip") == 0) {
1045		correct_payload[0] = PAYLOAD_LEN;
1046		correct_payload[1] = PAYLOAD_LEN;
1047
1048		printf("different ECN doesn't coalesce: ");
1049		check_recv_pkts(rxfd, correct_payload, 2);
1050
1051		printf("different tos doesn't coalesce: ");
1052		check_recv_pkts(rxfd, correct_payload, 2);
1053
1054		if (proto == PF_INET) {
1055			printf("different ttl doesn't coalesce: ");
1056			check_recv_pkts(rxfd, correct_payload, 2);
1057
1058			printf("ip options doesn't coalesce: ");
1059			correct_payload[2] = PAYLOAD_LEN;
1060			check_recv_pkts(rxfd, correct_payload, 3);
1061
1062			printf("fragmented ip4 doesn't coalesce: ");
1063			check_recv_pkts(rxfd, correct_payload, 2);
1064		} else if (proto == PF_INET6) {
1065			/* GRO doesn't check for ipv6 hop limit when flushing.
1066			 * Hence no corresponding test to the ipv4 case.
1067			 */
1068			printf("fragmented ip6 doesn't coalesce: ");
1069			correct_payload[0] = PAYLOAD_LEN * 2;
1070			correct_payload[1] = PAYLOAD_LEN;
1071			correct_payload[2] = PAYLOAD_LEN;
1072			check_recv_pkts(rxfd, correct_payload, 3);
1073
1074			printf("ipv6 with ext header does coalesce: ");
1075			correct_payload[0] = PAYLOAD_LEN * 2;
1076			check_recv_pkts(rxfd, correct_payload, 1);
1077
1078			printf("ipv6 with ext header with different payloads doesn't coalesce: ");
1079			correct_payload[0] = PAYLOAD_LEN;
1080			correct_payload[1] = PAYLOAD_LEN;
1081			check_recv_pkts(rxfd, correct_payload, 2);
1082		}
1083	} else if (strcmp(testname, "large") == 0) {
1084		int offset = proto == PF_INET ? 20 : 0;
1085		int remainder = (MAX_PAYLOAD + offset) % MSS;
1086
1087		correct_payload[0] = (MAX_PAYLOAD + offset);
1088		correct_payload[1] = remainder;
1089		printf("Shouldn't coalesce if exceed IP max pkt size: ");
1090		check_recv_pkts(rxfd, correct_payload, 2);
1091
1092		/* last segment sent individually, doesn't start new segment */
1093		correct_payload[0] = correct_payload[0] - remainder;
1094		correct_payload[1] = remainder + 1;
1095		correct_payload[2] = remainder + 1;
1096		check_recv_pkts(rxfd, correct_payload, 3);
1097	} else {
1098		error(1, 0, "Test case error, should never trigger");
1099	}
1100
1101	if (close(rxfd))
1102		error(1, 0, "socket close");
1103}
1104
1105static void parse_args(int argc, char **argv)
1106{
1107	static const struct option opts[] = {
1108		{ "daddr", required_argument, NULL, 'd' },
1109		{ "dmac", required_argument, NULL, 'D' },
1110		{ "iface", required_argument, NULL, 'i' },
1111		{ "ipv4", no_argument, NULL, '4' },
1112		{ "ipv6", no_argument, NULL, '6' },
1113		{ "rx", no_argument, NULL, 'r' },
1114		{ "saddr", required_argument, NULL, 's' },
1115		{ "smac", required_argument, NULL, 'S' },
1116		{ "test", required_argument, NULL, 't' },
1117		{ "verbose", no_argument, NULL, 'v' },
1118		{ 0, 0, 0, 0 }
1119	};
1120	int c;
1121
1122	while ((c = getopt_long(argc, argv, "46d:D:i:rs:S:t:v", opts, NULL)) != -1) {
1123		switch (c) {
1124		case '4':
1125			proto = PF_INET;
1126			ethhdr_proto = htons(ETH_P_IP);
1127			break;
1128		case '6':
1129			proto = PF_INET6;
1130			ethhdr_proto = htons(ETH_P_IPV6);
1131			break;
1132		case 'd':
1133			addr4_dst = addr6_dst = optarg;
1134			break;
1135		case 'D':
1136			dmac = optarg;
1137			break;
1138		case 'i':
1139			ifname = optarg;
1140			break;
1141		case 'r':
1142			tx_socket = false;
1143			break;
1144		case 's':
1145			addr4_src = addr6_src = optarg;
1146			break;
1147		case 'S':
1148			smac = optarg;
1149			break;
1150		case 't':
1151			testname = optarg;
1152			break;
1153		case 'v':
1154			verbose = true;
1155			break;
1156		default:
1157			error(1, 0, "%s invalid option %c\n", __func__, c);
1158			break;
1159		}
1160	}
1161}
1162
1163int main(int argc, char **argv)
1164{
1165	parse_args(argc, argv);
1166
1167	if (proto == PF_INET) {
1168		tcp_offset = ETH_HLEN + sizeof(struct iphdr);
1169		total_hdr_len = tcp_offset + sizeof(struct tcphdr);
1170	} else if (proto == PF_INET6) {
1171		tcp_offset = ETH_HLEN + sizeof(struct ipv6hdr);
1172		total_hdr_len = MAX_HDR_LEN;
1173	} else {
1174		error(1, 0, "Protocol family is not ipv4 or ipv6");
1175	}
1176
1177	read_MAC(src_mac, smac);
1178	read_MAC(dst_mac, dmac);
1179
1180	if (tx_socket)
1181		gro_sender();
1182	else
1183		gro_receiver();
1184
1185	fprintf(stderr, "Gro::%s test passed.\n", testname);
1186	return 0;
1187}
1188