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