0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define _GNU_SOURCE
0011
0012 #include <stddef.h>
0013 #include <arpa/inet.h>
0014 #include <asm/byteorder.h>
0015 #include <error.h>
0016 #include <errno.h>
0017 #include <linux/if_packet.h>
0018 #include <linux/if_ether.h>
0019 #include <linux/ipv6.h>
0020 #include <netinet/ip.h>
0021 #include <netinet/in.h>
0022 #include <netinet/udp.h>
0023 #include <poll.h>
0024 #include <stdbool.h>
0025 #include <stdlib.h>
0026 #include <stdio.h>
0027 #include <string.h>
0028 #include <sys/ioctl.h>
0029 #include <sys/socket.h>
0030 #include <sys/stat.h>
0031 #include <sys/time.h>
0032 #include <sys/types.h>
0033 #include <unistd.h>
0034
0035 #define CFG_PORT_INNER 8000
0036
0037
0038
0039 struct grehdr {
0040 uint16_t unused;
0041 uint16_t protocol;
0042 } __attribute__((packed));
0043
0044 struct guehdr {
0045 union {
0046 struct {
0047 #if defined(__LITTLE_ENDIAN_BITFIELD)
0048 __u8 hlen:5,
0049 control:1,
0050 version:2;
0051 #elif defined (__BIG_ENDIAN_BITFIELD)
0052 __u8 version:2,
0053 control:1,
0054 hlen:5;
0055 #else
0056 #error "Please fix <asm/byteorder.h>"
0057 #endif
0058 __u8 proto_ctype;
0059 __be16 flags;
0060 };
0061 __be32 word;
0062 };
0063 };
0064
0065 static uint8_t cfg_dsfield_inner;
0066 static uint8_t cfg_dsfield_outer;
0067 static uint8_t cfg_encap_proto;
0068 static bool cfg_expect_failure = false;
0069 static int cfg_l3_extra = AF_UNSPEC;
0070 static int cfg_l3_inner = AF_UNSPEC;
0071 static int cfg_l3_outer = AF_UNSPEC;
0072 static int cfg_num_pkt = 10;
0073 static int cfg_num_secs = 0;
0074 static char cfg_payload_char = 'a';
0075 static int cfg_payload_len = 100;
0076 static int cfg_port_gue = 6080;
0077 static bool cfg_only_rx;
0078 static bool cfg_only_tx;
0079 static int cfg_src_port = 9;
0080
0081 static char buf[ETH_DATA_LEN];
0082
0083 #define INIT_ADDR4(name, addr4, port) \
0084 static struct sockaddr_in name = { \
0085 .sin_family = AF_INET, \
0086 .sin_port = __constant_htons(port), \
0087 .sin_addr.s_addr = __constant_htonl(addr4), \
0088 };
0089
0090 #define INIT_ADDR6(name, addr6, port) \
0091 static struct sockaddr_in6 name = { \
0092 .sin6_family = AF_INET6, \
0093 .sin6_port = __constant_htons(port), \
0094 .sin6_addr = addr6, \
0095 };
0096
0097 INIT_ADDR4(in_daddr4, INADDR_LOOPBACK, CFG_PORT_INNER)
0098 INIT_ADDR4(in_saddr4, INADDR_LOOPBACK + 2, 0)
0099 INIT_ADDR4(out_daddr4, INADDR_LOOPBACK, 0)
0100 INIT_ADDR4(out_saddr4, INADDR_LOOPBACK + 1, 0)
0101 INIT_ADDR4(extra_daddr4, INADDR_LOOPBACK, 0)
0102 INIT_ADDR4(extra_saddr4, INADDR_LOOPBACK + 1, 0)
0103
0104 INIT_ADDR6(in_daddr6, IN6ADDR_LOOPBACK_INIT, CFG_PORT_INNER)
0105 INIT_ADDR6(in_saddr6, IN6ADDR_LOOPBACK_INIT, 0)
0106 INIT_ADDR6(out_daddr6, IN6ADDR_LOOPBACK_INIT, 0)
0107 INIT_ADDR6(out_saddr6, IN6ADDR_LOOPBACK_INIT, 0)
0108 INIT_ADDR6(extra_daddr6, IN6ADDR_LOOPBACK_INIT, 0)
0109 INIT_ADDR6(extra_saddr6, IN6ADDR_LOOPBACK_INIT, 0)
0110
0111 static unsigned long util_gettime(void)
0112 {
0113 struct timeval tv;
0114
0115 gettimeofday(&tv, NULL);
0116 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
0117 }
0118
0119 static void util_printaddr(const char *msg, struct sockaddr *addr)
0120 {
0121 unsigned long off = 0;
0122 char nbuf[INET6_ADDRSTRLEN];
0123
0124 switch (addr->sa_family) {
0125 case PF_INET:
0126 off = __builtin_offsetof(struct sockaddr_in, sin_addr);
0127 break;
0128 case PF_INET6:
0129 off = __builtin_offsetof(struct sockaddr_in6, sin6_addr);
0130 break;
0131 default:
0132 error(1, 0, "printaddr: unsupported family %u\n",
0133 addr->sa_family);
0134 }
0135
0136 if (!inet_ntop(addr->sa_family, ((void *) addr) + off, nbuf,
0137 sizeof(nbuf)))
0138 error(1, errno, "inet_ntop");
0139
0140 fprintf(stderr, "%s: %s\n", msg, nbuf);
0141 }
0142
0143 static unsigned long add_csum_hword(const uint16_t *start, int num_u16)
0144 {
0145 unsigned long sum = 0;
0146 int i;
0147
0148 for (i = 0; i < num_u16; i++)
0149 sum += start[i];
0150
0151 return sum;
0152 }
0153
0154 static uint16_t build_ip_csum(const uint16_t *start, int num_u16,
0155 unsigned long sum)
0156 {
0157 sum += add_csum_hword(start, num_u16);
0158
0159 while (sum >> 16)
0160 sum = (sum & 0xffff) + (sum >> 16);
0161
0162 return ~sum;
0163 }
0164
0165 static void build_ipv4_header(void *header, uint8_t proto,
0166 uint32_t src, uint32_t dst,
0167 int payload_len, uint8_t tos)
0168 {
0169 struct iphdr *iph = header;
0170
0171 iph->ihl = 5;
0172 iph->version = 4;
0173 iph->tos = tos;
0174 iph->ttl = 8;
0175 iph->tot_len = htons(sizeof(*iph) + payload_len);
0176 iph->id = htons(1337);
0177 iph->protocol = proto;
0178 iph->saddr = src;
0179 iph->daddr = dst;
0180 iph->check = build_ip_csum((void *) iph, iph->ihl << 1, 0);
0181 }
0182
0183 static void ipv6_set_dsfield(struct ipv6hdr *ip6h, uint8_t dsfield)
0184 {
0185 uint16_t val, *ptr = (uint16_t *)ip6h;
0186
0187 val = ntohs(*ptr);
0188 val &= 0xF00F;
0189 val |= ((uint16_t) dsfield) << 4;
0190 *ptr = htons(val);
0191 }
0192
0193 static void build_ipv6_header(void *header, uint8_t proto,
0194 struct sockaddr_in6 *src,
0195 struct sockaddr_in6 *dst,
0196 int payload_len, uint8_t dsfield)
0197 {
0198 struct ipv6hdr *ip6h = header;
0199
0200 ip6h->version = 6;
0201 ip6h->payload_len = htons(payload_len);
0202 ip6h->nexthdr = proto;
0203 ip6h->hop_limit = 8;
0204 ipv6_set_dsfield(ip6h, dsfield);
0205
0206 memcpy(&ip6h->saddr, &src->sin6_addr, sizeof(ip6h->saddr));
0207 memcpy(&ip6h->daddr, &dst->sin6_addr, sizeof(ip6h->daddr));
0208 }
0209
0210 static uint16_t build_udp_v4_csum(const struct iphdr *iph,
0211 const struct udphdr *udph,
0212 int num_words)
0213 {
0214 unsigned long pseudo_sum;
0215 int num_u16 = sizeof(iph->saddr);
0216
0217 pseudo_sum = add_csum_hword((void *) &iph->saddr, num_u16);
0218 pseudo_sum += htons(IPPROTO_UDP);
0219 pseudo_sum += udph->len;
0220 return build_ip_csum((void *) udph, num_words, pseudo_sum);
0221 }
0222
0223 static uint16_t build_udp_v6_csum(const struct ipv6hdr *ip6h,
0224 const struct udphdr *udph,
0225 int num_words)
0226 {
0227 unsigned long pseudo_sum;
0228 int num_u16 = sizeof(ip6h->saddr);
0229
0230 pseudo_sum = add_csum_hword((void *) &ip6h->saddr, num_u16);
0231 pseudo_sum += htons(ip6h->nexthdr);
0232 pseudo_sum += ip6h->payload_len;
0233 return build_ip_csum((void *) udph, num_words, pseudo_sum);
0234 }
0235
0236 static void build_udp_header(void *header, int payload_len,
0237 uint16_t dport, int family)
0238 {
0239 struct udphdr *udph = header;
0240 int len = sizeof(*udph) + payload_len;
0241
0242 udph->source = htons(cfg_src_port);
0243 udph->dest = htons(dport);
0244 udph->len = htons(len);
0245 udph->check = 0;
0246 if (family == AF_INET)
0247 udph->check = build_udp_v4_csum(header - sizeof(struct iphdr),
0248 udph, len >> 1);
0249 else
0250 udph->check = build_udp_v6_csum(header - sizeof(struct ipv6hdr),
0251 udph, len >> 1);
0252 }
0253
0254 static void build_gue_header(void *header, uint8_t proto)
0255 {
0256 struct guehdr *gueh = header;
0257
0258 gueh->proto_ctype = proto;
0259 }
0260
0261 static void build_gre_header(void *header, uint16_t proto)
0262 {
0263 struct grehdr *greh = header;
0264
0265 greh->protocol = htons(proto);
0266 }
0267
0268 static int l3_length(int family)
0269 {
0270 if (family == AF_INET)
0271 return sizeof(struct iphdr);
0272 else
0273 return sizeof(struct ipv6hdr);
0274 }
0275
0276 static int build_packet(void)
0277 {
0278 int ol3_len = 0, ol4_len = 0, il3_len = 0, il4_len = 0;
0279 int el3_len = 0;
0280
0281 if (cfg_l3_extra)
0282 el3_len = l3_length(cfg_l3_extra);
0283
0284
0285 if (cfg_encap_proto) {
0286 ol3_len = l3_length(cfg_l3_outer);
0287
0288 if (cfg_encap_proto == IPPROTO_GRE)
0289 ol4_len = sizeof(struct grehdr);
0290 else if (cfg_encap_proto == IPPROTO_UDP)
0291 ol4_len = sizeof(struct udphdr) + sizeof(struct guehdr);
0292 }
0293
0294 il3_len = l3_length(cfg_l3_inner);
0295 il4_len = sizeof(struct udphdr);
0296
0297 if (el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len >=
0298 sizeof(buf))
0299 error(1, 0, "packet too large\n");
0300
0301
0302
0303
0304
0305 memset(buf + el3_len + ol3_len + ol4_len + il3_len + il4_len,
0306 cfg_payload_char, cfg_payload_len);
0307
0308
0309 buf[el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len] = 0;
0310
0311 switch (cfg_l3_inner) {
0312 case PF_INET:
0313 build_ipv4_header(buf + el3_len + ol3_len + ol4_len,
0314 IPPROTO_UDP,
0315 in_saddr4.sin_addr.s_addr,
0316 in_daddr4.sin_addr.s_addr,
0317 il4_len + cfg_payload_len,
0318 cfg_dsfield_inner);
0319 break;
0320 case PF_INET6:
0321 build_ipv6_header(buf + el3_len + ol3_len + ol4_len,
0322 IPPROTO_UDP,
0323 &in_saddr6, &in_daddr6,
0324 il4_len + cfg_payload_len,
0325 cfg_dsfield_inner);
0326 break;
0327 }
0328
0329 build_udp_header(buf + el3_len + ol3_len + ol4_len + il3_len,
0330 cfg_payload_len, CFG_PORT_INNER, cfg_l3_inner);
0331
0332 if (!cfg_encap_proto)
0333 return il3_len + il4_len + cfg_payload_len;
0334
0335 switch (cfg_l3_outer) {
0336 case PF_INET:
0337 build_ipv4_header(buf + el3_len, cfg_encap_proto,
0338 out_saddr4.sin_addr.s_addr,
0339 out_daddr4.sin_addr.s_addr,
0340 ol4_len + il3_len + il4_len + cfg_payload_len,
0341 cfg_dsfield_outer);
0342 break;
0343 case PF_INET6:
0344 build_ipv6_header(buf + el3_len, cfg_encap_proto,
0345 &out_saddr6, &out_daddr6,
0346 ol4_len + il3_len + il4_len + cfg_payload_len,
0347 cfg_dsfield_outer);
0348 break;
0349 }
0350
0351 switch (cfg_encap_proto) {
0352 case IPPROTO_UDP:
0353 build_gue_header(buf + el3_len + ol3_len + ol4_len -
0354 sizeof(struct guehdr),
0355 cfg_l3_inner == PF_INET ? IPPROTO_IPIP
0356 : IPPROTO_IPV6);
0357 build_udp_header(buf + el3_len + ol3_len,
0358 sizeof(struct guehdr) + il3_len + il4_len +
0359 cfg_payload_len,
0360 cfg_port_gue, cfg_l3_outer);
0361 break;
0362 case IPPROTO_GRE:
0363 build_gre_header(buf + el3_len + ol3_len,
0364 cfg_l3_inner == PF_INET ? ETH_P_IP
0365 : ETH_P_IPV6);
0366 break;
0367 }
0368
0369 switch (cfg_l3_extra) {
0370 case PF_INET:
0371 build_ipv4_header(buf,
0372 cfg_l3_outer == PF_INET ? IPPROTO_IPIP
0373 : IPPROTO_IPV6,
0374 extra_saddr4.sin_addr.s_addr,
0375 extra_daddr4.sin_addr.s_addr,
0376 ol3_len + ol4_len + il3_len + il4_len +
0377 cfg_payload_len, 0);
0378 break;
0379 case PF_INET6:
0380 build_ipv6_header(buf,
0381 cfg_l3_outer == PF_INET ? IPPROTO_IPIP
0382 : IPPROTO_IPV6,
0383 &extra_saddr6, &extra_daddr6,
0384 ol3_len + ol4_len + il3_len + il4_len +
0385 cfg_payload_len, 0);
0386 break;
0387 }
0388
0389 return el3_len + ol3_len + ol4_len + il3_len + il4_len +
0390 cfg_payload_len;
0391 }
0392
0393
0394 static int setup_tx(void)
0395 {
0396 int family, fd, ret;
0397
0398 if (cfg_l3_extra)
0399 family = cfg_l3_extra;
0400 else if (cfg_l3_outer)
0401 family = cfg_l3_outer;
0402 else
0403 family = cfg_l3_inner;
0404
0405 fd = socket(family, SOCK_RAW, IPPROTO_RAW);
0406 if (fd == -1)
0407 error(1, errno, "socket tx");
0408
0409 if (cfg_l3_extra) {
0410 if (cfg_l3_extra == PF_INET)
0411 ret = connect(fd, (void *) &extra_daddr4,
0412 sizeof(extra_daddr4));
0413 else
0414 ret = connect(fd, (void *) &extra_daddr6,
0415 sizeof(extra_daddr6));
0416 if (ret)
0417 error(1, errno, "connect tx");
0418 } else if (cfg_l3_outer) {
0419
0420 if (cfg_l3_outer == PF_INET)
0421 ret = connect(fd, (void *) &out_daddr4,
0422 sizeof(out_daddr4));
0423 else
0424 ret = connect(fd, (void *) &out_daddr6,
0425 sizeof(out_daddr6));
0426 if (ret)
0427 error(1, errno, "connect tx");
0428 } else {
0429
0430 if (cfg_l3_inner == PF_INET)
0431 ret = connect(fd, (void *) &in_daddr4,
0432 sizeof(in_daddr4));
0433 else
0434 ret = connect(fd, (void *) &in_daddr6,
0435 sizeof(in_daddr6));
0436 if (ret)
0437 error(1, errno, "connect tx");
0438 }
0439
0440 return fd;
0441 }
0442
0443
0444 static int setup_rx(void)
0445 {
0446 int fd, ret;
0447
0448 fd = socket(cfg_l3_inner, SOCK_DGRAM, 0);
0449 if (fd == -1)
0450 error(1, errno, "socket rx");
0451
0452 if (cfg_l3_inner == PF_INET)
0453 ret = bind(fd, (void *) &in_daddr4, sizeof(in_daddr4));
0454 else
0455 ret = bind(fd, (void *) &in_daddr6, sizeof(in_daddr6));
0456 if (ret)
0457 error(1, errno, "bind rx");
0458
0459 return fd;
0460 }
0461
0462 static int do_tx(int fd, const char *pkt, int len)
0463 {
0464 int ret;
0465
0466 ret = write(fd, pkt, len);
0467 if (ret == -1)
0468 error(1, errno, "send");
0469 if (ret != len)
0470 error(1, errno, "send: len (%d < %d)\n", ret, len);
0471
0472 return 1;
0473 }
0474
0475 static int do_poll(int fd, short events, int timeout)
0476 {
0477 struct pollfd pfd;
0478 int ret;
0479
0480 pfd.fd = fd;
0481 pfd.events = events;
0482
0483 ret = poll(&pfd, 1, timeout);
0484 if (ret == -1)
0485 error(1, errno, "poll");
0486 if (ret && !(pfd.revents & POLLIN))
0487 error(1, errno, "poll: unexpected event 0x%x\n", pfd.revents);
0488
0489 return ret;
0490 }
0491
0492 static int do_rx(int fd)
0493 {
0494 char rbuf;
0495 int ret, num = 0;
0496
0497 while (1) {
0498 ret = recv(fd, &rbuf, 1, MSG_DONTWAIT);
0499 if (ret == -1 && errno == EAGAIN)
0500 break;
0501 if (ret == -1)
0502 error(1, errno, "recv");
0503 if (rbuf != cfg_payload_char)
0504 error(1, 0, "recv: payload mismatch");
0505 num++;
0506 }
0507
0508 return num;
0509 }
0510
0511 static int do_main(void)
0512 {
0513 unsigned long tstop, treport, tcur;
0514 int fdt = -1, fdr = -1, len, tx = 0, rx = 0;
0515
0516 if (!cfg_only_tx)
0517 fdr = setup_rx();
0518 if (!cfg_only_rx)
0519 fdt = setup_tx();
0520
0521 len = build_packet();
0522
0523 tcur = util_gettime();
0524 treport = tcur + 1000;
0525 tstop = tcur + (cfg_num_secs * 1000);
0526
0527 while (1) {
0528 if (!cfg_only_rx)
0529 tx += do_tx(fdt, buf, len);
0530
0531 if (!cfg_only_tx)
0532 rx += do_rx(fdr);
0533
0534 if (cfg_num_secs) {
0535 tcur = util_gettime();
0536 if (tcur >= tstop)
0537 break;
0538 if (tcur >= treport) {
0539 fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx);
0540 tx = 0;
0541 rx = 0;
0542 treport = tcur + 1000;
0543 }
0544 } else {
0545 if (tx == cfg_num_pkt)
0546 break;
0547 }
0548 }
0549
0550
0551 if (rx < tx) {
0552 tstop = util_gettime() + 100;
0553 while (rx < tx) {
0554 tcur = util_gettime();
0555 if (tcur >= tstop)
0556 break;
0557
0558 do_poll(fdr, POLLIN, tstop - tcur);
0559 rx += do_rx(fdr);
0560 }
0561 }
0562
0563 fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx);
0564
0565 if (fdr != -1 && close(fdr))
0566 error(1, errno, "close rx");
0567 if (fdt != -1 && close(fdt))
0568 error(1, errno, "close tx");
0569
0570
0571
0572
0573
0574 if (cfg_expect_failure)
0575 return rx != 0;
0576 else
0577 return rx != tx;
0578 }
0579
0580
0581 static void __attribute__((noreturn)) usage(const char *filepath)
0582 {
0583 fprintf(stderr, "Usage: %s [-e gre|gue|bare|none] [-i 4|6] [-l len] "
0584 "[-O 4|6] [-o 4|6] [-n num] [-t secs] [-R] [-T] "
0585 "[-s <osrc> [-d <odst>] [-S <isrc>] [-D <idst>] "
0586 "[-x <otos>] [-X <itos>] [-f <isport>] [-F]\n",
0587 filepath);
0588 exit(1);
0589 }
0590
0591 static void parse_addr(int family, void *addr, const char *optarg)
0592 {
0593 int ret;
0594
0595 ret = inet_pton(family, optarg, addr);
0596 if (ret == -1)
0597 error(1, errno, "inet_pton");
0598 if (ret == 0)
0599 error(1, 0, "inet_pton: bad string");
0600 }
0601
0602 static void parse_addr4(struct sockaddr_in *addr, const char *optarg)
0603 {
0604 parse_addr(AF_INET, &addr->sin_addr, optarg);
0605 }
0606
0607 static void parse_addr6(struct sockaddr_in6 *addr, const char *optarg)
0608 {
0609 parse_addr(AF_INET6, &addr->sin6_addr, optarg);
0610 }
0611
0612 static int parse_protocol_family(const char *filepath, const char *optarg)
0613 {
0614 if (!strcmp(optarg, "4"))
0615 return PF_INET;
0616 if (!strcmp(optarg, "6"))
0617 return PF_INET6;
0618
0619 usage(filepath);
0620 }
0621
0622 static void parse_opts(int argc, char **argv)
0623 {
0624 int c;
0625
0626 while ((c = getopt(argc, argv, "d:D:e:f:Fhi:l:n:o:O:Rs:S:t:Tx:X:")) != -1) {
0627 switch (c) {
0628 case 'd':
0629 if (cfg_l3_outer == AF_UNSPEC)
0630 error(1, 0, "-d must be preceded by -o");
0631 if (cfg_l3_outer == AF_INET)
0632 parse_addr4(&out_daddr4, optarg);
0633 else
0634 parse_addr6(&out_daddr6, optarg);
0635 break;
0636 case 'D':
0637 if (cfg_l3_inner == AF_UNSPEC)
0638 error(1, 0, "-D must be preceded by -i");
0639 if (cfg_l3_inner == AF_INET)
0640 parse_addr4(&in_daddr4, optarg);
0641 else
0642 parse_addr6(&in_daddr6, optarg);
0643 break;
0644 case 'e':
0645 if (!strcmp(optarg, "gre"))
0646 cfg_encap_proto = IPPROTO_GRE;
0647 else if (!strcmp(optarg, "gue"))
0648 cfg_encap_proto = IPPROTO_UDP;
0649 else if (!strcmp(optarg, "bare"))
0650 cfg_encap_proto = IPPROTO_IPIP;
0651 else if (!strcmp(optarg, "none"))
0652 cfg_encap_proto = IPPROTO_IP;
0653 else
0654 usage(argv[0]);
0655 break;
0656 case 'f':
0657 cfg_src_port = strtol(optarg, NULL, 0);
0658 break;
0659 case 'F':
0660 cfg_expect_failure = true;
0661 break;
0662 case 'h':
0663 usage(argv[0]);
0664 break;
0665 case 'i':
0666 if (!strcmp(optarg, "4"))
0667 cfg_l3_inner = PF_INET;
0668 else if (!strcmp(optarg, "6"))
0669 cfg_l3_inner = PF_INET6;
0670 else
0671 usage(argv[0]);
0672 break;
0673 case 'l':
0674 cfg_payload_len = strtol(optarg, NULL, 0);
0675 break;
0676 case 'n':
0677 cfg_num_pkt = strtol(optarg, NULL, 0);
0678 break;
0679 case 'o':
0680 cfg_l3_outer = parse_protocol_family(argv[0], optarg);
0681 break;
0682 case 'O':
0683 cfg_l3_extra = parse_protocol_family(argv[0], optarg);
0684 break;
0685 case 'R':
0686 cfg_only_rx = true;
0687 break;
0688 case 's':
0689 if (cfg_l3_outer == AF_INET)
0690 parse_addr4(&out_saddr4, optarg);
0691 else
0692 parse_addr6(&out_saddr6, optarg);
0693 break;
0694 case 'S':
0695 if (cfg_l3_inner == AF_INET)
0696 parse_addr4(&in_saddr4, optarg);
0697 else
0698 parse_addr6(&in_saddr6, optarg);
0699 break;
0700 case 't':
0701 cfg_num_secs = strtol(optarg, NULL, 0);
0702 break;
0703 case 'T':
0704 cfg_only_tx = true;
0705 break;
0706 case 'x':
0707 cfg_dsfield_outer = strtol(optarg, NULL, 0);
0708 break;
0709 case 'X':
0710 cfg_dsfield_inner = strtol(optarg, NULL, 0);
0711 break;
0712 }
0713 }
0714
0715 if (cfg_only_rx && cfg_only_tx)
0716 error(1, 0, "options: cannot combine rx-only and tx-only");
0717
0718 if (cfg_encap_proto && cfg_l3_outer == AF_UNSPEC)
0719 error(1, 0, "options: must specify outer with encap");
0720 else if ((!cfg_encap_proto) && cfg_l3_outer != AF_UNSPEC)
0721 error(1, 0, "options: cannot combine no-encap and outer");
0722 else if ((!cfg_encap_proto) && cfg_l3_extra != AF_UNSPEC)
0723 error(1, 0, "options: cannot combine no-encap and extra");
0724
0725 if (cfg_l3_inner == AF_UNSPEC)
0726 cfg_l3_inner = AF_INET6;
0727 if (cfg_l3_inner == AF_INET6 && cfg_encap_proto == IPPROTO_IPIP)
0728 cfg_encap_proto = IPPROTO_IPV6;
0729
0730
0731
0732
0733
0734 if (((cfg_dsfield_outer & 0x3) == 0x3) &&
0735 ((cfg_dsfield_inner & 0x3) == 0x0))
0736 cfg_expect_failure = true;
0737 }
0738
0739 static void print_opts(void)
0740 {
0741 if (cfg_l3_inner == PF_INET6) {
0742 util_printaddr("inner.dest6", (void *) &in_daddr6);
0743 util_printaddr("inner.source6", (void *) &in_saddr6);
0744 } else {
0745 util_printaddr("inner.dest4", (void *) &in_daddr4);
0746 util_printaddr("inner.source4", (void *) &in_saddr4);
0747 }
0748
0749 if (!cfg_l3_outer)
0750 return;
0751
0752 fprintf(stderr, "encap proto: %u\n", cfg_encap_proto);
0753
0754 if (cfg_l3_outer == PF_INET6) {
0755 util_printaddr("outer.dest6", (void *) &out_daddr6);
0756 util_printaddr("outer.source6", (void *) &out_saddr6);
0757 } else {
0758 util_printaddr("outer.dest4", (void *) &out_daddr4);
0759 util_printaddr("outer.source4", (void *) &out_saddr4);
0760 }
0761
0762 if (!cfg_l3_extra)
0763 return;
0764
0765 if (cfg_l3_outer == PF_INET6) {
0766 util_printaddr("extra.dest6", (void *) &extra_daddr6);
0767 util_printaddr("extra.source6", (void *) &extra_saddr6);
0768 } else {
0769 util_printaddr("extra.dest4", (void *) &extra_daddr4);
0770 util_printaddr("extra.source4", (void *) &extra_saddr4);
0771 }
0772
0773 }
0774
0775 int main(int argc, char **argv)
0776 {
0777 parse_opts(argc, argv);
0778 print_opts();
0779 return do_main();
0780 }