xref: /openbsd/usr.sbin/tcpdump/print-gre.c (revision ce7279d8)
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