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