1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * This testsuite provides conformance testing for GRO coalescing. 4 * 5 * Test cases: 6 * 7 * data_*: 8 * Data packets of the same size and same header setup with correct 9 * sequence numbers coalesce. The one exception being the last data 10 * packet coalesced: it can be smaller than the rest and coalesced 11 * as long as it is in the same flow. 12 * - data_same: same size packets coalesce 13 * - data_lrg_sml: large then small coalesces 14 * - data_sml_lrg: small then large doesn't coalesce 15 * 16 * ack: 17 * Pure ACK does not coalesce. 18 * 19 * flags_*: 20 * No packets with PSH, SYN, URG, RST, CWR set will be coalesced. 21 * - flags_psh, flags_syn, flags_rst, flags_urg, flags_cwr 22 * 23 * tcp_*: 24 * Packets with incorrect checksum, non-consecutive seqno and 25 * different TCP header options shouldn't coalesce. Nit: given that 26 * some extension headers have paddings, such as timestamp, headers 27 * that are padded differently would not be coalesced. 28 * - tcp_csum: incorrect checksum 29 * - tcp_seq: non-consecutive sequence numbers 30 * - tcp_ts: different timestamps 31 * - tcp_opt: different TCP options 32 * 33 * ip_*: 34 * Packets with different (ECN, TTL, TOS) header, IP options or 35 * IP fragments shouldn't coalesce. 36 * - ip_ecn, ip_tos: shared between IPv4/IPv6 37 * - ip_ttl, ip_opt, ip_frag4: IPv4 only 38 * - ip_id_df*: IPv4 IP ID field coalescing tests 39 * - ip_frag6, ip_v6ext_*: IPv6 only 40 * 41 * large_*: 42 * Packets larger than GRO_MAX_SIZE packets shouldn't coalesce. 43 * - large_max: exceeding max size 44 * - large_rem: remainder handling 45 * 46 * single, capacity: 47 * Boring cases used to test coalescing machinery itself and stats 48 * more than protocol behavior. 49 * 50 * MSS is defined as 4096 - header because if it is too small 51 * (i.e. 1500 MTU - header), it will result in many packets, 52 * increasing the "large" test case's flakiness. This is because 53 * due to time sensitivity in the coalescing window, the receiver 54 * may not coalesce all of the packets. 55 * 56 * Note the timing issue applies to all of the test cases, so some 57 * flakiness is to be expected. 58 * 59 */ 60 61 #define _GNU_SOURCE 62 63 #include <arpa/inet.h> 64 #include <errno.h> 65 #include <error.h> 66 #include <getopt.h> 67 #include <linux/filter.h> 68 #include <linux/if_packet.h> 69 #include <linux/ipv6.h> 70 #include <linux/net_tstamp.h> 71 #include <net/ethernet.h> 72 #include <net/if.h> 73 #include <netinet/in.h> 74 #include <netinet/ip.h> 75 #include <netinet/ip6.h> 76 #include <netinet/tcp.h> 77 #include <stdbool.h> 78 #include <stddef.h> 79 #include <stdio.h> 80 #include <stdarg.h> 81 #include <string.h> 82 #include <time.h> 83 #include <unistd.h> 84 85 #include "kselftest.h" 86 #include "ksft.h" 87 88 #define DPORT 8000 89 #define SPORT 1500 90 #define PAYLOAD_LEN 100 91 #define NUM_PACKETS 4 92 #define START_SEQ 100 93 #define START_ACK 100 94 #define ETH_P_NONE 0 95 #define TOTAL_HDR_LEN (ETH_HLEN + sizeof(struct ipv6hdr) + sizeof(struct tcphdr)) 96 #define MSS (4096 - sizeof(struct tcphdr) - sizeof(struct ipv6hdr)) 97 #define MAX_PAYLOAD (IP_MAXPACKET - sizeof(struct tcphdr) - sizeof(struct ipv6hdr)) 98 #define NUM_LARGE_PKT (MAX_PAYLOAD / MSS) 99 #define MAX_HDR_LEN (ETH_HLEN + sizeof(struct ipv6hdr) + sizeof(struct tcphdr)) 100 #define MIN_EXTHDR_SIZE 8 101 #define EXT_PAYLOAD_1 "\x00\x00\x00\x00\x00\x00" 102 #define EXT_PAYLOAD_2 "\x11\x11\x11\x11\x11\x11" 103 104 #define ipv6_optlen(p) (((p)->hdrlen+1) << 3) /* calculate IPv6 extension header len */ 105 #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) 106 107 enum flush_id_case { 108 FLUSH_ID_DF1_INC, 109 FLUSH_ID_DF1_FIXED, 110 FLUSH_ID_DF0_INC, 111 FLUSH_ID_DF0_FIXED, 112 FLUSH_ID_DF1_INC_FIXED, 113 FLUSH_ID_DF1_FIXED_INC, 114 }; 115 116 static const char *addr6_src = "fdaa::2"; 117 static const char *addr6_dst = "fdaa::1"; 118 static const char *addr4_src = "192.168.1.200"; 119 static const char *addr4_dst = "192.168.1.100"; 120 static int proto = -1; 121 static uint8_t src_mac[ETH_ALEN], dst_mac[ETH_ALEN]; 122 static char *testname = "data"; 123 static char *ifname = "eth0"; 124 static char *smac = "aa:00:00:00:00:02"; 125 static char *dmac = "aa:00:00:00:00:01"; 126 static bool verbose; 127 static bool tx_socket = true; 128 static int tcp_offset = -1; 129 static int total_hdr_len = -1; 130 static int ethhdr_proto = -1; 131 static bool ipip; 132 static uint64_t txtime_ns; 133 static int num_flows = 4; 134 static bool order_check; 135 136 #define CAPACITY_PAYLOAD_LEN 200 137 138 #define TXTIME_DELAY_MS 5 139 140 static void vlog(const char *fmt, ...) 141 { 142 va_list args; 143 144 if (verbose) { 145 va_start(args, fmt); 146 vfprintf(stderr, fmt, args); 147 va_end(args); 148 } 149 } 150 151 static void setup_sock_filter(int fd) 152 { 153 const int dport_off = tcp_offset + offsetof(struct tcphdr, dest); 154 const int ethproto_off = offsetof(struct ethhdr, h_proto); 155 int optlen = 0; 156 int ipproto_off, opt_ipproto_off; 157 int next_off; 158 159 if (ipip) 160 next_off = sizeof(struct iphdr) + offsetof(struct iphdr, protocol); 161 else if (proto == PF_INET) 162 next_off = offsetof(struct iphdr, protocol); 163 else 164 next_off = offsetof(struct ipv6hdr, nexthdr); 165 ipproto_off = ETH_HLEN + next_off; 166 167 /* Overridden later if exthdrs are used: */ 168 opt_ipproto_off = ipproto_off; 169 170 if (strcmp(testname, "ip_opt") == 0) { 171 optlen = sizeof(struct ip_timestamp); 172 } else if (strcmp(testname, "ip_frag6") == 0 || 173 strcmp(testname, "ip_v6ext_same") == 0 || 174 strcmp(testname, "ip_v6ext_diff") == 0) { 175 BUILD_BUG_ON(sizeof(struct ip6_hbh) > MIN_EXTHDR_SIZE); 176 BUILD_BUG_ON(sizeof(struct ip6_dest) > MIN_EXTHDR_SIZE); 177 BUILD_BUG_ON(sizeof(struct ip6_frag) > MIN_EXTHDR_SIZE); 178 179 /* same size for HBH and Fragment extension header types */ 180 optlen = MIN_EXTHDR_SIZE; 181 opt_ipproto_off = ETH_HLEN + sizeof(struct ipv6hdr) 182 + offsetof(struct ip6_ext, ip6e_nxt); 183 } 184 185 /* this filter validates the following: 186 * - packet is IPv4/IPv6 according to the running test. 187 * - packet is TCP. Also handles the case of one extension header and then TCP. 188 * - checks the packet tcp dport equals to DPORT. Also handles the case of one 189 * extension header and then TCP. 190 */ 191 struct sock_filter filter[] = { 192 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ethproto_off), 193 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ntohs(ethhdr_proto), 0, 9), 194 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ipproto_off), 195 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_TCP, 2, 0), 196 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, opt_ipproto_off), 197 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_TCP, 0, 5), 198 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, dport_off), 199 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DPORT, 2, 0), 200 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, dport_off + optlen), 201 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DPORT, 0, 1), 202 BPF_STMT(BPF_RET + BPF_K, 0xFFFFFFFF), 203 BPF_STMT(BPF_RET + BPF_K, 0), 204 }; 205 206 struct sock_fprog bpf = { 207 .len = ARRAY_SIZE(filter), 208 .filter = filter, 209 }; 210 211 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)) < 0) 212 error(1, errno, "error setting filter"); 213 } 214 215 static uint32_t checksum_nofold(void *data, size_t len, uint32_t sum) 216 { 217 uint16_t *words = data; 218 int i; 219 220 for (i = 0; i < len / 2; i++) 221 sum += words[i]; 222 if (len & 1) 223 sum += ((char *)data)[len - 1]; 224 return sum; 225 } 226 227 static uint16_t checksum_fold(void *data, size_t len, uint32_t sum) 228 { 229 sum = checksum_nofold(data, len, sum); 230 while (sum > 0xFFFF) 231 sum = (sum & 0xFFFF) + (sum >> 16); 232 return ~sum; 233 } 234 235 static uint16_t tcp_checksum(void *buf, int payload_len) 236 { 237 struct pseudo_header6 { 238 struct in6_addr saddr; 239 struct in6_addr daddr; 240 uint16_t protocol; 241 uint16_t payload_len; 242 } ph6; 243 struct pseudo_header4 { 244 struct in_addr saddr; 245 struct in_addr daddr; 246 uint16_t protocol; 247 uint16_t payload_len; 248 } ph4; 249 uint32_t sum = 0; 250 251 if (proto == PF_INET6) { 252 if (inet_pton(AF_INET6, addr6_src, &ph6.saddr) != 1) 253 error(1, errno, "inet_pton6 source ip pseudo"); 254 if (inet_pton(AF_INET6, addr6_dst, &ph6.daddr) != 1) 255 error(1, errno, "inet_pton6 dest ip pseudo"); 256 ph6.protocol = htons(IPPROTO_TCP); 257 ph6.payload_len = htons(sizeof(struct tcphdr) + payload_len); 258 259 sum = checksum_nofold(&ph6, sizeof(ph6), 0); 260 } else if (proto == PF_INET) { 261 if (inet_pton(AF_INET, addr4_src, &ph4.saddr) != 1) 262 error(1, errno, "inet_pton source ip pseudo"); 263 if (inet_pton(AF_INET, addr4_dst, &ph4.daddr) != 1) 264 error(1, errno, "inet_pton dest ip pseudo"); 265 ph4.protocol = htons(IPPROTO_TCP); 266 ph4.payload_len = htons(sizeof(struct tcphdr) + payload_len); 267 268 sum = checksum_nofold(&ph4, sizeof(ph4), 0); 269 } 270 271 return checksum_fold(buf, sizeof(struct tcphdr) + payload_len, sum); 272 } 273 274 static void read_MAC(uint8_t *mac_addr, char *mac) 275 { 276 if (sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 277 &mac_addr[0], &mac_addr[1], &mac_addr[2], 278 &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) 279 error(1, 0, "sscanf"); 280 } 281 282 static void fill_datalinklayer(void *buf) 283 { 284 struct ethhdr *eth = buf; 285 286 memcpy(eth->h_dest, dst_mac, ETH_ALEN); 287 memcpy(eth->h_source, src_mac, ETH_ALEN); 288 eth->h_proto = ethhdr_proto; 289 } 290 291 static void fill_networklayer(void *buf, int payload_len, int protocol) 292 { 293 struct ipv6hdr *ip6h = buf; 294 struct iphdr *iph = buf; 295 296 if (proto == PF_INET6) { 297 memset(ip6h, 0, sizeof(*ip6h)); 298 299 ip6h->version = 6; 300 ip6h->payload_len = htons(sizeof(struct tcphdr) + payload_len); 301 ip6h->nexthdr = protocol; 302 ip6h->hop_limit = 8; 303 if (inet_pton(AF_INET6, addr6_src, &ip6h->saddr) != 1) 304 error(1, errno, "inet_pton source ip6"); 305 if (inet_pton(AF_INET6, addr6_dst, &ip6h->daddr) != 1) 306 error(1, errno, "inet_pton dest ip6"); 307 } else if (proto == PF_INET) { 308 memset(iph, 0, sizeof(*iph)); 309 310 iph->version = 4; 311 iph->ihl = 5; 312 iph->ttl = 8; 313 iph->protocol = protocol; 314 iph->tot_len = htons(sizeof(struct tcphdr) + 315 payload_len + sizeof(struct iphdr)); 316 iph->frag_off = htons(0x4000); /* DF = 1, MF = 0 */ 317 if (inet_pton(AF_INET, addr4_src, &iph->saddr) != 1) 318 error(1, errno, "inet_pton source ip"); 319 if (inet_pton(AF_INET, addr4_dst, &iph->daddr) != 1) 320 error(1, errno, "inet_pton dest ip"); 321 iph->check = checksum_fold(buf, sizeof(struct iphdr), 0); 322 } 323 } 324 325 static void fill_transportlayer(void *buf, int seq_offset, int ack_offset, 326 int payload_len, int fin) 327 { 328 struct tcphdr *tcph = buf; 329 330 memset(tcph, 0, sizeof(*tcph)); 331 332 tcph->source = htons(SPORT); 333 tcph->dest = htons(DPORT); 334 tcph->seq = ntohl(START_SEQ + seq_offset); 335 tcph->ack_seq = ntohl(START_ACK + ack_offset); 336 tcph->ack = 1; 337 tcph->fin = fin; 338 tcph->doff = 5; 339 tcph->window = htons(TCP_MAXWIN); 340 tcph->urg_ptr = 0; 341 tcph->check = tcp_checksum(tcph, payload_len); 342 } 343 344 static void write_packet(int fd, char *buf, int len, struct sockaddr_ll *daddr) 345 { 346 char control[CMSG_SPACE(sizeof(uint64_t))]; 347 struct msghdr msg = {}; 348 struct iovec iov = {}; 349 struct cmsghdr *cm; 350 int ret = -1; 351 352 iov.iov_base = buf; 353 iov.iov_len = len; 354 355 msg.msg_iov = &iov; 356 msg.msg_iovlen = 1; 357 msg.msg_name = daddr; 358 msg.msg_namelen = sizeof(*daddr); 359 360 if (txtime_ns) { 361 memset(control, 0, sizeof(control)); 362 msg.msg_control = control; 363 msg.msg_controllen = sizeof(control); 364 365 cm = CMSG_FIRSTHDR(&msg); 366 cm->cmsg_level = SOL_SOCKET; 367 cm->cmsg_type = SCM_TXTIME; 368 cm->cmsg_len = CMSG_LEN(sizeof(uint64_t)); 369 memcpy(CMSG_DATA(cm), &txtime_ns, sizeof(txtime_ns)); 370 } 371 372 ret = sendmsg(fd, &msg, 0); 373 if (ret == -1) 374 error(1, errno, "sendmsg failure"); 375 if (ret != len) 376 error(1, 0, "sendmsg wrong length: %d vs %d", ret, len); 377 } 378 379 static void create_packet(void *buf, int seq_offset, int ack_offset, 380 int payload_len, int fin) 381 { 382 memset(buf, 0, total_hdr_len); 383 memset(buf + total_hdr_len, 'a', payload_len); 384 385 fill_transportlayer(buf + tcp_offset, seq_offset, ack_offset, 386 payload_len, fin); 387 388 if (ipip) { 389 fill_networklayer(buf + ETH_HLEN, payload_len + sizeof(struct iphdr), 390 IPPROTO_IPIP); 391 fill_networklayer(buf + ETH_HLEN + sizeof(struct iphdr), 392 payload_len, IPPROTO_TCP); 393 } else { 394 fill_networklayer(buf + ETH_HLEN, payload_len, IPPROTO_TCP); 395 } 396 397 fill_datalinklayer(buf); 398 } 399 400 static void create_capacity_packet(void *buf, int flow_id, int pkt_idx, int psh) 401 { 402 int seq_offset = pkt_idx * CAPACITY_PAYLOAD_LEN; 403 struct tcphdr *tcph; 404 405 create_packet(buf, seq_offset, 0, CAPACITY_PAYLOAD_LEN, 0); 406 407 /* Customize for this flow id */ 408 memset(buf + total_hdr_len, 'a' + flow_id, CAPACITY_PAYLOAD_LEN); 409 410 tcph = buf + tcp_offset; 411 tcph->source = htons(SPORT + flow_id); 412 tcph->psh = psh; 413 tcph->check = 0; 414 tcph->check = tcp_checksum(tcph, CAPACITY_PAYLOAD_LEN); 415 } 416 417 /* Send a capacity test, 2 packets per flow, all first packets then all second: 418 * A1 B1 C1 D1 ... A2 B2 C2 D2 ... 419 */ 420 static void send_capacity(int fd, struct sockaddr_ll *daddr) 421 { 422 static char buf[MAX_HDR_LEN + CAPACITY_PAYLOAD_LEN]; 423 int pkt_size = total_hdr_len + CAPACITY_PAYLOAD_LEN; 424 int i; 425 426 /* Send first packet of each flow (no PSH) */ 427 for (i = 0; i < num_flows; i++) { 428 create_capacity_packet(buf, i, 0, 0); 429 write_packet(fd, buf, pkt_size, daddr); 430 } 431 432 /* Send second packet of each flow (with PSH to flush) */ 433 for (i = 0; i < num_flows; i++) { 434 create_capacity_packet(buf, i, 1, 1); 435 write_packet(fd, buf, pkt_size, daddr); 436 } 437 } 438 439 #ifndef TH_CWR 440 #define TH_CWR 0x80 441 #endif 442 static void set_flags(struct tcphdr *tcph, int payload_len, int psh, int syn, 443 int rst, int urg, int cwr) 444 { 445 tcph->psh = psh; 446 tcph->syn = syn; 447 tcph->rst = rst; 448 tcph->urg = urg; 449 if (cwr) 450 tcph->th_flags |= TH_CWR; 451 else 452 tcph->th_flags &= ~TH_CWR; 453 tcph->check = 0; 454 tcph->check = tcp_checksum(tcph, payload_len); 455 } 456 457 /* send extra flags of the (NUM_PACKETS / 2) and (NUM_PACKETS / 2 - 1) 458 * pkts, not first and not last pkt 459 */ 460 static void send_flags(int fd, struct sockaddr_ll *daddr, int psh, int syn, 461 int rst, int urg, int cwr) 462 { 463 static char flag_buf[2][MAX_HDR_LEN + PAYLOAD_LEN]; 464 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 465 int payload_len, pkt_size, i; 466 struct tcphdr *tcph; 467 int flag[2]; 468 469 payload_len = PAYLOAD_LEN * (psh || cwr); 470 pkt_size = total_hdr_len + payload_len; 471 flag[0] = NUM_PACKETS / 2; 472 flag[1] = NUM_PACKETS / 2 - 1; 473 474 /* Create and configure packets with flags 475 */ 476 for (i = 0; i < 2; i++) { 477 if (flag[i] > 0) { 478 create_packet(flag_buf[i], flag[i] * payload_len, 0, 479 payload_len, 0); 480 tcph = (struct tcphdr *)(flag_buf[i] + tcp_offset); 481 set_flags(tcph, payload_len, psh, syn, rst, urg, cwr); 482 } 483 } 484 485 for (i = 0; i < NUM_PACKETS + 1; i++) { 486 if (i == flag[0]) { 487 write_packet(fd, flag_buf[0], pkt_size, daddr); 488 continue; 489 } else if (i == flag[1] && cwr) { 490 write_packet(fd, flag_buf[1], pkt_size, daddr); 491 continue; 492 } 493 create_packet(buf, i * PAYLOAD_LEN, 0, PAYLOAD_LEN, 0); 494 write_packet(fd, buf, total_hdr_len + PAYLOAD_LEN, daddr); 495 } 496 } 497 498 /* Test for data of same length, smaller than previous 499 * and of different lengths 500 */ 501 static void send_data_pkts(int fd, struct sockaddr_ll *daddr, 502 int payload_len1, int payload_len2) 503 { 504 static char buf[ETH_HLEN + IP_MAXPACKET]; 505 506 create_packet(buf, 0, 0, payload_len1, 0); 507 write_packet(fd, buf, total_hdr_len + payload_len1, daddr); 508 create_packet(buf, payload_len1, 0, payload_len2, 0); 509 write_packet(fd, buf, total_hdr_len + payload_len2, daddr); 510 } 511 512 /* If incoming segments make tracked segment length exceed 513 * legal IP datagram length, do not coalesce 514 */ 515 static void send_large(int fd, struct sockaddr_ll *daddr, int remainder) 516 { 517 static char pkts[NUM_LARGE_PKT][TOTAL_HDR_LEN + MSS]; 518 static char last[TOTAL_HDR_LEN + MSS]; 519 static char new_seg[TOTAL_HDR_LEN + MSS]; 520 int i; 521 522 for (i = 0; i < NUM_LARGE_PKT; i++) 523 create_packet(pkts[i], i * MSS, 0, MSS, 0); 524 create_packet(last, NUM_LARGE_PKT * MSS, 0, remainder, 0); 525 create_packet(new_seg, (NUM_LARGE_PKT + 1) * MSS, 0, remainder, 0); 526 527 for (i = 0; i < NUM_LARGE_PKT; i++) 528 write_packet(fd, pkts[i], total_hdr_len + MSS, daddr); 529 write_packet(fd, last, total_hdr_len + remainder, daddr); 530 write_packet(fd, new_seg, total_hdr_len + remainder, daddr); 531 } 532 533 /* Pure acks and dup acks don't coalesce */ 534 static void send_ack(int fd, struct sockaddr_ll *daddr) 535 { 536 static char buf[MAX_HDR_LEN]; 537 538 create_packet(buf, 0, 0, 0, 0); 539 write_packet(fd, buf, total_hdr_len, daddr); 540 write_packet(fd, buf, total_hdr_len, daddr); 541 create_packet(buf, 0, 1, 0, 0); 542 write_packet(fd, buf, total_hdr_len, daddr); 543 } 544 545 static void recompute_packet(char *buf, char *no_ext, int extlen) 546 { 547 struct tcphdr *tcphdr = (struct tcphdr *)(buf + tcp_offset); 548 struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN); 549 struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN); 550 551 memmove(buf, no_ext, total_hdr_len); 552 memmove(buf + total_hdr_len + extlen, 553 no_ext + total_hdr_len, PAYLOAD_LEN); 554 555 tcphdr->doff = tcphdr->doff + (extlen / 4); 556 tcphdr->check = 0; 557 tcphdr->check = tcp_checksum(tcphdr, PAYLOAD_LEN + extlen); 558 if (proto == PF_INET) { 559 iph->tot_len = htons(ntohs(iph->tot_len) + extlen); 560 iph->check = 0; 561 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0); 562 563 if (ipip) { 564 iph += 1; 565 iph->tot_len = htons(ntohs(iph->tot_len) + extlen); 566 iph->check = 0; 567 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0); 568 } 569 } else { 570 ip6h->payload_len = htons(ntohs(ip6h->payload_len) + extlen); 571 } 572 } 573 574 static void tcp_write_options(char *buf, int kind, int ts) 575 { 576 struct tcp_option_ts { 577 uint8_t kind; 578 uint8_t len; 579 uint32_t tsval; 580 uint32_t tsecr; 581 } *opt_ts = (void *)buf; 582 struct tcp_option_window { 583 uint8_t kind; 584 uint8_t len; 585 uint8_t shift; 586 } *opt_window = (void *)buf; 587 588 switch (kind) { 589 case TCPOPT_NOP: 590 buf[0] = TCPOPT_NOP; 591 break; 592 case TCPOPT_WINDOW: 593 memset(opt_window, 0, sizeof(struct tcp_option_window)); 594 opt_window->kind = TCPOPT_WINDOW; 595 opt_window->len = TCPOLEN_WINDOW; 596 opt_window->shift = 0; 597 break; 598 case TCPOPT_TIMESTAMP: 599 memset(opt_ts, 0, sizeof(struct tcp_option_ts)); 600 opt_ts->kind = TCPOPT_TIMESTAMP; 601 opt_ts->len = TCPOLEN_TIMESTAMP; 602 opt_ts->tsval = ts; 603 opt_ts->tsecr = 0; 604 break; 605 default: 606 error(1, 0, "unimplemented TCP option"); 607 break; 608 } 609 } 610 611 /* TCP with options is always a permutation of {TS, NOP, NOP}. 612 * Implement different orders to verify coalescing stops. 613 */ 614 static void add_standard_tcp_options(char *buf, char *no_ext, int ts, int order) 615 { 616 switch (order) { 617 case 0: 618 tcp_write_options(buf + total_hdr_len, TCPOPT_NOP, 0); 619 tcp_write_options(buf + total_hdr_len + 1, TCPOPT_NOP, 0); 620 tcp_write_options(buf + total_hdr_len + 2 /* two NOP opts */, 621 TCPOPT_TIMESTAMP, ts); 622 break; 623 case 1: 624 tcp_write_options(buf + total_hdr_len, TCPOPT_NOP, 0); 625 tcp_write_options(buf + total_hdr_len + 1, 626 TCPOPT_TIMESTAMP, ts); 627 tcp_write_options(buf + total_hdr_len + 1 + TCPOLEN_TIMESTAMP, 628 TCPOPT_NOP, 0); 629 break; 630 case 2: 631 tcp_write_options(buf + total_hdr_len, TCPOPT_TIMESTAMP, ts); 632 tcp_write_options(buf + total_hdr_len + TCPOLEN_TIMESTAMP + 1, 633 TCPOPT_NOP, 0); 634 tcp_write_options(buf + total_hdr_len + TCPOLEN_TIMESTAMP + 2, 635 TCPOPT_NOP, 0); 636 break; 637 default: 638 error(1, 0, "unknown order"); 639 break; 640 } 641 recompute_packet(buf, no_ext, TCPOLEN_TSTAMP_APPA); 642 } 643 644 /* Packets with invalid checksum don't coalesce. */ 645 static void send_changed_checksum(int fd, struct sockaddr_ll *daddr) 646 { 647 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 648 struct tcphdr *tcph = (struct tcphdr *)(buf + tcp_offset); 649 int pkt_size = total_hdr_len + PAYLOAD_LEN; 650 651 create_packet(buf, 0, 0, PAYLOAD_LEN, 0); 652 write_packet(fd, buf, pkt_size, daddr); 653 654 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0); 655 tcph->check = tcph->check - 1; 656 write_packet(fd, buf, pkt_size, daddr); 657 } 658 659 /* Packets with non-consecutive sequence number don't coalesce.*/ 660 static void send_changed_seq(int fd, struct sockaddr_ll *daddr) 661 { 662 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 663 struct tcphdr *tcph = (struct tcphdr *)(buf + tcp_offset); 664 int pkt_size = total_hdr_len + PAYLOAD_LEN; 665 666 create_packet(buf, 0, 0, PAYLOAD_LEN, 0); 667 write_packet(fd, buf, pkt_size, daddr); 668 669 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0); 670 tcph->seq = ntohl(htonl(tcph->seq) + 1); 671 tcph->check = 0; 672 tcph->check = tcp_checksum(tcph, PAYLOAD_LEN); 673 write_packet(fd, buf, pkt_size, daddr); 674 } 675 676 /* Packet with different timestamp option or different timestamps 677 * don't coalesce. 678 */ 679 static void send_changed_ts(int fd, struct sockaddr_ll *daddr) 680 { 681 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 682 static char extpkt[sizeof(buf) + TCPOLEN_TSTAMP_APPA]; 683 int pkt_size = total_hdr_len + PAYLOAD_LEN + TCPOLEN_TSTAMP_APPA; 684 685 create_packet(buf, 0, 0, PAYLOAD_LEN, 0); 686 add_standard_tcp_options(extpkt, buf, 0, 0); 687 write_packet(fd, extpkt, pkt_size, daddr); 688 689 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0); 690 add_standard_tcp_options(extpkt, buf, 0, 0); 691 write_packet(fd, extpkt, pkt_size, daddr); 692 693 create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0); 694 add_standard_tcp_options(extpkt, buf, 100, 0); 695 write_packet(fd, extpkt, pkt_size, daddr); 696 697 create_packet(buf, PAYLOAD_LEN * 3, 0, PAYLOAD_LEN, 0); 698 add_standard_tcp_options(extpkt, buf, 100, 1); 699 write_packet(fd, extpkt, pkt_size, daddr); 700 701 create_packet(buf, PAYLOAD_LEN * 4, 0, PAYLOAD_LEN, 0); 702 add_standard_tcp_options(extpkt, buf, 100, 2); 703 write_packet(fd, extpkt, pkt_size, daddr); 704 } 705 706 /* Packet with different tcp options don't coalesce. */ 707 static void send_diff_opt(int fd, struct sockaddr_ll *daddr) 708 { 709 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 710 static char extpkt1[sizeof(buf) + TCPOLEN_TSTAMP_APPA]; 711 static char extpkt2[sizeof(buf) + TCPOLEN_MAXSEG]; 712 int extpkt1_size = total_hdr_len + PAYLOAD_LEN + TCPOLEN_TSTAMP_APPA; 713 int extpkt2_size = total_hdr_len + PAYLOAD_LEN + TCPOLEN_MAXSEG; 714 715 create_packet(buf, 0, 0, PAYLOAD_LEN, 0); 716 add_standard_tcp_options(extpkt1, buf, 0, 0); 717 write_packet(fd, extpkt1, extpkt1_size, daddr); 718 719 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0); 720 add_standard_tcp_options(extpkt1, buf, 0, 0); 721 write_packet(fd, extpkt1, extpkt1_size, daddr); 722 723 create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0); 724 tcp_write_options(extpkt2 + MAX_HDR_LEN, TCPOPT_NOP, 0); 725 tcp_write_options(extpkt2 + MAX_HDR_LEN + 1, TCPOPT_WINDOW, 0); 726 recompute_packet(extpkt2, buf, TCPOLEN_WINDOW + 1); 727 write_packet(fd, extpkt2, extpkt2_size, daddr); 728 } 729 730 static void add_ipv4_ts_option(void *buf, void *optpkt) 731 { 732 struct ip_timestamp *ts = (struct ip_timestamp *)(optpkt + tcp_offset); 733 int optlen = sizeof(struct ip_timestamp); 734 struct iphdr *iph; 735 736 if (optlen % 4) 737 error(1, 0, "ipv4 timestamp length is not a multiple of 4B"); 738 739 ts->ipt_code = IPOPT_TS; 740 ts->ipt_len = optlen; 741 ts->ipt_ptr = 5; 742 ts->ipt_flg = IPOPT_TS_TSONLY; 743 744 memcpy(optpkt, buf, tcp_offset); 745 memcpy(optpkt + tcp_offset + optlen, buf + tcp_offset, 746 sizeof(struct tcphdr) + PAYLOAD_LEN); 747 748 iph = (struct iphdr *)(optpkt + ETH_HLEN); 749 iph->ihl = 5 + (optlen / 4); 750 iph->tot_len = htons(ntohs(iph->tot_len) + optlen); 751 iph->check = 0; 752 iph->check = checksum_fold(iph, sizeof(struct iphdr) + optlen, 0); 753 } 754 755 static void add_ipv6_exthdr(void *buf, void *optpkt, __u8 exthdr_type, char *ext_payload) 756 { 757 struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr *)(optpkt + tcp_offset); 758 struct ipv6hdr *iph = (struct ipv6hdr *)(optpkt + ETH_HLEN); 759 char *exthdr_payload_start = (char *)(exthdr + 1); 760 761 exthdr->hdrlen = 0; 762 exthdr->nexthdr = IPPROTO_TCP; 763 764 memcpy(exthdr_payload_start, ext_payload, MIN_EXTHDR_SIZE - sizeof(*exthdr)); 765 766 memcpy(optpkt, buf, tcp_offset); 767 memcpy(optpkt + tcp_offset + MIN_EXTHDR_SIZE, buf + tcp_offset, 768 sizeof(struct tcphdr) + PAYLOAD_LEN); 769 770 iph->nexthdr = exthdr_type; 771 iph->payload_len = htons(ntohs(iph->payload_len) + MIN_EXTHDR_SIZE); 772 } 773 774 static void fix_ip4_checksum(struct iphdr *iph) 775 { 776 iph->check = 0; 777 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0); 778 } 779 780 static void send_flush_id_case(int fd, struct sockaddr_ll *daddr, 781 enum flush_id_case tcase) 782 { 783 static char buf1[MAX_HDR_LEN + PAYLOAD_LEN]; 784 static char buf2[MAX_HDR_LEN + PAYLOAD_LEN]; 785 static char buf3[MAX_HDR_LEN + PAYLOAD_LEN]; 786 bool send_three = false; 787 struct iphdr *iph1; 788 struct iphdr *iph2; 789 struct iphdr *iph3; 790 791 iph1 = (struct iphdr *)(buf1 + ETH_HLEN); 792 iph2 = (struct iphdr *)(buf2 + ETH_HLEN); 793 iph3 = (struct iphdr *)(buf3 + ETH_HLEN); 794 795 create_packet(buf1, 0, 0, PAYLOAD_LEN, 0); 796 create_packet(buf2, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0); 797 create_packet(buf3, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0); 798 799 switch (tcase) { 800 case FLUSH_ID_DF1_INC: /* DF=1, Incrementing - should coalesce */ 801 iph1->frag_off |= htons(IP_DF); 802 iph1->id = htons(8); 803 804 iph2->frag_off |= htons(IP_DF); 805 iph2->id = htons(9); 806 break; 807 808 case FLUSH_ID_DF1_FIXED: /* DF=1, Fixed - should coalesce */ 809 iph1->frag_off |= htons(IP_DF); 810 iph1->id = htons(8); 811 812 iph2->frag_off |= htons(IP_DF); 813 iph2->id = htons(8); 814 break; 815 816 case FLUSH_ID_DF0_INC: /* DF=0, Incrementing - should coalesce */ 817 iph1->frag_off &= ~htons(IP_DF); 818 iph1->id = htons(8); 819 820 iph2->frag_off &= ~htons(IP_DF); 821 iph2->id = htons(9); 822 break; 823 824 case FLUSH_ID_DF0_FIXED: /* DF=0, Fixed - should coalesce */ 825 iph1->frag_off &= ~htons(IP_DF); 826 iph1->id = htons(8); 827 828 iph2->frag_off &= ~htons(IP_DF); 829 iph2->id = htons(8); 830 break; 831 832 case FLUSH_ID_DF1_INC_FIXED: /* DF=1, two packets incrementing, and 833 * one fixed - should coalesce only the 834 * first two packets 835 */ 836 iph1->frag_off |= htons(IP_DF); 837 iph1->id = htons(8); 838 839 iph2->frag_off |= htons(IP_DF); 840 iph2->id = htons(9); 841 842 iph3->frag_off |= htons(IP_DF); 843 iph3->id = htons(9); 844 send_three = true; 845 break; 846 847 case FLUSH_ID_DF1_FIXED_INC: /* DF=1, two packets fixed, and one 848 * incrementing - should coalesce only 849 * the first two packets 850 */ 851 iph1->frag_off |= htons(IP_DF); 852 iph1->id = htons(8); 853 854 iph2->frag_off |= htons(IP_DF); 855 iph2->id = htons(8); 856 857 iph3->frag_off |= htons(IP_DF); 858 iph3->id = htons(9); 859 send_three = true; 860 break; 861 } 862 863 fix_ip4_checksum(iph1); 864 fix_ip4_checksum(iph2); 865 write_packet(fd, buf1, total_hdr_len + PAYLOAD_LEN, daddr); 866 write_packet(fd, buf2, total_hdr_len + PAYLOAD_LEN, daddr); 867 868 if (send_three) { 869 fix_ip4_checksum(iph3); 870 write_packet(fd, buf3, total_hdr_len + PAYLOAD_LEN, daddr); 871 } 872 } 873 874 static void send_ipv6_exthdr(int fd, struct sockaddr_ll *daddr, char *ext_data1, char *ext_data2) 875 { 876 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 877 static char exthdr_pck[sizeof(buf) + MIN_EXTHDR_SIZE]; 878 879 create_packet(buf, 0, 0, PAYLOAD_LEN, 0); 880 add_ipv6_exthdr(buf, exthdr_pck, IPPROTO_DSTOPTS, ext_data1); 881 write_packet(fd, exthdr_pck, total_hdr_len + PAYLOAD_LEN + MIN_EXTHDR_SIZE, daddr); 882 883 create_packet(buf, PAYLOAD_LEN * 1, 0, PAYLOAD_LEN, 0); 884 add_ipv6_exthdr(buf, exthdr_pck, IPPROTO_DSTOPTS, ext_data2); 885 write_packet(fd, exthdr_pck, total_hdr_len + PAYLOAD_LEN + MIN_EXTHDR_SIZE, daddr); 886 } 887 888 /* IPv4 options shouldn't coalesce */ 889 static void send_ip_options(int fd, struct sockaddr_ll *daddr) 890 { 891 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 892 static char optpkt[sizeof(buf) + sizeof(struct ip_timestamp)]; 893 int optlen = sizeof(struct ip_timestamp); 894 int pkt_size = total_hdr_len + PAYLOAD_LEN + optlen; 895 896 create_packet(buf, 0, 0, PAYLOAD_LEN, 0); 897 write_packet(fd, buf, total_hdr_len + PAYLOAD_LEN, daddr); 898 899 create_packet(buf, PAYLOAD_LEN * 1, 0, PAYLOAD_LEN, 0); 900 add_ipv4_ts_option(buf, optpkt); 901 write_packet(fd, optpkt, pkt_size, daddr); 902 903 create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0); 904 write_packet(fd, buf, total_hdr_len + PAYLOAD_LEN, daddr); 905 } 906 907 /* IPv4 fragments shouldn't coalesce */ 908 static void send_fragment4(int fd, struct sockaddr_ll *daddr) 909 { 910 static char buf[IP_MAXPACKET]; 911 struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN); 912 int pkt_size = total_hdr_len + PAYLOAD_LEN; 913 914 create_packet(buf, 0, 0, PAYLOAD_LEN, 0); 915 write_packet(fd, buf, pkt_size, daddr); 916 917 /* Once fragmented, packet would retain the total_len. 918 * Tcp header is prepared as if rest of data is in follow-up frags, 919 * but follow up frags aren't actually sent. 920 */ 921 memset(buf + total_hdr_len, 'a', PAYLOAD_LEN * 2); 922 fill_transportlayer(buf + tcp_offset, PAYLOAD_LEN, 0, PAYLOAD_LEN * 2, 0); 923 fill_networklayer(buf + ETH_HLEN, PAYLOAD_LEN, IPPROTO_TCP); 924 fill_datalinklayer(buf); 925 926 iph->frag_off = htons(0x6000); // DF = 1, MF = 1 927 iph->check = 0; 928 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0); 929 write_packet(fd, buf, pkt_size, daddr); 930 } 931 932 /* IPv4 packets with different ttl don't coalesce.*/ 933 static void send_changed_ttl(int fd, struct sockaddr_ll *daddr) 934 { 935 int pkt_size = total_hdr_len + PAYLOAD_LEN; 936 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 937 struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN); 938 939 create_packet(buf, 0, 0, PAYLOAD_LEN, 0); 940 write_packet(fd, buf, pkt_size, daddr); 941 942 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0); 943 iph->ttl = 7; 944 iph->check = 0; 945 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0); 946 write_packet(fd, buf, pkt_size, daddr); 947 } 948 949 /* Packets with different tos don't coalesce.*/ 950 static void send_changed_tos(int fd, struct sockaddr_ll *daddr) 951 { 952 int pkt_size = total_hdr_len + PAYLOAD_LEN; 953 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 954 struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN); 955 struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN); 956 957 create_packet(buf, 0, 0, PAYLOAD_LEN, 0); 958 write_packet(fd, buf, pkt_size, daddr); 959 960 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0); 961 if (proto == PF_INET) { 962 iph->tos = 1; 963 iph->check = 0; 964 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0); 965 } else if (proto == PF_INET6) { 966 ip6h->priority = 0xf; 967 } 968 write_packet(fd, buf, pkt_size, daddr); 969 } 970 971 /* Packets with different ECN don't coalesce.*/ 972 static void send_changed_ECN(int fd, struct sockaddr_ll *daddr) 973 { 974 int pkt_size = total_hdr_len + PAYLOAD_LEN; 975 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 976 struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN); 977 978 create_packet(buf, 0, 0, PAYLOAD_LEN, 0); 979 write_packet(fd, buf, pkt_size, daddr); 980 981 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0); 982 if (proto == PF_INET) { 983 buf[ETH_HLEN + 1] ^= 0x2; // ECN set to 10 984 iph->check = 0; 985 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0); 986 } else { 987 buf[ETH_HLEN + 1] ^= 0x20; // ECN set to 10 988 } 989 write_packet(fd, buf, pkt_size, daddr); 990 } 991 992 /* IPv6 fragments and packets with extensions don't coalesce.*/ 993 static void send_fragment6(int fd, struct sockaddr_ll *daddr) 994 { 995 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 996 static char extpkt[MAX_HDR_LEN + PAYLOAD_LEN + 997 sizeof(struct ip6_frag)]; 998 struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN); 999 struct ip6_frag *frag = (void *)(extpkt + tcp_offset); 1000 int extlen = sizeof(struct ip6_frag); 1001 int bufpkt_len = total_hdr_len + PAYLOAD_LEN; 1002 int extpkt_len = bufpkt_len + extlen; 1003 int i; 1004 1005 for (i = 0; i < 2; i++) { 1006 create_packet(buf, PAYLOAD_LEN * i, 0, PAYLOAD_LEN, 0); 1007 write_packet(fd, buf, bufpkt_len, daddr); 1008 } 1009 sleep(1); 1010 create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0); 1011 memset(extpkt, 0, extpkt_len); 1012 1013 ip6h->nexthdr = IPPROTO_FRAGMENT; 1014 ip6h->payload_len = htons(ntohs(ip6h->payload_len) + extlen); 1015 frag->ip6f_nxt = IPPROTO_TCP; 1016 1017 memcpy(extpkt, buf, tcp_offset); 1018 memcpy(extpkt + tcp_offset + extlen, buf + tcp_offset, 1019 sizeof(struct tcphdr) + PAYLOAD_LEN); 1020 write_packet(fd, extpkt, extpkt_len, daddr); 1021 1022 create_packet(buf, PAYLOAD_LEN * 3, 0, PAYLOAD_LEN, 0); 1023 write_packet(fd, buf, bufpkt_len, daddr); 1024 } 1025 1026 static void bind_packetsocket(int fd) 1027 { 1028 struct sockaddr_ll daddr = {}; 1029 1030 daddr.sll_family = AF_PACKET; 1031 daddr.sll_protocol = ethhdr_proto; 1032 daddr.sll_ifindex = if_nametoindex(ifname); 1033 if (daddr.sll_ifindex == 0) 1034 error(1, errno, "if_nametoindex"); 1035 1036 if (bind(fd, (void *)&daddr, sizeof(daddr)) < 0) 1037 error(1, errno, "could not bind socket"); 1038 } 1039 1040 static void set_timeout(int fd) 1041 { 1042 struct timeval timeout; 1043 1044 timeout.tv_sec = 3; 1045 timeout.tv_usec = 0; 1046 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, 1047 sizeof(timeout)) < 0) 1048 error(1, errno, "cannot set timeout, setsockopt failed"); 1049 } 1050 1051 static void set_rcvbuf(int fd) 1052 { 1053 int bufsize = 1 * 1024 * 1024; /* 1 MB */ 1054 1055 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize))) 1056 error(1, errno, "cannot set rcvbuf size, setsockopt failed"); 1057 } 1058 1059 static void recv_error(int fd, int rcv_errno) 1060 { 1061 struct tpacket_stats stats; 1062 socklen_t len; 1063 1064 len = sizeof(stats); 1065 if (getsockopt(fd, SOL_PACKET, PACKET_STATISTICS, &stats, &len)) 1066 error(1, errno, "can't get stats"); 1067 1068 fprintf(stderr, "Socket stats: packets=%u, drops=%u\n", 1069 stats.tp_packets, stats.tp_drops); 1070 error(1, rcv_errno, "could not receive"); 1071 } 1072 1073 static void check_recv_pkts(int fd, int *correct_payload, 1074 int correct_num_pkts) 1075 { 1076 static char buffer[IP_MAXPACKET + ETH_HLEN + 1]; 1077 struct iphdr *iph = (struct iphdr *)(buffer + ETH_HLEN); 1078 struct ipv6hdr *ip6h = (struct ipv6hdr *)(buffer + ETH_HLEN); 1079 struct tcphdr *tcph; 1080 bool bad_packet = false; 1081 int tcp_ext_len = 0; 1082 int ip_ext_len = 0; 1083 int pkt_size = -1; 1084 int data_len = 0; 1085 int num_pkt = 0; 1086 int i; 1087 1088 vlog("Expected {"); 1089 for (i = 0; i < correct_num_pkts; i++) 1090 vlog("%d ", correct_payload[i]); 1091 vlog("}, Total %d packets\nReceived {", correct_num_pkts); 1092 1093 while (1) { 1094 ip_ext_len = 0; 1095 pkt_size = recv(fd, buffer, IP_MAXPACKET + ETH_HLEN + 1, 0); 1096 if (pkt_size < 0) 1097 recv_error(fd, errno); 1098 1099 if (iph->version == 4) 1100 ip_ext_len = (iph->ihl - 5) * 4; 1101 else if (ip6h->version == 6 && ip6h->nexthdr != IPPROTO_TCP) 1102 ip_ext_len = MIN_EXTHDR_SIZE; 1103 1104 tcph = (struct tcphdr *)(buffer + tcp_offset + ip_ext_len); 1105 1106 if (tcph->fin) 1107 break; 1108 1109 tcp_ext_len = (tcph->doff - 5) * 4; 1110 data_len = pkt_size - total_hdr_len - tcp_ext_len - ip_ext_len; 1111 /* Min ethernet frame payload is 46(ETH_ZLEN - ETH_HLEN) by RFC 802.3. 1112 * Ipv4/tcp packets without at least 6 bytes of data will be padded. 1113 * Packet sockets are protocol agnostic, and will not trim the padding. 1114 */ 1115 if (pkt_size == ETH_ZLEN && iph->version == 4) { 1116 data_len = ntohs(iph->tot_len) 1117 - sizeof(struct tcphdr) - sizeof(struct iphdr); 1118 } 1119 vlog("%d ", data_len); 1120 if (data_len != correct_payload[num_pkt]) { 1121 vlog("[!=%d]", correct_payload[num_pkt]); 1122 bad_packet = true; 1123 } 1124 num_pkt++; 1125 } 1126 vlog("}, Total %d packets.\n", num_pkt); 1127 if (num_pkt != correct_num_pkts) 1128 error(1, 0, "incorrect number of packets"); 1129 if (bad_packet) 1130 error(1, 0, "incorrect packet geometry"); 1131 1132 printf("Test succeeded\n\n"); 1133 } 1134 1135 static void check_capacity_pkts(int fd) 1136 { 1137 static char buffer[IP_MAXPACKET + ETH_HLEN + 1]; 1138 struct iphdr *iph = (struct iphdr *)(buffer + ETH_HLEN); 1139 struct ipv6hdr *ip6h = (struct ipv6hdr *)(buffer + ETH_HLEN); 1140 int num_pkt = 0, num_coal = 0, pkt_idx; 1141 const char *fail_reason = NULL; 1142 int flow_order[num_flows * 2]; 1143 int coalesced[num_flows]; 1144 struct tcphdr *tcph; 1145 int ip_ext_len = 0; 1146 int total_data = 0; 1147 int pkt_size = -1; 1148 int data_len = 0; 1149 int flow_id; 1150 int sport; 1151 1152 memset(coalesced, 0, sizeof(coalesced)); 1153 memset(flow_order, -1, sizeof(flow_order)); 1154 1155 while (total_data < num_flows * CAPACITY_PAYLOAD_LEN * 2) { 1156 ip_ext_len = 0; 1157 pkt_size = recv(fd, buffer, IP_MAXPACKET + ETH_HLEN + 1, 0); 1158 if (pkt_size < 0) 1159 recv_error(fd, errno); 1160 1161 if (iph->version == 4) 1162 ip_ext_len = (iph->ihl - 5) * 4; 1163 else if (ip6h->version == 6 && ip6h->nexthdr != IPPROTO_TCP) 1164 ip_ext_len = MIN_EXTHDR_SIZE; 1165 1166 tcph = (struct tcphdr *)(buffer + tcp_offset + ip_ext_len); 1167 1168 /* FIN packet terminates reception */ 1169 if (tcph->fin) 1170 break; 1171 1172 sport = ntohs(tcph->source); 1173 flow_id = sport - SPORT; 1174 1175 if (flow_id < 0 || flow_id >= num_flows) { 1176 vlog("Invalid flow_id %d from sport %d\n", 1177 flow_id, sport); 1178 fail_reason = fail_reason ?: "invalid packet"; 1179 continue; 1180 } 1181 1182 /* Calculate payload length */ 1183 if (pkt_size == ETH_ZLEN && iph->version == 4) { 1184 data_len = ntohs(iph->tot_len) 1185 - sizeof(struct tcphdr) - sizeof(struct iphdr); 1186 } else { 1187 data_len = pkt_size - total_hdr_len - ip_ext_len; 1188 } 1189 1190 flow_order[num_pkt] = flow_id; 1191 coalesced[flow_id] = data_len; 1192 1193 if (data_len == CAPACITY_PAYLOAD_LEN * 2) { 1194 num_coal++; 1195 } else { 1196 vlog("Pkt %d: flow %d, sport %d, len %d (expected %d)\n", 1197 num_pkt, flow_id, sport, data_len, 1198 CAPACITY_PAYLOAD_LEN * 2); 1199 fail_reason = fail_reason ?: "not coalesced"; 1200 } 1201 1202 num_pkt++; 1203 total_data += data_len; 1204 } 1205 1206 /* Check flow ordering. We expect to see all non-coalesced first segs 1207 * then interleaved coalesced and non-coalesced second frames. 1208 */ 1209 pkt_idx = 0; 1210 for (flow_id = 0; order_check && flow_id < num_flows; flow_id++) { 1211 bool coaled = coalesced[flow_id] > CAPACITY_PAYLOAD_LEN; 1212 1213 if (coaled) 1214 continue; 1215 1216 if (flow_order[pkt_idx] != flow_id) { 1217 vlog("Flow order mismatch (non-coalesced) at position %d: expected flow %d, got flow %d\n", 1218 pkt_idx, flow_id, flow_order[pkt_idx]); 1219 fail_reason = fail_reason ?: "bad packet order (1)"; 1220 } 1221 pkt_idx++; 1222 } 1223 for (flow_id = 0; order_check && flow_id < num_flows; flow_id++) { 1224 bool coaled = coalesced[flow_id] > CAPACITY_PAYLOAD_LEN; 1225 1226 if (flow_order[pkt_idx] != flow_id) { 1227 vlog("Flow order mismatch at position %d: expected flow %d, got flow %d, coalesced: %d\n", 1228 pkt_idx, flow_id, flow_order[pkt_idx], coaled); 1229 fail_reason = fail_reason ?: "bad packet order (2)"; 1230 } 1231 pkt_idx++; 1232 } 1233 1234 if (!fail_reason) { 1235 vlog("All %d flows coalesced correctly\n", num_flows); 1236 printf("Test succeeded\n\n"); 1237 } else { 1238 printf("FAILED\n"); 1239 } 1240 1241 /* Always print stats for external validation */ 1242 printf("STATS: received=%d wire=%d coalesced=%d\n", 1243 num_pkt, num_pkt + num_coal, num_coal); 1244 1245 if (fail_reason) 1246 error(1, 0, "capacity test failed %s", fail_reason); 1247 } 1248 1249 static void gro_sender(void) 1250 { 1251 int bufsize = 4 * 1024 * 1024; /* 4 MB */ 1252 const int fin_delay_us = 100 * 1000; 1253 static char fin_pkt[MAX_HDR_LEN]; 1254 struct sockaddr_ll daddr = {}; 1255 int txfd = -1; 1256 1257 txfd = socket(PF_PACKET, SOCK_RAW, IPPROTO_RAW); 1258 if (txfd < 0) 1259 error(1, errno, "socket creation"); 1260 1261 if (setsockopt(txfd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize))) 1262 error(1, errno, "cannot set sndbuf size, setsockopt failed"); 1263 1264 /* Enable SO_TXTIME unless test case generates more than one flow 1265 * SO_TXTIME could result in qdisc layer sorting the packets at sender. 1266 */ 1267 if (strcmp(testname, "single") && strcmp(testname, "capacity")) { 1268 struct sock_txtime so_txtime = { .clockid = CLOCK_MONOTONIC, }; 1269 struct timespec ts; 1270 1271 if (setsockopt(txfd, SOL_SOCKET, SO_TXTIME, 1272 &so_txtime, sizeof(so_txtime))) 1273 error(1, errno, "setsockopt SO_TXTIME"); 1274 1275 if (clock_gettime(CLOCK_MONOTONIC, &ts)) 1276 error(1, errno, "clock_gettime"); 1277 1278 txtime_ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec; 1279 txtime_ns += TXTIME_DELAY_MS * 1000000ULL; 1280 } 1281 1282 memset(&daddr, 0, sizeof(daddr)); 1283 daddr.sll_ifindex = if_nametoindex(ifname); 1284 if (daddr.sll_ifindex == 0) 1285 error(1, errno, "if_nametoindex"); 1286 daddr.sll_family = AF_PACKET; 1287 memcpy(daddr.sll_addr, dst_mac, ETH_ALEN); 1288 daddr.sll_halen = ETH_ALEN; 1289 create_packet(fin_pkt, PAYLOAD_LEN * 2, 0, 0, 1); 1290 1291 /* data sub-tests */ 1292 if (strcmp(testname, "data_same") == 0) { 1293 send_data_pkts(txfd, &daddr, PAYLOAD_LEN, PAYLOAD_LEN); 1294 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1295 } else if (strcmp(testname, "data_lrg_sml") == 0) { 1296 send_data_pkts(txfd, &daddr, PAYLOAD_LEN, PAYLOAD_LEN / 2); 1297 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1298 } else if (strcmp(testname, "data_sml_lrg") == 0) { 1299 send_data_pkts(txfd, &daddr, PAYLOAD_LEN / 2, PAYLOAD_LEN); 1300 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1301 1302 /* ack test */ 1303 } else if (strcmp(testname, "ack") == 0) { 1304 send_ack(txfd, &daddr); 1305 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1306 1307 /* flags sub-tests */ 1308 } else if (strcmp(testname, "flags_psh") == 0) { 1309 send_flags(txfd, &daddr, 1, 0, 0, 0, 0); 1310 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1311 } else if (strcmp(testname, "flags_syn") == 0) { 1312 send_flags(txfd, &daddr, 0, 1, 0, 0, 0); 1313 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1314 } else if (strcmp(testname, "flags_rst") == 0) { 1315 send_flags(txfd, &daddr, 0, 0, 1, 0, 0); 1316 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1317 } else if (strcmp(testname, "flags_urg") == 0) { 1318 send_flags(txfd, &daddr, 0, 0, 0, 1, 0); 1319 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1320 } else if (strcmp(testname, "flags_cwr") == 0) { 1321 send_flags(txfd, &daddr, 0, 0, 0, 0, 1); 1322 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1323 1324 /* tcp sub-tests */ 1325 } else if (strcmp(testname, "tcp_csum") == 0) { 1326 send_changed_checksum(txfd, &daddr); 1327 usleep(fin_delay_us); 1328 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1329 } else if (strcmp(testname, "tcp_seq") == 0) { 1330 send_changed_seq(txfd, &daddr); 1331 usleep(fin_delay_us); 1332 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1333 } else if (strcmp(testname, "tcp_ts") == 0) { 1334 send_changed_ts(txfd, &daddr); 1335 usleep(fin_delay_us); 1336 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1337 } else if (strcmp(testname, "tcp_opt") == 0) { 1338 send_diff_opt(txfd, &daddr); 1339 usleep(fin_delay_us); 1340 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1341 1342 /* ip sub-tests - shared between IPv4 and IPv6 */ 1343 } else if (strcmp(testname, "ip_ecn") == 0) { 1344 send_changed_ECN(txfd, &daddr); 1345 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1346 } else if (strcmp(testname, "ip_tos") == 0) { 1347 send_changed_tos(txfd, &daddr); 1348 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1349 1350 /* ip sub-tests - IPv4 only */ 1351 } else if (strcmp(testname, "ip_ttl") == 0) { 1352 send_changed_ttl(txfd, &daddr); 1353 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1354 } else if (strcmp(testname, "ip_opt") == 0) { 1355 send_ip_options(txfd, &daddr); 1356 usleep(fin_delay_us); 1357 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1358 } else if (strcmp(testname, "ip_frag4") == 0) { 1359 send_fragment4(txfd, &daddr); 1360 usleep(fin_delay_us); 1361 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1362 } else if (strcmp(testname, "ip_id_df1_inc") == 0) { 1363 send_flush_id_case(txfd, &daddr, FLUSH_ID_DF1_INC); 1364 usleep(fin_delay_us); 1365 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1366 } else if (strcmp(testname, "ip_id_df1_fixed") == 0) { 1367 send_flush_id_case(txfd, &daddr, FLUSH_ID_DF1_FIXED); 1368 usleep(fin_delay_us); 1369 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1370 } else if (strcmp(testname, "ip_id_df0_inc") == 0) { 1371 send_flush_id_case(txfd, &daddr, FLUSH_ID_DF0_INC); 1372 usleep(fin_delay_us); 1373 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1374 } else if (strcmp(testname, "ip_id_df0_fixed") == 0) { 1375 send_flush_id_case(txfd, &daddr, FLUSH_ID_DF0_FIXED); 1376 usleep(fin_delay_us); 1377 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1378 } else if (strcmp(testname, "ip_id_df1_inc_fixed") == 0) { 1379 send_flush_id_case(txfd, &daddr, FLUSH_ID_DF1_INC_FIXED); 1380 usleep(fin_delay_us); 1381 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1382 } else if (strcmp(testname, "ip_id_df1_fixed_inc") == 0) { 1383 send_flush_id_case(txfd, &daddr, FLUSH_ID_DF1_FIXED_INC); 1384 usleep(fin_delay_us); 1385 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1386 1387 /* ip sub-tests - IPv6 only */ 1388 } else if (strcmp(testname, "ip_frag6") == 0) { 1389 send_fragment6(txfd, &daddr); 1390 usleep(fin_delay_us); 1391 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1392 } else if (strcmp(testname, "ip_v6ext_same") == 0) { 1393 send_ipv6_exthdr(txfd, &daddr, EXT_PAYLOAD_1, EXT_PAYLOAD_1); 1394 usleep(fin_delay_us); 1395 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1396 } else if (strcmp(testname, "ip_v6ext_diff") == 0) { 1397 send_ipv6_exthdr(txfd, &daddr, EXT_PAYLOAD_1, EXT_PAYLOAD_2); 1398 usleep(fin_delay_us); 1399 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1400 1401 /* large sub-tests */ 1402 } else if (strcmp(testname, "large_max") == 0) { 1403 int offset = (proto == PF_INET && !ipip) ? 20 : 0; 1404 int remainder = (MAX_PAYLOAD + offset) % MSS; 1405 1406 send_large(txfd, &daddr, remainder); 1407 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1408 } else if (strcmp(testname, "large_rem") == 0) { 1409 int offset = (proto == PF_INET && !ipip) ? 20 : 0; 1410 int remainder = (MAX_PAYLOAD + offset) % MSS; 1411 1412 send_large(txfd, &daddr, remainder + 1); 1413 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1414 1415 /* machinery sub-tests */ 1416 } else if (strcmp(testname, "single") == 0) { 1417 static char buf[MAX_HDR_LEN + PAYLOAD_LEN]; 1418 1419 create_packet(buf, 0, 0, PAYLOAD_LEN, 0); 1420 write_packet(txfd, buf, total_hdr_len + PAYLOAD_LEN, &daddr); 1421 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1422 } else if (strcmp(testname, "capacity") == 0) { 1423 send_capacity(txfd, &daddr); 1424 usleep(fin_delay_us); 1425 write_packet(txfd, fin_pkt, total_hdr_len, &daddr); 1426 1427 } else { 1428 error(1, 0, "Unknown testcase: %s", testname); 1429 } 1430 1431 if (close(txfd)) 1432 error(1, errno, "socket close"); 1433 } 1434 1435 static void gro_receiver(void) 1436 { 1437 static int correct_payload[NUM_PACKETS]; 1438 int rxfd = -1; 1439 1440 rxfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_NONE)); 1441 if (rxfd < 0) 1442 error(1, 0, "socket creation"); 1443 setup_sock_filter(rxfd); 1444 set_timeout(rxfd); 1445 set_rcvbuf(rxfd); 1446 bind_packetsocket(rxfd); 1447 1448 ksft_ready(); 1449 1450 memset(correct_payload, 0, sizeof(correct_payload)); 1451 1452 /* data sub-tests */ 1453 if (strcmp(testname, "data_same") == 0) { 1454 printf("pure data packet of same size: "); 1455 correct_payload[0] = PAYLOAD_LEN * 2; 1456 check_recv_pkts(rxfd, correct_payload, 1); 1457 } else if (strcmp(testname, "data_lrg_sml") == 0) { 1458 printf("large data packets followed by a smaller one: "); 1459 correct_payload[0] = PAYLOAD_LEN * 1.5; 1460 check_recv_pkts(rxfd, correct_payload, 1); 1461 } else if (strcmp(testname, "data_sml_lrg") == 0) { 1462 printf("small data packets followed by a larger one: "); 1463 correct_payload[0] = PAYLOAD_LEN / 2; 1464 correct_payload[1] = PAYLOAD_LEN; 1465 check_recv_pkts(rxfd, correct_payload, 2); 1466 1467 /* ack test */ 1468 } else if (strcmp(testname, "ack") == 0) { 1469 printf("duplicate ack and pure ack: "); 1470 check_recv_pkts(rxfd, correct_payload, 3); 1471 1472 /* flags sub-tests */ 1473 } else if (strcmp(testname, "flags_psh") == 0) { 1474 correct_payload[0] = PAYLOAD_LEN * 3; 1475 correct_payload[1] = PAYLOAD_LEN * 2; 1476 printf("psh flag ends coalescing: "); 1477 check_recv_pkts(rxfd, correct_payload, 2); 1478 } else if (strcmp(testname, "flags_syn") == 0) { 1479 correct_payload[0] = PAYLOAD_LEN * 2; 1480 correct_payload[1] = 0; 1481 correct_payload[2] = PAYLOAD_LEN * 2; 1482 printf("syn flag ends coalescing: "); 1483 check_recv_pkts(rxfd, correct_payload, 3); 1484 } else if (strcmp(testname, "flags_rst") == 0) { 1485 correct_payload[0] = PAYLOAD_LEN * 2; 1486 correct_payload[1] = 0; 1487 correct_payload[2] = PAYLOAD_LEN * 2; 1488 printf("rst flag ends coalescing: "); 1489 check_recv_pkts(rxfd, correct_payload, 3); 1490 } else if (strcmp(testname, "flags_urg") == 0) { 1491 correct_payload[0] = PAYLOAD_LEN * 2; 1492 correct_payload[1] = 0; 1493 correct_payload[2] = PAYLOAD_LEN * 2; 1494 printf("urg flag ends coalescing: "); 1495 check_recv_pkts(rxfd, correct_payload, 3); 1496 } else if (strcmp(testname, "flags_cwr") == 0) { 1497 correct_payload[0] = PAYLOAD_LEN; 1498 correct_payload[1] = PAYLOAD_LEN * 2; 1499 correct_payload[2] = PAYLOAD_LEN * 2; 1500 printf("cwr flag ends coalescing: "); 1501 check_recv_pkts(rxfd, correct_payload, 3); 1502 1503 /* tcp sub-tests */ 1504 } else if (strcmp(testname, "tcp_csum") == 0) { 1505 correct_payload[0] = PAYLOAD_LEN; 1506 correct_payload[1] = PAYLOAD_LEN; 1507 printf("changed checksum does not coalesce: "); 1508 check_recv_pkts(rxfd, correct_payload, 2); 1509 } else if (strcmp(testname, "tcp_seq") == 0) { 1510 correct_payload[0] = PAYLOAD_LEN; 1511 correct_payload[1] = PAYLOAD_LEN; 1512 printf("Wrong Seq number doesn't coalesce: "); 1513 check_recv_pkts(rxfd, correct_payload, 2); 1514 } else if (strcmp(testname, "tcp_ts") == 0) { 1515 correct_payload[0] = PAYLOAD_LEN * 2; 1516 correct_payload[1] = PAYLOAD_LEN; 1517 correct_payload[2] = PAYLOAD_LEN; 1518 correct_payload[3] = PAYLOAD_LEN; 1519 printf("Different timestamp doesn't coalesce: "); 1520 check_recv_pkts(rxfd, correct_payload, 4); 1521 } else if (strcmp(testname, "tcp_opt") == 0) { 1522 correct_payload[0] = PAYLOAD_LEN * 2; 1523 correct_payload[1] = PAYLOAD_LEN; 1524 printf("Different options doesn't coalesce: "); 1525 check_recv_pkts(rxfd, correct_payload, 2); 1526 1527 /* ip sub-tests - shared between IPv4 and IPv6 */ 1528 } else if (strcmp(testname, "ip_ecn") == 0) { 1529 correct_payload[0] = PAYLOAD_LEN; 1530 correct_payload[1] = PAYLOAD_LEN; 1531 printf("different ECN doesn't coalesce: "); 1532 check_recv_pkts(rxfd, correct_payload, 2); 1533 } else if (strcmp(testname, "ip_tos") == 0) { 1534 correct_payload[0] = PAYLOAD_LEN; 1535 correct_payload[1] = PAYLOAD_LEN; 1536 printf("different tos doesn't coalesce: "); 1537 check_recv_pkts(rxfd, correct_payload, 2); 1538 1539 /* ip sub-tests - IPv4 only */ 1540 } else if (strcmp(testname, "ip_ttl") == 0) { 1541 correct_payload[0] = PAYLOAD_LEN; 1542 correct_payload[1] = PAYLOAD_LEN; 1543 printf("different ttl doesn't coalesce: "); 1544 check_recv_pkts(rxfd, correct_payload, 2); 1545 } else if (strcmp(testname, "ip_opt") == 0) { 1546 correct_payload[0] = PAYLOAD_LEN; 1547 correct_payload[1] = PAYLOAD_LEN; 1548 correct_payload[2] = PAYLOAD_LEN; 1549 printf("ip options doesn't coalesce: "); 1550 check_recv_pkts(rxfd, correct_payload, 3); 1551 } else if (strcmp(testname, "ip_frag4") == 0) { 1552 correct_payload[0] = PAYLOAD_LEN; 1553 correct_payload[1] = PAYLOAD_LEN; 1554 printf("fragmented ip4 doesn't coalesce: "); 1555 check_recv_pkts(rxfd, correct_payload, 2); 1556 } else if (strcmp(testname, "ip_id_df1_inc") == 0) { 1557 printf("DF=1, Incrementing - should coalesce: "); 1558 correct_payload[0] = PAYLOAD_LEN * 2; 1559 check_recv_pkts(rxfd, correct_payload, 1); 1560 } else if (strcmp(testname, "ip_id_df1_fixed") == 0) { 1561 printf("DF=1, Fixed - should coalesce: "); 1562 correct_payload[0] = PAYLOAD_LEN * 2; 1563 check_recv_pkts(rxfd, correct_payload, 1); 1564 } else if (strcmp(testname, "ip_id_df0_inc") == 0) { 1565 printf("DF=0, Incrementing - should coalesce: "); 1566 correct_payload[0] = PAYLOAD_LEN * 2; 1567 check_recv_pkts(rxfd, correct_payload, 1); 1568 } else if (strcmp(testname, "ip_id_df0_fixed") == 0) { 1569 printf("DF=0, Fixed - should coalesce: "); 1570 correct_payload[0] = PAYLOAD_LEN * 2; 1571 check_recv_pkts(rxfd, correct_payload, 1); 1572 } else if (strcmp(testname, "ip_id_df1_inc_fixed") == 0) { 1573 printf("DF=1, 2 Incrementing and one fixed - should coalesce only first 2 packets: "); 1574 correct_payload[0] = PAYLOAD_LEN * 2; 1575 correct_payload[1] = PAYLOAD_LEN; 1576 check_recv_pkts(rxfd, correct_payload, 2); 1577 } else if (strcmp(testname, "ip_id_df1_fixed_inc") == 0) { 1578 printf("DF=1, 2 Fixed and one incrementing - should coalesce only first 2 packets: "); 1579 correct_payload[0] = PAYLOAD_LEN * 2; 1580 correct_payload[1] = PAYLOAD_LEN; 1581 check_recv_pkts(rxfd, correct_payload, 2); 1582 1583 /* ip sub-tests - IPv6 only */ 1584 } else if (strcmp(testname, "ip_frag6") == 0) { 1585 /* GRO doesn't check for ipv6 hop limit when flushing. 1586 * Hence no corresponding test to the ipv4 case. 1587 */ 1588 printf("fragmented ip6 doesn't coalesce: "); 1589 correct_payload[0] = PAYLOAD_LEN * 2; 1590 correct_payload[1] = PAYLOAD_LEN; 1591 correct_payload[2] = PAYLOAD_LEN; 1592 check_recv_pkts(rxfd, correct_payload, 3); 1593 } else if (strcmp(testname, "ip_v6ext_same") == 0) { 1594 printf("ipv6 with ext header does coalesce: "); 1595 correct_payload[0] = PAYLOAD_LEN * 2; 1596 check_recv_pkts(rxfd, correct_payload, 1); 1597 } else if (strcmp(testname, "ip_v6ext_diff") == 0) { 1598 printf("ipv6 with ext header with different payloads doesn't coalesce: "); 1599 correct_payload[0] = PAYLOAD_LEN; 1600 correct_payload[1] = PAYLOAD_LEN; 1601 check_recv_pkts(rxfd, correct_payload, 2); 1602 1603 /* large sub-tests */ 1604 } else if (strcmp(testname, "large_max") == 0) { 1605 int offset = (proto == PF_INET && !ipip) ? 20 : 0; 1606 int remainder = (MAX_PAYLOAD + offset) % MSS; 1607 1608 correct_payload[0] = (MAX_PAYLOAD + offset); 1609 correct_payload[1] = remainder; 1610 printf("Shouldn't coalesce if exceed IP max pkt size: "); 1611 check_recv_pkts(rxfd, correct_payload, 2); 1612 } else if (strcmp(testname, "large_rem") == 0) { 1613 int offset = (proto == PF_INET && !ipip) ? 20 : 0; 1614 int remainder = (MAX_PAYLOAD + offset) % MSS; 1615 1616 /* last segment sent individually, doesn't start new segment */ 1617 correct_payload[0] = (MAX_PAYLOAD + offset) - remainder; 1618 correct_payload[1] = remainder + 1; 1619 correct_payload[2] = remainder + 1; 1620 printf("last segment sent individually: "); 1621 check_recv_pkts(rxfd, correct_payload, 3); 1622 1623 /* machinery sub-tests */ 1624 } else if (strcmp(testname, "single") == 0) { 1625 printf("single data packet: "); 1626 correct_payload[0] = PAYLOAD_LEN; 1627 check_recv_pkts(rxfd, correct_payload, 1); 1628 } else if (strcmp(testname, "capacity") == 0) { 1629 check_capacity_pkts(rxfd); 1630 1631 } else { 1632 error(1, 0, "Test case error: unknown testname %s", testname); 1633 } 1634 1635 if (close(rxfd)) 1636 error(1, 0, "socket close"); 1637 } 1638 1639 static void parse_args(int argc, char **argv) 1640 { 1641 static const struct option opts[] = { 1642 { "daddr", required_argument, NULL, 'd' }, 1643 { "dmac", required_argument, NULL, 'D' }, 1644 { "iface", required_argument, NULL, 'i' }, 1645 { "ipv4", no_argument, NULL, '4' }, 1646 { "ipv6", no_argument, NULL, '6' }, 1647 { "ipip", no_argument, NULL, 'e' }, 1648 { "num-flows", required_argument, NULL, 'n' }, 1649 { "rx", no_argument, NULL, 'r' }, 1650 { "saddr", required_argument, NULL, 's' }, 1651 { "smac", required_argument, NULL, 'S' }, 1652 { "test", required_argument, NULL, 't' }, 1653 { "order-check", no_argument, NULL, 'o' }, 1654 { "verbose", no_argument, NULL, 'v' }, 1655 { 0, 0, 0, 0 } 1656 }; 1657 int c; 1658 1659 while ((c = getopt_long(argc, argv, "46d:D:ei:n:rs:S:t:ov", opts, NULL)) != -1) { 1660 switch (c) { 1661 case '4': 1662 proto = PF_INET; 1663 ethhdr_proto = htons(ETH_P_IP); 1664 break; 1665 case '6': 1666 proto = PF_INET6; 1667 ethhdr_proto = htons(ETH_P_IPV6); 1668 break; 1669 case 'e': 1670 ipip = true; 1671 proto = PF_INET; 1672 ethhdr_proto = htons(ETH_P_IP); 1673 break; 1674 case 'd': 1675 addr4_dst = addr6_dst = optarg; 1676 break; 1677 case 'D': 1678 dmac = optarg; 1679 break; 1680 case 'i': 1681 ifname = optarg; 1682 break; 1683 case 'n': 1684 num_flows = atoi(optarg); 1685 break; 1686 case 'r': 1687 tx_socket = false; 1688 break; 1689 case 's': 1690 addr4_src = addr6_src = optarg; 1691 break; 1692 case 'S': 1693 smac = optarg; 1694 break; 1695 case 't': 1696 testname = optarg; 1697 break; 1698 case 'o': 1699 order_check = true; 1700 break; 1701 case 'v': 1702 verbose = true; 1703 break; 1704 default: 1705 error(1, 0, "%s invalid option %c\n", __func__, c); 1706 break; 1707 } 1708 } 1709 } 1710 1711 int main(int argc, char **argv) 1712 { 1713 parse_args(argc, argv); 1714 1715 if (ipip) { 1716 tcp_offset = ETH_HLEN + sizeof(struct iphdr) * 2; 1717 total_hdr_len = tcp_offset + sizeof(struct tcphdr); 1718 } else if (proto == PF_INET) { 1719 tcp_offset = ETH_HLEN + sizeof(struct iphdr); 1720 total_hdr_len = tcp_offset + sizeof(struct tcphdr); 1721 } else if (proto == PF_INET6) { 1722 tcp_offset = ETH_HLEN + sizeof(struct ipv6hdr); 1723 total_hdr_len = MAX_HDR_LEN; 1724 } else { 1725 error(1, 0, "Protocol family is not ipv4 or ipv6"); 1726 } 1727 1728 read_MAC(src_mac, smac); 1729 read_MAC(dst_mac, dmac); 1730 1731 if (tx_socket) { 1732 gro_sender(); 1733 } else { 1734 /* Only the receiver exit status determines test success. */ 1735 gro_receiver(); 1736 fprintf(stderr, "Gro::%s test passed.\n", testname); 1737 } 1738 1739 return 0; 1740 } 1741