root/tools/testing/selftests/bpf/test_flow_dissector.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. INIT_ADDR4
  2. util_printaddr
  3. add_csum_hword
  4. build_ip_csum
  5. build_ipv4_header
  6. ipv6_set_dsfield
  7. build_ipv6_header
  8. build_udp_v4_csum
  9. build_udp_v6_csum
  10. build_udp_header
  11. build_gue_header
  12. build_gre_header
  13. l3_length
  14. build_packet
  15. setup_tx
  16. setup_rx
  17. do_tx
  18. do_poll
  19. do_rx
  20. do_main
  21. usage
  22. parse_addr
  23. parse_addr4
  24. parse_addr6
  25. parse_protocol_family
  26. parse_opts
  27. print_opts
  28. main

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Inject packets with all sorts of encapsulation into the kernel.
   4  *
   5  * IPv4/IPv6    outer layer 3
   6  * GRE/GUE/BARE outer layer 4, where bare is IPIP/SIT/IPv4-in-IPv6/..
   7  * IPv4/IPv6    inner layer 3
   8  */
   9 
  10 #define _GNU_SOURCE
  11 
  12 #include <stddef.h>
  13 #include <arpa/inet.h>
  14 #include <asm/byteorder.h>
  15 #include <error.h>
  16 #include <errno.h>
  17 #include <linux/if_packet.h>
  18 #include <linux/if_ether.h>
  19 #include <linux/ipv6.h>
  20 #include <netinet/ip.h>
  21 #include <netinet/in.h>
  22 #include <netinet/udp.h>
  23 #include <poll.h>
  24 #include <stdbool.h>
  25 #include <stdlib.h>
  26 #include <stdio.h>
  27 #include <string.h>
  28 #include <sys/ioctl.h>
  29 #include <sys/socket.h>
  30 #include <sys/stat.h>
  31 #include <sys/time.h>
  32 #include <sys/types.h>
  33 #include <unistd.h>
  34 
  35 #define CFG_PORT_INNER  8000
  36 
  37 /* Add some protocol definitions that do not exist in userspace */
  38 
  39 struct grehdr {
  40         uint16_t unused;
  41         uint16_t protocol;
  42 } __attribute__((packed));
  43 
  44 struct guehdr {
  45         union {
  46                 struct {
  47 #if defined(__LITTLE_ENDIAN_BITFIELD)
  48                         __u8    hlen:5,
  49                                 control:1,
  50                                 version:2;
  51 #elif defined (__BIG_ENDIAN_BITFIELD)
  52                         __u8    version:2,
  53                                 control:1,
  54                                 hlen:5;
  55 #else
  56 #error  "Please fix <asm/byteorder.h>"
  57 #endif
  58                         __u8    proto_ctype;
  59                         __be16  flags;
  60                 };
  61                 __be32  word;
  62         };
  63 };
  64 
  65 static uint8_t  cfg_dsfield_inner;
  66 static uint8_t  cfg_dsfield_outer;
  67 static uint8_t  cfg_encap_proto;
  68 static bool     cfg_expect_failure = false;
  69 static int      cfg_l3_extra = AF_UNSPEC;       /* optional SIT prefix */
  70 static int      cfg_l3_inner = AF_UNSPEC;
  71 static int      cfg_l3_outer = AF_UNSPEC;
  72 static int      cfg_num_pkt = 10;
  73 static int      cfg_num_secs = 0;
  74 static char     cfg_payload_char = 'a';
  75 static int      cfg_payload_len = 100;
  76 static int      cfg_port_gue = 6080;
  77 static bool     cfg_only_rx;
  78 static bool     cfg_only_tx;
  79 static int      cfg_src_port = 9;
  80 
  81 static char     buf[ETH_DATA_LEN];
  82 
  83 #define INIT_ADDR4(name, addr4, port)                           \
  84         static struct sockaddr_in name = {                      \
  85                 .sin_family = AF_INET,                          \
  86                 .sin_port = __constant_htons(port),             \
  87                 .sin_addr.s_addr = __constant_htonl(addr4),     \
  88         };
  89 
  90 #define INIT_ADDR6(name, addr6, port)                           \
  91         static struct sockaddr_in6 name = {                     \
  92                 .sin6_family = AF_INET6,                        \
  93                 .sin6_port = __constant_htons(port),            \
  94                 .sin6_addr = addr6,                             \
  95         };
  96 
  97 INIT_ADDR4(in_daddr4, INADDR_LOOPBACK, CFG_PORT_INNER)
  98 INIT_ADDR4(in_saddr4, INADDR_LOOPBACK + 2, 0)
  99 INIT_ADDR4(out_daddr4, INADDR_LOOPBACK, 0)
 100 INIT_ADDR4(out_saddr4, INADDR_LOOPBACK + 1, 0)
 101 INIT_ADDR4(extra_daddr4, INADDR_LOOPBACK, 0)
 102 INIT_ADDR4(extra_saddr4, INADDR_LOOPBACK + 1, 0)
 103 
 104 INIT_ADDR6(in_daddr6, IN6ADDR_LOOPBACK_INIT, CFG_PORT_INNER)
 105 INIT_ADDR6(in_saddr6, IN6ADDR_LOOPBACK_INIT, 0)
 106 INIT_ADDR6(out_daddr6, IN6ADDR_LOOPBACK_INIT, 0)
 107 INIT_ADDR6(out_saddr6, IN6ADDR_LOOPBACK_INIT, 0)
 108 INIT_ADDR6(extra_daddr6, IN6ADDR_LOOPBACK_INIT, 0)
 109 INIT_ADDR6(extra_saddr6, IN6ADDR_LOOPBACK_INIT, 0)
 110 
 111 static unsigned long util_gettime(void)
 112 {
 113         struct timeval tv;
 114 
 115         gettimeofday(&tv, NULL);
 116         return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
 117 }
 118 
 119 static void util_printaddr(const char *msg, struct sockaddr *addr)
 120 {
 121         unsigned long off = 0;
 122         char nbuf[INET6_ADDRSTRLEN];
 123 
 124         switch (addr->sa_family) {
 125         case PF_INET:
 126                 off = __builtin_offsetof(struct sockaddr_in, sin_addr);
 127                 break;
 128         case PF_INET6:
 129                 off = __builtin_offsetof(struct sockaddr_in6, sin6_addr);
 130                 break;
 131         default:
 132                 error(1, 0, "printaddr: unsupported family %u\n",
 133                       addr->sa_family);
 134         }
 135 
 136         if (!inet_ntop(addr->sa_family, ((void *) addr) + off, nbuf,
 137                        sizeof(nbuf)))
 138                 error(1, errno, "inet_ntop");
 139 
 140         fprintf(stderr, "%s: %s\n", msg, nbuf);
 141 }
 142 
 143 static unsigned long add_csum_hword(const uint16_t *start, int num_u16)
 144 {
 145         unsigned long sum = 0;
 146         int i;
 147 
 148         for (i = 0; i < num_u16; i++)
 149                 sum += start[i];
 150 
 151         return sum;
 152 }
 153 
 154 static uint16_t build_ip_csum(const uint16_t *start, int num_u16,
 155                               unsigned long sum)
 156 {
 157         sum += add_csum_hword(start, num_u16);
 158 
 159         while (sum >> 16)
 160                 sum = (sum & 0xffff) + (sum >> 16);
 161 
 162         return ~sum;
 163 }
 164 
 165 static void build_ipv4_header(void *header, uint8_t proto,
 166                               uint32_t src, uint32_t dst,
 167                               int payload_len, uint8_t tos)
 168 {
 169         struct iphdr *iph = header;
 170 
 171         iph->ihl = 5;
 172         iph->version = 4;
 173         iph->tos = tos;
 174         iph->ttl = 8;
 175         iph->tot_len = htons(sizeof(*iph) + payload_len);
 176         iph->id = htons(1337);
 177         iph->protocol = proto;
 178         iph->saddr = src;
 179         iph->daddr = dst;
 180         iph->check = build_ip_csum((void *) iph, iph->ihl << 1, 0);
 181 }
 182 
 183 static void ipv6_set_dsfield(struct ipv6hdr *ip6h, uint8_t dsfield)
 184 {
 185         uint16_t val, *ptr = (uint16_t *)ip6h;
 186 
 187         val = ntohs(*ptr);
 188         val &= 0xF00F;
 189         val |= ((uint16_t) dsfield) << 4;
 190         *ptr = htons(val);
 191 }
 192 
 193 static void build_ipv6_header(void *header, uint8_t proto,
 194                               struct sockaddr_in6 *src,
 195                               struct sockaddr_in6 *dst,
 196                               int payload_len, uint8_t dsfield)
 197 {
 198         struct ipv6hdr *ip6h = header;
 199 
 200         ip6h->version = 6;
 201         ip6h->payload_len = htons(payload_len);
 202         ip6h->nexthdr = proto;
 203         ip6h->hop_limit = 8;
 204         ipv6_set_dsfield(ip6h, dsfield);
 205 
 206         memcpy(&ip6h->saddr, &src->sin6_addr, sizeof(ip6h->saddr));
 207         memcpy(&ip6h->daddr, &dst->sin6_addr, sizeof(ip6h->daddr));
 208 }
 209 
 210 static uint16_t build_udp_v4_csum(const struct iphdr *iph,
 211                                   const struct udphdr *udph,
 212                                   int num_words)
 213 {
 214         unsigned long pseudo_sum;
 215         int num_u16 = sizeof(iph->saddr);       /* halfwords: twice byte len */
 216 
 217         pseudo_sum = add_csum_hword((void *) &iph->saddr, num_u16);
 218         pseudo_sum += htons(IPPROTO_UDP);
 219         pseudo_sum += udph->len;
 220         return build_ip_csum((void *) udph, num_words, pseudo_sum);
 221 }
 222 
 223 static uint16_t build_udp_v6_csum(const struct ipv6hdr *ip6h,
 224                                   const struct udphdr *udph,
 225                                   int num_words)
 226 {
 227         unsigned long pseudo_sum;
 228         int num_u16 = sizeof(ip6h->saddr);      /* halfwords: twice byte len */
 229 
 230         pseudo_sum = add_csum_hword((void *) &ip6h->saddr, num_u16);
 231         pseudo_sum += htons(ip6h->nexthdr);
 232         pseudo_sum += ip6h->payload_len;
 233         return build_ip_csum((void *) udph, num_words, pseudo_sum);
 234 }
 235 
 236 static void build_udp_header(void *header, int payload_len,
 237                              uint16_t dport, int family)
 238 {
 239         struct udphdr *udph = header;
 240         int len = sizeof(*udph) + payload_len;
 241 
 242         udph->source = htons(cfg_src_port);
 243         udph->dest = htons(dport);
 244         udph->len = htons(len);
 245         udph->check = 0;
 246         if (family == AF_INET)
 247                 udph->check = build_udp_v4_csum(header - sizeof(struct iphdr),
 248                                                 udph, len >> 1);
 249         else
 250                 udph->check = build_udp_v6_csum(header - sizeof(struct ipv6hdr),
 251                                                 udph, len >> 1);
 252 }
 253 
 254 static void build_gue_header(void *header, uint8_t proto)
 255 {
 256         struct guehdr *gueh = header;
 257 
 258         gueh->proto_ctype = proto;
 259 }
 260 
 261 static void build_gre_header(void *header, uint16_t proto)
 262 {
 263         struct grehdr *greh = header;
 264 
 265         greh->protocol = htons(proto);
 266 }
 267 
 268 static int l3_length(int family)
 269 {
 270         if (family == AF_INET)
 271                 return sizeof(struct iphdr);
 272         else
 273                 return sizeof(struct ipv6hdr);
 274 }
 275 
 276 static int build_packet(void)
 277 {
 278         int ol3_len = 0, ol4_len = 0, il3_len = 0, il4_len = 0;
 279         int el3_len = 0;
 280 
 281         if (cfg_l3_extra)
 282                 el3_len = l3_length(cfg_l3_extra);
 283 
 284         /* calculate header offsets */
 285         if (cfg_encap_proto) {
 286                 ol3_len = l3_length(cfg_l3_outer);
 287 
 288                 if (cfg_encap_proto == IPPROTO_GRE)
 289                         ol4_len = sizeof(struct grehdr);
 290                 else if (cfg_encap_proto == IPPROTO_UDP)
 291                         ol4_len = sizeof(struct udphdr) + sizeof(struct guehdr);
 292         }
 293 
 294         il3_len = l3_length(cfg_l3_inner);
 295         il4_len = sizeof(struct udphdr);
 296 
 297         if (el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len >=
 298             sizeof(buf))
 299                 error(1, 0, "packet too large\n");
 300 
 301         /*
 302          * Fill packet from inside out, to calculate correct checksums.
 303          * But create ip before udp headers, as udp uses ip for pseudo-sum.
 304          */
 305         memset(buf + el3_len + ol3_len + ol4_len + il3_len + il4_len,
 306                cfg_payload_char, cfg_payload_len);
 307 
 308         /* add zero byte for udp csum padding */
 309         buf[el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len] = 0;
 310 
 311         switch (cfg_l3_inner) {
 312         case PF_INET:
 313                 build_ipv4_header(buf + el3_len + ol3_len + ol4_len,
 314                                   IPPROTO_UDP,
 315                                   in_saddr4.sin_addr.s_addr,
 316                                   in_daddr4.sin_addr.s_addr,
 317                                   il4_len + cfg_payload_len,
 318                                   cfg_dsfield_inner);
 319                 break;
 320         case PF_INET6:
 321                 build_ipv6_header(buf + el3_len + ol3_len + ol4_len,
 322                                   IPPROTO_UDP,
 323                                   &in_saddr6, &in_daddr6,
 324                                   il4_len + cfg_payload_len,
 325                                   cfg_dsfield_inner);
 326                 break;
 327         }
 328 
 329         build_udp_header(buf + el3_len + ol3_len + ol4_len + il3_len,
 330                          cfg_payload_len, CFG_PORT_INNER, cfg_l3_inner);
 331 
 332         if (!cfg_encap_proto)
 333                 return il3_len + il4_len + cfg_payload_len;
 334 
 335         switch (cfg_l3_outer) {
 336         case PF_INET:
 337                 build_ipv4_header(buf + el3_len, cfg_encap_proto,
 338                                   out_saddr4.sin_addr.s_addr,
 339                                   out_daddr4.sin_addr.s_addr,
 340                                   ol4_len + il3_len + il4_len + cfg_payload_len,
 341                                   cfg_dsfield_outer);
 342                 break;
 343         case PF_INET6:
 344                 build_ipv6_header(buf + el3_len, cfg_encap_proto,
 345                                   &out_saddr6, &out_daddr6,
 346                                   ol4_len + il3_len + il4_len + cfg_payload_len,
 347                                   cfg_dsfield_outer);
 348                 break;
 349         }
 350 
 351         switch (cfg_encap_proto) {
 352         case IPPROTO_UDP:
 353                 build_gue_header(buf + el3_len + ol3_len + ol4_len -
 354                                  sizeof(struct guehdr),
 355                                  cfg_l3_inner == PF_INET ? IPPROTO_IPIP
 356                                                          : IPPROTO_IPV6);
 357                 build_udp_header(buf + el3_len + ol3_len,
 358                                  sizeof(struct guehdr) + il3_len + il4_len +
 359                                  cfg_payload_len,
 360                                  cfg_port_gue, cfg_l3_outer);
 361                 break;
 362         case IPPROTO_GRE:
 363                 build_gre_header(buf + el3_len + ol3_len,
 364                                  cfg_l3_inner == PF_INET ? ETH_P_IP
 365                                                          : ETH_P_IPV6);
 366                 break;
 367         }
 368 
 369         switch (cfg_l3_extra) {
 370         case PF_INET:
 371                 build_ipv4_header(buf,
 372                                   cfg_l3_outer == PF_INET ? IPPROTO_IPIP
 373                                                           : IPPROTO_IPV6,
 374                                   extra_saddr4.sin_addr.s_addr,
 375                                   extra_daddr4.sin_addr.s_addr,
 376                                   ol3_len + ol4_len + il3_len + il4_len +
 377                                   cfg_payload_len, 0);
 378                 break;
 379         case PF_INET6:
 380                 build_ipv6_header(buf,
 381                                   cfg_l3_outer == PF_INET ? IPPROTO_IPIP
 382                                                           : IPPROTO_IPV6,
 383                                   &extra_saddr6, &extra_daddr6,
 384                                   ol3_len + ol4_len + il3_len + il4_len +
 385                                   cfg_payload_len, 0);
 386                 break;
 387         }
 388 
 389         return el3_len + ol3_len + ol4_len + il3_len + il4_len +
 390                cfg_payload_len;
 391 }
 392 
 393 /* sender transmits encapsulated over RAW or unencap'd over UDP */
 394 static int setup_tx(void)
 395 {
 396         int family, fd, ret;
 397 
 398         if (cfg_l3_extra)
 399                 family = cfg_l3_extra;
 400         else if (cfg_l3_outer)
 401                 family = cfg_l3_outer;
 402         else
 403                 family = cfg_l3_inner;
 404 
 405         fd = socket(family, SOCK_RAW, IPPROTO_RAW);
 406         if (fd == -1)
 407                 error(1, errno, "socket tx");
 408 
 409         if (cfg_l3_extra) {
 410                 if (cfg_l3_extra == PF_INET)
 411                         ret = connect(fd, (void *) &extra_daddr4,
 412                                       sizeof(extra_daddr4));
 413                 else
 414                         ret = connect(fd, (void *) &extra_daddr6,
 415                                       sizeof(extra_daddr6));
 416                 if (ret)
 417                         error(1, errno, "connect tx");
 418         } else if (cfg_l3_outer) {
 419                 /* connect to destination if not encapsulated */
 420                 if (cfg_l3_outer == PF_INET)
 421                         ret = connect(fd, (void *) &out_daddr4,
 422                                       sizeof(out_daddr4));
 423                 else
 424                         ret = connect(fd, (void *) &out_daddr6,
 425                                       sizeof(out_daddr6));
 426                 if (ret)
 427                         error(1, errno, "connect tx");
 428         } else {
 429                 /* otherwise using loopback */
 430                 if (cfg_l3_inner == PF_INET)
 431                         ret = connect(fd, (void *) &in_daddr4,
 432                                       sizeof(in_daddr4));
 433                 else
 434                         ret = connect(fd, (void *) &in_daddr6,
 435                                       sizeof(in_daddr6));
 436                 if (ret)
 437                         error(1, errno, "connect tx");
 438         }
 439 
 440         return fd;
 441 }
 442 
 443 /* receiver reads unencapsulated UDP */
 444 static int setup_rx(void)
 445 {
 446         int fd, ret;
 447 
 448         fd = socket(cfg_l3_inner, SOCK_DGRAM, 0);
 449         if (fd == -1)
 450                 error(1, errno, "socket rx");
 451 
 452         if (cfg_l3_inner == PF_INET)
 453                 ret = bind(fd, (void *) &in_daddr4, sizeof(in_daddr4));
 454         else
 455                 ret = bind(fd, (void *) &in_daddr6, sizeof(in_daddr6));
 456         if (ret)
 457                 error(1, errno, "bind rx");
 458 
 459         return fd;
 460 }
 461 
 462 static int do_tx(int fd, const char *pkt, int len)
 463 {
 464         int ret;
 465 
 466         ret = write(fd, pkt, len);
 467         if (ret == -1)
 468                 error(1, errno, "send");
 469         if (ret != len)
 470                 error(1, errno, "send: len (%d < %d)\n", ret, len);
 471 
 472         return 1;
 473 }
 474 
 475 static int do_poll(int fd, short events, int timeout)
 476 {
 477         struct pollfd pfd;
 478         int ret;
 479 
 480         pfd.fd = fd;
 481         pfd.events = events;
 482 
 483         ret = poll(&pfd, 1, timeout);
 484         if (ret == -1)
 485                 error(1, errno, "poll");
 486         if (ret && !(pfd.revents & POLLIN))
 487                 error(1, errno, "poll: unexpected event 0x%x\n", pfd.revents);
 488 
 489         return ret;
 490 }
 491 
 492 static int do_rx(int fd)
 493 {
 494         char rbuf;
 495         int ret, num = 0;
 496 
 497         while (1) {
 498                 ret = recv(fd, &rbuf, 1, MSG_DONTWAIT);
 499                 if (ret == -1 && errno == EAGAIN)
 500                         break;
 501                 if (ret == -1)
 502                         error(1, errno, "recv");
 503                 if (rbuf != cfg_payload_char)
 504                         error(1, 0, "recv: payload mismatch");
 505                 num++;
 506         };
 507 
 508         return num;
 509 }
 510 
 511 static int do_main(void)
 512 {
 513         unsigned long tstop, treport, tcur;
 514         int fdt = -1, fdr = -1, len, tx = 0, rx = 0;
 515 
 516         if (!cfg_only_tx)
 517                 fdr = setup_rx();
 518         if (!cfg_only_rx)
 519                 fdt = setup_tx();
 520 
 521         len = build_packet();
 522 
 523         tcur = util_gettime();
 524         treport = tcur + 1000;
 525         tstop = tcur + (cfg_num_secs * 1000);
 526 
 527         while (1) {
 528                 if (!cfg_only_rx)
 529                         tx += do_tx(fdt, buf, len);
 530 
 531                 if (!cfg_only_tx)
 532                         rx += do_rx(fdr);
 533 
 534                 if (cfg_num_secs) {
 535                         tcur = util_gettime();
 536                         if (tcur >= tstop)
 537                                 break;
 538                         if (tcur >= treport) {
 539                                 fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx);
 540                                 tx = 0;
 541                                 rx = 0;
 542                                 treport = tcur + 1000;
 543                         }
 544                 } else {
 545                         if (tx == cfg_num_pkt)
 546                                 break;
 547                 }
 548         }
 549 
 550         /* read straggler packets, if any */
 551         if (rx < tx) {
 552                 tstop = util_gettime() + 100;
 553                 while (rx < tx) {
 554                         tcur = util_gettime();
 555                         if (tcur >= tstop)
 556                                 break;
 557 
 558                         do_poll(fdr, POLLIN, tstop - tcur);
 559                         rx += do_rx(fdr);
 560                 }
 561         }
 562 
 563         fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx);
 564 
 565         if (fdr != -1 && close(fdr))
 566                 error(1, errno, "close rx");
 567         if (fdt != -1 && close(fdt))
 568                 error(1, errno, "close tx");
 569 
 570         /*
 571          * success (== 0) only if received all packets
 572          * unless failure is expected, in which case none must arrive.
 573          */
 574         if (cfg_expect_failure)
 575                 return rx != 0;
 576         else
 577                 return rx != tx;
 578 }
 579 
 580 
 581 static void __attribute__((noreturn)) usage(const char *filepath)
 582 {
 583         fprintf(stderr, "Usage: %s [-e gre|gue|bare|none] [-i 4|6] [-l len] "
 584                         "[-O 4|6] [-o 4|6] [-n num] [-t secs] [-R] [-T] "
 585                         "[-s <osrc> [-d <odst>] [-S <isrc>] [-D <idst>] "
 586                         "[-x <otos>] [-X <itos>] [-f <isport>] [-F]\n",
 587                 filepath);
 588         exit(1);
 589 }
 590 
 591 static void parse_addr(int family, void *addr, const char *optarg)
 592 {
 593         int ret;
 594 
 595         ret = inet_pton(family, optarg, addr);
 596         if (ret == -1)
 597                 error(1, errno, "inet_pton");
 598         if (ret == 0)
 599                 error(1, 0, "inet_pton: bad string");
 600 }
 601 
 602 static void parse_addr4(struct sockaddr_in *addr, const char *optarg)
 603 {
 604         parse_addr(AF_INET, &addr->sin_addr, optarg);
 605 }
 606 
 607 static void parse_addr6(struct sockaddr_in6 *addr, const char *optarg)
 608 {
 609         parse_addr(AF_INET6, &addr->sin6_addr, optarg);
 610 }
 611 
 612 static int parse_protocol_family(const char *filepath, const char *optarg)
 613 {
 614         if (!strcmp(optarg, "4"))
 615                 return PF_INET;
 616         if (!strcmp(optarg, "6"))
 617                 return PF_INET6;
 618 
 619         usage(filepath);
 620 }
 621 
 622 static void parse_opts(int argc, char **argv)
 623 {
 624         int c;
 625 
 626         while ((c = getopt(argc, argv, "d:D:e:f:Fhi:l:n:o:O:Rs:S:t:Tx:X:")) != -1) {
 627                 switch (c) {
 628                 case 'd':
 629                         if (cfg_l3_outer == AF_UNSPEC)
 630                                 error(1, 0, "-d must be preceded by -o");
 631                         if (cfg_l3_outer == AF_INET)
 632                                 parse_addr4(&out_daddr4, optarg);
 633                         else
 634                                 parse_addr6(&out_daddr6, optarg);
 635                         break;
 636                 case 'D':
 637                         if (cfg_l3_inner == AF_UNSPEC)
 638                                 error(1, 0, "-D must be preceded by -i");
 639                         if (cfg_l3_inner == AF_INET)
 640                                 parse_addr4(&in_daddr4, optarg);
 641                         else
 642                                 parse_addr6(&in_daddr6, optarg);
 643                         break;
 644                 case 'e':
 645                         if (!strcmp(optarg, "gre"))
 646                                 cfg_encap_proto = IPPROTO_GRE;
 647                         else if (!strcmp(optarg, "gue"))
 648                                 cfg_encap_proto = IPPROTO_UDP;
 649                         else if (!strcmp(optarg, "bare"))
 650                                 cfg_encap_proto = IPPROTO_IPIP;
 651                         else if (!strcmp(optarg, "none"))
 652                                 cfg_encap_proto = IPPROTO_IP;   /* == 0 */
 653                         else
 654                                 usage(argv[0]);
 655                         break;
 656                 case 'f':
 657                         cfg_src_port = strtol(optarg, NULL, 0);
 658                         break;
 659                 case 'F':
 660                         cfg_expect_failure = true;
 661                         break;
 662                 case 'h':
 663                         usage(argv[0]);
 664                         break;
 665                 case 'i':
 666                         if (!strcmp(optarg, "4"))
 667                                 cfg_l3_inner = PF_INET;
 668                         else if (!strcmp(optarg, "6"))
 669                                 cfg_l3_inner = PF_INET6;
 670                         else
 671                                 usage(argv[0]);
 672                         break;
 673                 case 'l':
 674                         cfg_payload_len = strtol(optarg, NULL, 0);
 675                         break;
 676                 case 'n':
 677                         cfg_num_pkt = strtol(optarg, NULL, 0);
 678                         break;
 679                 case 'o':
 680                         cfg_l3_outer = parse_protocol_family(argv[0], optarg);
 681                         break;
 682                 case 'O':
 683                         cfg_l3_extra = parse_protocol_family(argv[0], optarg);
 684                         break;
 685                 case 'R':
 686                         cfg_only_rx = true;
 687                         break;
 688                 case 's':
 689                         if (cfg_l3_outer == AF_INET)
 690                                 parse_addr4(&out_saddr4, optarg);
 691                         else
 692                                 parse_addr6(&out_saddr6, optarg);
 693                         break;
 694                 case 'S':
 695                         if (cfg_l3_inner == AF_INET)
 696                                 parse_addr4(&in_saddr4, optarg);
 697                         else
 698                                 parse_addr6(&in_saddr6, optarg);
 699                         break;
 700                 case 't':
 701                         cfg_num_secs = strtol(optarg, NULL, 0);
 702                         break;
 703                 case 'T':
 704                         cfg_only_tx = true;
 705                         break;
 706                 case 'x':
 707                         cfg_dsfield_outer = strtol(optarg, NULL, 0);
 708                         break;
 709                 case 'X':
 710                         cfg_dsfield_inner = strtol(optarg, NULL, 0);
 711                         break;
 712                 }
 713         }
 714 
 715         if (cfg_only_rx && cfg_only_tx)
 716                 error(1, 0, "options: cannot combine rx-only and tx-only");
 717 
 718         if (cfg_encap_proto && cfg_l3_outer == AF_UNSPEC)
 719                 error(1, 0, "options: must specify outer with encap");
 720         else if ((!cfg_encap_proto) && cfg_l3_outer != AF_UNSPEC)
 721                 error(1, 0, "options: cannot combine no-encap and outer");
 722         else if ((!cfg_encap_proto) && cfg_l3_extra != AF_UNSPEC)
 723                 error(1, 0, "options: cannot combine no-encap and extra");
 724 
 725         if (cfg_l3_inner == AF_UNSPEC)
 726                 cfg_l3_inner = AF_INET6;
 727         if (cfg_l3_inner == AF_INET6 && cfg_encap_proto == IPPROTO_IPIP)
 728                 cfg_encap_proto = IPPROTO_IPV6;
 729 
 730         /* RFC 6040 4.2:
 731          *   on decap, if outer encountered congestion (CE == 0x3),
 732          *   but inner cannot encode ECN (NoECT == 0x0), then drop packet.
 733          */
 734         if (((cfg_dsfield_outer & 0x3) == 0x3) &&
 735             ((cfg_dsfield_inner & 0x3) == 0x0))
 736                 cfg_expect_failure = true;
 737 }
 738 
 739 static void print_opts(void)
 740 {
 741         if (cfg_l3_inner == PF_INET6) {
 742                 util_printaddr("inner.dest6", (void *) &in_daddr6);
 743                 util_printaddr("inner.source6", (void *) &in_saddr6);
 744         } else {
 745                 util_printaddr("inner.dest4", (void *) &in_daddr4);
 746                 util_printaddr("inner.source4", (void *) &in_saddr4);
 747         }
 748 
 749         if (!cfg_l3_outer)
 750                 return;
 751 
 752         fprintf(stderr, "encap proto:   %u\n", cfg_encap_proto);
 753 
 754         if (cfg_l3_outer == PF_INET6) {
 755                 util_printaddr("outer.dest6", (void *) &out_daddr6);
 756                 util_printaddr("outer.source6", (void *) &out_saddr6);
 757         } else {
 758                 util_printaddr("outer.dest4", (void *) &out_daddr4);
 759                 util_printaddr("outer.source4", (void *) &out_saddr4);
 760         }
 761 
 762         if (!cfg_l3_extra)
 763                 return;
 764 
 765         if (cfg_l3_outer == PF_INET6) {
 766                 util_printaddr("extra.dest6", (void *) &extra_daddr6);
 767                 util_printaddr("extra.source6", (void *) &extra_saddr6);
 768         } else {
 769                 util_printaddr("extra.dest4", (void *) &extra_daddr4);
 770                 util_printaddr("extra.source4", (void *) &extra_saddr4);
 771         }
 772 
 773 }
 774 
 775 int main(int argc, char **argv)
 776 {
 777         parse_opts(argc, argv);
 778         print_opts();
 779         return do_main();
 780 }

/* [<][>][^][v][top][bottom][index][help] */