1 /* $OpenBSD: print-gre.c,v 1.35 2024/05/21 05:00:48 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * tcpdump filter for GRE - Generic Routing Encapsulation
31 * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE)
32 */
33
34 #include <sys/time.h>
35 #include <sys/uio.h>
36 #include <sys/socket.h>
37
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40 #include <arpa/inet.h>
41
42 #include <net/ethertypes.h>
43
44 #include <stdio.h>
45 #include <string.h>
46
47 #include "interface.h"
48 #include "addrtoname.h"
49 #include "extract.h"
50
51 #define GRE_CP 0x8000 /* checksum present */
52 #define GRE_RP 0x4000 /* routing present */
53 #define GRE_KP 0x2000 /* key present */
54 #define GRE_SP 0x1000 /* sequence# present */
55 #define GRE_sP 0x0800 /* source routing */
56 #define GRE_RECRS 0x0700 /* recursion count */
57 #define GRE_AP 0x0080 /* acknowledgment# present */
58 #define GRE_VERS 0x0007 /* protocol version */
59
60 /* source route entry types */
61 #define GRESRE_IP 0x0800 /* IP */
62 #define GRESRE_ASN 0xfffe /* ASN */
63
64 #define NVGRE_VSID_MASK 0xffffff00U
65 #define NVGRE_VSID_SHIFT 8
66 #define NVGRE_FLOWID_MASK 0x000000ffU
67 #define NVGRE_FLOWID_SHIFT 0
68
69 #define GRE_WCCP 0x883e
70 #define ERSPAN_II 0x88be
71 #define ERSPAN_III 0x22eb
72
73 struct wccp_redirect {
74 uint8_t flags;
75 #define WCCP_D (1 << 7)
76 #define WCCP_A (1 << 6)
77 uint8_t ServiceId;
78 uint8_t AltBucket;
79 uint8_t PriBucket;
80 };
81
82 void gre_print_0(const u_char *, u_int);
83 void gre_print_1(const u_char *, u_int);
84 void gre_print_pptp(const u_char *, u_int, uint16_t);
85 void gre_print_eoip(const u_char *, u_int, uint16_t);
86 void gre_print_erspan(uint16_t, const u_char *, u_int);
87 void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int);
88 void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int);
89 void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int);
90
91 void
gre_print(const u_char * p,u_int length)92 gre_print(const u_char *p, u_int length)
93 {
94 uint16_t vers;
95 int l;
96
97 l = snapend - p;
98
99 if (l < sizeof(vers)) {
100 printf("[|gre]");
101 return;
102 }
103 vers = EXTRACT_16BITS(p) & GRE_VERS;
104
105 switch (vers) {
106 case 0:
107 gre_print_0(p, length);
108 break;
109 case 1:
110 gre_print_1(p, length);
111 break;
112 default:
113 printf("gre-unknown-version=%u", vers);
114 break;
115 }
116 }
117
118 void
gre_print_0(const u_char * p,u_int length)119 gre_print_0(const u_char *p, u_int length)
120 {
121 uint16_t flags, proto;
122 u_int l;
123
124 l = snapend - p;
125
126 flags = EXTRACT_16BITS(p);
127 p += sizeof(flags);
128 l -= sizeof(flags);
129 length -= sizeof(flags);
130
131 printf("gre");
132
133 if (vflag) {
134 printf(" [%s%s%s%s%s]",
135 (flags & GRE_CP) ? "C" : "",
136 (flags & GRE_RP) ? "R" : "",
137 (flags & GRE_KP) ? "K" : "",
138 (flags & GRE_SP) ? "S" : "",
139 (flags & GRE_sP) ? "s" : "");
140 }
141
142 if (l < sizeof(proto))
143 goto trunc;
144 proto = EXTRACT_16BITS(p);
145 p += sizeof(proto);
146 l -= sizeof(proto);
147 length -= sizeof(proto);
148
149 if (vflag)
150 printf(" %04x", proto);
151
152 if ((flags & GRE_CP) | (flags & GRE_RP)) {
153 if (l < 2)
154 goto trunc;
155 if ((flags & GRE_CP) && vflag)
156 printf(" sum 0x%x", EXTRACT_16BITS(p));
157 p += 2;
158 l -= 2;
159 length -= 2;
160
161 if (l < 2)
162 goto trunc;
163 if (flags & GRE_RP)
164 printf(" off 0x%x", EXTRACT_16BITS(p));
165 p += 2;
166 l -= 2;
167 length -= 2;
168 }
169
170 if (flags & GRE_KP) {
171 uint32_t key, vsid;
172
173 if (l < sizeof(key))
174 goto trunc;
175 key = EXTRACT_32BITS(p);
176 p += sizeof(key);
177 l -= sizeof(key);
178 length -= sizeof(key);
179
180 /* maybe NVGRE, or key entropy? */
181 vsid = (key & NVGRE_VSID_MASK) >> NVGRE_VSID_SHIFT;
182 printf(" key=%u|%u+%02x", key, vsid,
183 (key & NVGRE_FLOWID_MASK) >> NVGRE_FLOWID_SHIFT);
184 }
185
186 if (flags & GRE_SP) {
187 if (l < 4)
188 goto trunc;
189 printf(" seq %u", EXTRACT_32BITS(p));
190 p += 4;
191 l -= 4;
192 length -= 4;
193 }
194
195 if (flags & GRE_RP) {
196 for (;;) {
197 u_int16_t af;
198 u_int8_t sreoff;
199 u_int8_t srelen;
200
201 if (l < 4)
202 goto trunc;
203 af = EXTRACT_16BITS(p);
204 sreoff = *(p + 2);
205 srelen = *(p + 3);
206 p += 4;
207 l -= 4;
208 length -= 4;
209
210 if (af == 0 && srelen == 0)
211 break;
212
213 gre_sre_print(af, sreoff, srelen, p, l);
214
215 if (l < srelen)
216 goto trunc;
217 p += srelen;
218 l -= srelen;
219 length -= srelen;
220 }
221 }
222
223 printf(" ");
224
225 switch (packettype) {
226 case PT_ERSPAN:
227 gre_print_erspan(flags, p, length);
228 return;
229 default:
230 break;
231 }
232
233 switch (proto) {
234 case 0:
235 printf("keep-alive");
236 break;
237 case GRE_WCCP: {
238 printf("wccp ");
239
240 if (l == 0)
241 return;
242
243 if (*p >> 4 != 4) {
244 struct wccp_redirect *wccp;
245
246 if (l < sizeof(*wccp)) {
247 printf("[|wccp]");
248 return;
249 }
250
251 wccp = (struct wccp_redirect *)p;
252
253 printf("D:%c A:%c SId:%u Alt:%u Pri:%u",
254 (wccp->flags & WCCP_D) ? '1' : '0',
255 (wccp->flags & WCCP_A) ? '1' : '0',
256 wccp->ServiceId, wccp->AltBucket, wccp->PriBucket);
257
258 p += sizeof(*wccp);
259 l -= sizeof(*wccp);
260
261 printf(": ");
262 }
263
264 /* FALLTHROUGH */
265 }
266 case ETHERTYPE_IP:
267 ip_print(p, length);
268 break;
269 case ETHERTYPE_IPV6:
270 ip6_print(p, length);
271 break;
272 case ETHERTYPE_MPLS:
273 case ETHERTYPE_MPLS_MCAST:
274 mpls_print(p, length);
275 break;
276 case ETHERTYPE_TRANSETHER:
277 ether_tryprint(p, length, 0);
278 break;
279 #ifndef ETHERTYPE_NSH
280 #define ETHERTYPE_NSH 0x894f
281 #endif
282 case ETHERTYPE_NSH:
283 nsh_print(p, length);
284 break;
285 case ERSPAN_II:
286 gre_print_erspan(flags, p, length);
287 break;
288 case 0x2000:
289 cdp_print(p, length, l, 0);
290 break;
291 #ifndef ETHERTYPE_NHRP
292 #define ETHERTYPE_NHRP 0x2001
293 #endif
294 case ETHERTYPE_NHRP:
295 nhrp_print(p, length);
296 break;
297 default:
298 printf("unknown-proto-%04x", proto);
299 }
300 return;
301
302 trunc:
303 printf("[|gre]");
304 }
305
306 void
gre_print_1(const u_char * p,u_int length)307 gre_print_1(const u_char *p, u_int length)
308 {
309 uint16_t flags, proto;
310 int l;
311
312 l = snapend - p;
313
314 flags = EXTRACT_16BITS(p);
315 p += sizeof(flags);
316 l -= sizeof(flags);
317 length -= sizeof(flags);
318
319 if (l < sizeof(proto))
320 goto trunc;
321
322 proto = EXTRACT_16BITS(p);
323 p += sizeof(proto);
324 l -= sizeof(proto);
325 length -= sizeof(proto);
326
327 switch (proto) {
328 case ETHERTYPE_PPP:
329 gre_print_pptp(p, length, flags);
330 break;
331 case 0x6400:
332 /* MikroTik RouterBoard Ethernet over IP (EoIP) */
333 gre_print_eoip(p, length, flags);
334 break;
335 default:
336 printf("unknown-gre1-proto-%04x", proto);
337 break;
338 }
339
340 return;
341
342 trunc:
343 printf("[|gre1]");
344 }
345
346 void
gre_print_pptp(const u_char * p,u_int length,uint16_t flags)347 gre_print_pptp(const u_char *p, u_int length, uint16_t flags)
348 {
349 uint16_t len;
350 int l;
351
352 l = snapend - p;
353
354 printf("pptp");
355
356 if (vflag) {
357 printf(" [%s%s%s%s%s%s]",
358 (flags & GRE_CP) ? "C" : "",
359 (flags & GRE_RP) ? "R" : "",
360 (flags & GRE_KP) ? "K" : "",
361 (flags & GRE_SP) ? "S" : "",
362 (flags & GRE_sP) ? "s" : "",
363 (flags & GRE_AP) ? "A" : "");
364 }
365
366 if (flags & GRE_CP) {
367 printf(" cpset!");
368 return;
369 }
370 if (flags & GRE_RP) {
371 printf(" rpset!");
372 return;
373 }
374 if ((flags & GRE_KP) == 0) {
375 printf(" kpunset!");
376 return;
377 }
378 if (flags & GRE_sP) {
379 printf(" spset!");
380 return;
381 }
382
383 /* GRE_KP */
384 if (l < sizeof(len))
385 goto trunc;
386 len = EXTRACT_16BITS(p);
387 p += sizeof(len);
388 l -= sizeof(len);
389 length -= sizeof(len);
390
391 if (vflag)
392 printf(" len %u", EXTRACT_16BITS(p));
393
394 if (l < 2)
395 goto trunc;
396 printf(" callid %u", EXTRACT_16BITS(p));
397 p += 2;
398 l -= 2;
399 length -= 2;
400
401 if (flags & GRE_SP) {
402 if (l < 4)
403 goto trunc;
404 printf(" seq %u", EXTRACT_32BITS(p));
405 p += 4;
406 l -= 4;
407 length -= 4;
408 }
409
410 if (flags & GRE_AP) {
411 if (l < 4)
412 goto trunc;
413 printf(" ack %u", EXTRACT_32BITS(p));
414 p += 4;
415 l -= 4;
416 length -= 4;
417 }
418
419 if ((flags & GRE_SP) == 0)
420 return;
421
422 if (length < len) {
423 printf(" truncated-pptp - %d bytes missing!",
424 len - length);
425 len = length;
426 }
427
428 printf(": ");
429
430 ppp_hdlc_print(p, len);
431 return;
432
433 trunc:
434 printf("[|pptp]");
435 }
436
437 void
gre_print_eoip(const u_char * p,u_int length,uint16_t flags)438 gre_print_eoip(const u_char *p, u_int length, uint16_t flags)
439 {
440 uint16_t len, id;
441 int l;
442
443 l = snapend - p;
444
445 printf("eoip");
446
447 flags &= ~GRE_VERS;
448 if (flags != GRE_KP) {
449 printf(" unknown-eoip-flags-%04x!", flags);
450 return;
451 }
452
453 if (l < sizeof(len))
454 goto trunc;
455
456 len = EXTRACT_16BITS(p);
457 p += sizeof(len);
458 l -= sizeof(len);
459 length -= sizeof(len);
460
461 if (l < sizeof(id))
462 goto trunc;
463
464 id = EXTRACT_LE_16BITS(p);
465 p += sizeof(id);
466 l -= sizeof(id);
467 length -= sizeof(id);
468
469 if (vflag)
470 printf(" len=%u tunnel-id=%u", len, id);
471 else
472 printf(" %u", id);
473
474 if (length < len) {
475 printf(" truncated-eoip - %d bytes missing!",
476 len - length);
477 len = length;
478 }
479
480 printf(": ");
481
482 if (len == 0)
483 printf("keepalive");
484 else
485 ether_tryprint(p, len, 0);
486
487 return;
488
489 trunc:
490 printf("[|eoip]");
491 }
492
493 #define ERSPAN2_VER_SHIFT 28
494 #define ERSPAN2_VER_MASK (0xfU << ERSPAN2_VER_SHIFT)
495 #define ERSPAN2_VER (0x1U << ERSPAN2_VER_SHIFT)
496 #define ERSPAN2_VLAN_SHIFT 16
497 #define ERSPAN2_VLAN_MASK (0xfffU << ERSPAN2_VLAN_SHIFT)
498 #define ERSPAN2_COS_SHIFT 13
499 #define ERSPAN2_COS_MASK (0x7U << ERSPAN2_COS_SHIFT)
500 #define ERSPAN2_EN_SHIFT 11
501 #define ERSPAN2_EN_MASK (0x3U << ERSPAN2_EN_SHIFT)
502 #define ERSPAN2_EN_NONE (0x0U << ERSPAN2_EN_SHIFT)
503 #define ERSPAN2_EN_ISL (0x1U << ERSPAN2_EN_SHIFT)
504 #define ERSPAN2_EN_DOT1Q (0x2U << ERSPAN2_EN_SHIFT)
505 #define ERSPAN2_EN_VLAN (0x3U << ERSPAN2_EN_SHIFT)
506 #define ERSPAN2_T_SHIFT 10
507 #define ERSPAN2_T_MASK (0x1U << ERSPAN2_T_SHIFT)
508 #define ERSPAN2_SID_SHIFT 0
509 #define ERSPAN2_SID_MASK (0x3ffU << ERSPAN2_SID_SHIFT)
510
511 #define ERSPAN2_INDEX_SHIFT 0
512 #define ERSPAN2_INDEX_MASK (0xfffffU << ERSPAN2_INDEX_SHIFT)
513
514 void
gre_print_erspan(uint16_t flags,const u_char * bp,u_int len)515 gre_print_erspan(uint16_t flags, const u_char *bp, u_int len)
516 {
517 uint32_t hdr, ver, vlan, cos, en, sid, index;
518 u_int l;
519
520 printf("erspan");
521
522 if (!(flags & GRE_SP)) {
523 printf(" I: ");
524 ether_tryprint(bp, len, 0);
525 return;
526 }
527
528 l = snapend - bp;
529 if (l < sizeof(hdr))
530 goto trunc;
531
532 hdr = EXTRACT_32BITS(bp);
533 bp += sizeof(hdr);
534 l -= sizeof(hdr);
535 len -= sizeof(hdr);
536
537 ver = hdr & ERSPAN2_VER_MASK;
538 if (ver != ERSPAN2_VER) {
539 ver >>= ERSPAN2_VER_SHIFT;
540 printf(" erspan-unknown-version-%x", ver);
541 return;
542 }
543
544 if (vflag)
545 printf(" II");
546
547 sid = (hdr & ERSPAN2_SID_MASK) >> ERSPAN2_SID_SHIFT;
548 printf(" session %u", sid);
549
550 en = hdr & ERSPAN2_EN_MASK;
551 vlan = (hdr & ERSPAN2_VLAN_MASK) >> ERSPAN2_VLAN_SHIFT;
552 switch (en) {
553 case ERSPAN2_EN_NONE:
554 break;
555 case ERSPAN2_EN_ISL:
556 printf(" isl %u", vlan);
557 break;
558 case ERSPAN2_EN_DOT1Q:
559 printf(" vlan %u", vlan);
560 break;
561 case ERSPAN2_EN_VLAN:
562 printf(" vlan payload");
563 break;
564 }
565
566 if (vflag) {
567 cos = (hdr & ERSPAN2_COS_MASK) >> ERSPAN2_COS_SHIFT;
568 printf(" cos %u", cos);
569
570 if (hdr & ERSPAN2_T_MASK)
571 printf(" truncated");
572 }
573
574 if (l < sizeof(hdr))
575 goto trunc;
576
577 hdr = EXTRACT_32BITS(bp);
578 bp += sizeof(hdr);
579 l -= sizeof(hdr);
580 len -= sizeof(hdr);
581
582 if (vflag) {
583 index = (hdr & ERSPAN2_INDEX_MASK) >> ERSPAN2_INDEX_SHIFT;
584 printf(" index %u", index);
585 }
586
587 printf(": ");
588 ether_tryprint(bp, len, 0);
589 return;
590
591 trunc:
592 printf(" [|erspan]");
593 }
594
595 void
gre_sre_print(u_int16_t af,u_int8_t sreoff,u_int8_t srelen,const u_char * bp,u_int len)596 gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen,
597 const u_char *bp, u_int len)
598 {
599 switch (af) {
600 case GRESRE_IP:
601 printf(" (rtaf=ip");
602 gre_sre_ip_print(sreoff, srelen, bp, len);
603 printf(")");
604 break;
605 case GRESRE_ASN:
606 printf(" (rtaf=asn");
607 gre_sre_asn_print(sreoff, srelen, bp, len);
608 printf(")");
609 break;
610 default:
611 printf(" (rtaf=0x%x)", af);
612 }
613 }
614 void
gre_sre_ip_print(u_int8_t sreoff,u_int8_t srelen,const u_char * bp,u_int len)615 gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
616 {
617 struct in_addr a;
618 const u_char *up = bp;
619
620 if (sreoff & 3) {
621 printf(" badoffset=%u", sreoff);
622 return;
623 }
624 if (srelen & 3) {
625 printf(" badlength=%u", srelen);
626 return;
627 }
628 if (sreoff >= srelen) {
629 printf(" badoff/len=%u/%u", sreoff, srelen);
630 return;
631 }
632
633 for (;;) {
634 if (len < 4 || srelen == 0)
635 return;
636
637 memcpy(&a, bp, sizeof(a));
638 printf(" %s%s",
639 ((bp - up) == sreoff) ? "*" : "",
640 inet_ntoa(a));
641
642 bp += 4;
643 len -= 4;
644 srelen -= 4;
645 }
646 }
647
648 void
gre_sre_asn_print(u_int8_t sreoff,u_int8_t srelen,const u_char * bp,u_int len)649 gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
650 {
651 const u_char *up = bp;
652
653 if (sreoff & 1) {
654 printf(" badoffset=%u", sreoff);
655 return;
656 }
657 if (srelen & 1) {
658 printf(" badlength=%u", srelen);
659 return;
660 }
661 if (sreoff >= srelen) {
662 printf(" badoff/len=%u/%u", sreoff, srelen);
663 return;
664 }
665
666 for (;;) {
667 if (len < 2 || srelen == 0)
668 return;
669
670 printf(" %s%x",
671 ((bp - up) == sreoff) ? "*" : "",
672 EXTRACT_16BITS(bp));
673
674 bp += 2;
675 len -= 2;
676 srelen -= 2;
677 }
678 }
679
680 /*
681 * - RFC 7348 Virtual eXtensible Local Area Network (VXLAN)
682 * - draft-ietf-nvo3-vxlan-gpe-08 Generic Protocol Extension for VXLAN
683 */
684
685 struct vxlan_header {
686 uint16_t flags;
687 #define VXLAN_VER 0x3000 /* GPE */
688 #define VXLAN_VER_0 0x0000
689 #define VXLAN_I 0x0800 /* Instance Bit */
690 #define VXLAN_P 0x0400 /* GPE Next Protocol */
691 #define VXLAN_B 0x0200 /* GPE BUM Traffic */
692 #define VXLAN_O 0x0100 /* GPE OAM Flag */
693 uint8_t reserved;
694 uint8_t next_proto; /* GPE */
695 #define VXLAN_PROTO_RESERVED 0x00
696 #define VXLAN_PROTO_IPV4 0x01
697 #define VXLAN_PROTO_IPV6 0x02
698 #define VXLAN_PROTO_ETHERNET 0x03
699 #define VXLAN_PROTO_NSH 0x04
700 #define VXLAN_PROTO_MPLS 0x05
701 #define VXLAN_PROTO_VBNG 0x07
702 #define VXLAN_PROTO_GBP 0x80
703 #define VXLAN_PROTO_IOAM 0x82
704 uint32_t vni;
705 #define VXLAN_VNI_SHIFT 8
706 #define VXLAN_VNI_MASK (0xffffffU << VXLAN_VNI_SHIFT)
707 #define VXLAN_VNI_RESERVED (~VXLAN_VNI_MASK)
708 };
709
710 void
vxlan_print(const u_char * p,u_int length)711 vxlan_print(const u_char *p, u_int length)
712 {
713 const struct vxlan_header *vh;
714 uint16_t flags, ver;
715 uint8_t proto = VXLAN_PROTO_ETHERNET;
716 int l = snapend - p;
717
718 printf("VXLAN");
719
720 if (l < sizeof(*vh))
721 goto trunc;
722 if (length < sizeof(*vh)) {
723 printf(" ip truncated");
724 return;
725 }
726
727 vh = (const struct vxlan_header *)p;
728
729 p += sizeof(*vh);
730 length -= sizeof(*vh);
731
732 flags = ntohs(vh->flags);
733 ver = flags & VXLAN_VER;
734 if (ver != VXLAN_VER_0) {
735 printf(" unknown version %u", ver >> 12);
736 return;
737 }
738
739 if (flags & VXLAN_I) {
740 uint32_t vni = (htonl(vh->vni) & VXLAN_VNI_MASK) >>
741 VXLAN_VNI_SHIFT;
742 printf(" vni %u", vni);
743 }
744
745 if (flags & VXLAN_P)
746 proto = vh->next_proto;
747
748 if (flags & VXLAN_B)
749 printf(" BUM");
750
751 if (flags & VXLAN_O) {
752 printf(" OAM (proto 0x%x, len %u)", proto, length);
753 return;
754 }
755
756 printf(": ");
757
758 switch (proto) {
759 case VXLAN_PROTO_RESERVED:
760 printf("Reserved");
761 break;
762 case VXLAN_PROTO_IPV4:
763 ip_print(p, length);
764 break;
765 case VXLAN_PROTO_IPV6:
766 ip6_print(p, length);
767 break;
768 case VXLAN_PROTO_ETHERNET:
769 ether_tryprint(p, length, 0);
770 break;
771 case VXLAN_PROTO_NSH:
772 nsh_print(p, length);
773 break;
774 case VXLAN_PROTO_MPLS:
775 mpls_print(p, length);
776 break;
777
778 default:
779 printf("Unassigned proto 0x%x", proto);
780 break;
781 }
782
783 return;
784 trunc:
785 printf(" [|vxlan]");
786 }
787
788 /*
789 * Geneve: Generic Network Virtualization Encapsulation
790 * draft-ietf-nvo3-geneve-16
791 */
792
793 struct geneve_header {
794 uint16_t flags;
795 #define GENEVE_VER_SHIFT 14
796 #define GENEVE_VER_MASK (0x3U << GENEVE_VER_SHIFT)
797 #define GENEVE_VER_0 (0x0U << GENEVE_VER_SHIFT)
798 #define GENEVE_OPT_LEN_SHIFT 8
799 #define GENEVE_OPT_LEN_MASK (0x3fU << GENEVE_OPT_LEN_SHIFT)
800 #define GENEVE_OPT_LEN_UNITS 4
801 #define GENEVE_O 0x0080 /* Control packet */
802 #define GENEVE_C 0x0040 /* Critical options present */
803 uint16_t protocol;
804 uint32_t vni;
805 #define GENEVE_VNI_SHIFT 8
806 #define GENEVE_VNI_MASK (0xffffffU << GENEVE_VNI_SHIFT)
807 #define GENEVE_VNI_RESERVED (~GENEVE_VNI_MASK)
808 };
809
810 struct geneve_option {
811 uint16_t class;
812 uint8_t type;
813 uint8_t flags;
814 #define GENEVE_OPTION_LENGTH_SHIFT 0
815 #define GENEVE_OPTION_LENGTH_MASK (0x1fU << GENEVE_OPTION_LENGTH_SHIFT)
816 };
817
818 static void
geneve_options_print(const u_char * p,u_int l)819 geneve_options_print(const u_char *p, u_int l)
820 {
821 if (l == 0)
822 return;
823
824 do {
825 struct geneve_option *go;
826 unsigned int len, i;
827
828 if (l < sizeof(*go))
829 goto trunc;
830
831 go = (struct geneve_option *)p;
832 p += sizeof(*go);
833 l -= sizeof(*go);
834
835 printf("\n\toption class %u type %u", ntohs(go->class),
836 go->type);
837
838 len = (go->flags & GENEVE_OPTION_LENGTH_MASK) >>
839 GENEVE_OPTION_LENGTH_SHIFT;
840 if (len > 0) {
841 printf(":");
842 for (i = 0; i < len; i++) {
843 uint32_t w;
844
845 if (l < sizeof(w))
846 goto trunc;
847
848 w = EXTRACT_32BITS(p);
849 p += sizeof(w);
850 l -= sizeof(w);
851
852 printf(" %08x", w);
853 }
854 }
855 } while (l > 0);
856
857 return;
858 trunc:
859 printf("[|geneve option]");
860 }
861
862 void
geneve_print(const u_char * p,u_int length)863 geneve_print(const u_char *p, u_int length)
864 {
865 const struct geneve_header *gh;
866 uint16_t flags, ver, optlen, proto;
867 uint32_t vni;
868 int l = snapend - p;
869
870 printf("geneve");
871
872 if (l < sizeof(*gh))
873 goto trunc;
874 if (length < sizeof(*gh)) {
875 printf(" ip truncated");
876 return;
877 }
878
879 gh = (const struct geneve_header *)p;
880
881 p += sizeof(*gh);
882 l -= sizeof(*gh);
883 length -= sizeof(*gh);
884
885 flags = ntohs(gh->flags);
886 ver = flags & GENEVE_VER_MASK;
887 if (ver != GENEVE_VER_0) {
888 printf(" unknown version %u", ver >> GENEVE_VER_SHIFT);
889 return;
890 }
891
892 vni = (htonl(gh->vni) & GENEVE_VNI_MASK) >> GENEVE_VNI_SHIFT;
893 printf(" vni %u", vni);
894
895 if (flags & GENEVE_O)
896 printf(" Control");
897
898 if (flags & GENEVE_C)
899 printf(" Critical");
900
901 optlen = (flags & GENEVE_OPT_LEN_MASK) >> GENEVE_OPT_LEN_SHIFT;
902 optlen *= GENEVE_OPT_LEN_UNITS;
903
904 if (l < optlen)
905 goto trunc;
906 if (length < optlen) {
907 printf(" ip truncated");
908 return;
909 }
910
911 if (optlen > 0)
912 geneve_options_print(p, optlen);
913
914 p += optlen;
915 length -= optlen;
916
917 printf("\n ");
918
919 proto = ntohs(gh->protocol);
920 switch (proto) {
921 case ETHERTYPE_IP:
922 ip_print(p, length);
923 break;
924 case ETHERTYPE_IPV6:
925 ip6_print(p, length);
926 break;
927 case ETHERTYPE_MPLS:
928 case ETHERTYPE_MPLS_MCAST:
929 mpls_print(p, length);
930 break;
931 case ETHERTYPE_TRANSETHER:
932 ether_tryprint(p, length, 0);
933 break;
934
935 default:
936 printf("geneve-protocol-0x%x", proto);
937 break;
938 }
939
940 return;
941 trunc:
942 printf(" [|geneve]");
943 }
944