~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/test_flow_dissector.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 }
781 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php