Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.10.11.
   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}