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