test_flow_dissector.c 18 KB

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