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