18bdc5a62SPatrick Kelsey /* 28bdc5a62SPatrick Kelsey * Copyright (c) 2014 VMware, Inc. All Rights Reserved. 38bdc5a62SPatrick Kelsey * 48bdc5a62SPatrick Kelsey * Jesse Gross <jesse@nicira.com> 58bdc5a62SPatrick Kelsey * 68bdc5a62SPatrick Kelsey * Redistribution and use in source and binary forms, with or without 78bdc5a62SPatrick Kelsey * modification, are permitted provided that: (1) source code 88bdc5a62SPatrick Kelsey * distributions retain the above copyright notice and this paragraph 98bdc5a62SPatrick Kelsey * in its entirety, and (2) distributions including binary code include 108bdc5a62SPatrick Kelsey * the above copyright notice and this paragraph in its entirety in 118bdc5a62SPatrick Kelsey * the documentation or other materials provided with the distribution. 128bdc5a62SPatrick Kelsey * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 138bdc5a62SPatrick Kelsey * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 148bdc5a62SPatrick Kelsey * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 158bdc5a62SPatrick Kelsey * FOR A PARTICULAR PURPOSE. 168bdc5a62SPatrick Kelsey */ 178bdc5a62SPatrick Kelsey 183340d773SGleb Smirnoff /* \summary: Generic Network Virtualization Encapsulation (Geneve) printer */ 193340d773SGleb Smirnoff 20*ee67461eSJoseph Mingrone #include <config.h> 218bdc5a62SPatrick Kelsey 22*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h" 238bdc5a62SPatrick Kelsey 243340d773SGleb Smirnoff #include "netdissect.h" 258bdc5a62SPatrick Kelsey #include "extract.h" 268bdc5a62SPatrick Kelsey #include "ethertype.h" 278bdc5a62SPatrick Kelsey 288bdc5a62SPatrick Kelsey /* 293340d773SGleb Smirnoff * Geneve header, draft-ietf-nvo3-geneve 308bdc5a62SPatrick Kelsey * 318bdc5a62SPatrick Kelsey * 0 1 2 3 328bdc5a62SPatrick Kelsey * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 338bdc5a62SPatrick Kelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 348bdc5a62SPatrick Kelsey * |Ver| Opt Len |O|C| Rsvd. | Protocol Type | 358bdc5a62SPatrick Kelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 368bdc5a62SPatrick Kelsey * | Virtual Network Identifier (VNI) | Reserved | 378bdc5a62SPatrick Kelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 388bdc5a62SPatrick Kelsey * | Variable Length Options | 398bdc5a62SPatrick Kelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 408bdc5a62SPatrick Kelsey * 418bdc5a62SPatrick Kelsey * Options: 428bdc5a62SPatrick Kelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 438bdc5a62SPatrick Kelsey * | Option Class | Type |R|R|R| Length | 448bdc5a62SPatrick Kelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 458bdc5a62SPatrick Kelsey * | Variable Option Data | 468bdc5a62SPatrick Kelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 478bdc5a62SPatrick Kelsey */ 488bdc5a62SPatrick Kelsey 498bdc5a62SPatrick Kelsey #define VER_SHIFT 6 508bdc5a62SPatrick Kelsey #define HDR_OPTS_LEN_MASK 0x3F 518bdc5a62SPatrick Kelsey 528bdc5a62SPatrick Kelsey #define FLAG_OAM (1 << 7) 538bdc5a62SPatrick Kelsey #define FLAG_CRITICAL (1 << 6) 548bdc5a62SPatrick Kelsey #define FLAG_R1 (1 << 5) 558bdc5a62SPatrick Kelsey #define FLAG_R2 (1 << 4) 568bdc5a62SPatrick Kelsey #define FLAG_R3 (1 << 3) 578bdc5a62SPatrick Kelsey #define FLAG_R4 (1 << 2) 588bdc5a62SPatrick Kelsey #define FLAG_R5 (1 << 1) 598bdc5a62SPatrick Kelsey #define FLAG_R6 (1 << 0) 608bdc5a62SPatrick Kelsey 618bdc5a62SPatrick Kelsey #define OPT_TYPE_CRITICAL (1 << 7) 628bdc5a62SPatrick Kelsey #define OPT_LEN_MASK 0x1F 638bdc5a62SPatrick Kelsey 648bdc5a62SPatrick Kelsey static const struct tok geneve_flag_values[] = { 658bdc5a62SPatrick Kelsey { FLAG_OAM, "O" }, 668bdc5a62SPatrick Kelsey { FLAG_CRITICAL, "C" }, 678bdc5a62SPatrick Kelsey { FLAG_R1, "R1" }, 688bdc5a62SPatrick Kelsey { FLAG_R2, "R2" }, 698bdc5a62SPatrick Kelsey { FLAG_R3, "R3" }, 708bdc5a62SPatrick Kelsey { FLAG_R4, "R4" }, 718bdc5a62SPatrick Kelsey { FLAG_R5, "R5" }, 728bdc5a62SPatrick Kelsey { FLAG_R6, "R6" }, 738bdc5a62SPatrick Kelsey { 0, NULL } 748bdc5a62SPatrick Kelsey }; 758bdc5a62SPatrick Kelsey 768bdc5a62SPatrick Kelsey static const char * 778bdc5a62SPatrick Kelsey format_opt_class(uint16_t opt_class) 788bdc5a62SPatrick Kelsey { 793340d773SGleb Smirnoff switch (opt_class) { 803340d773SGleb Smirnoff case 0x0100: 813340d773SGleb Smirnoff return "Linux"; 823340d773SGleb Smirnoff case 0x0101: 833340d773SGleb Smirnoff return "Open vSwitch"; 843340d773SGleb Smirnoff case 0x0102: 853340d773SGleb Smirnoff return "Open Virtual Networking (OVN)"; 863340d773SGleb Smirnoff case 0x0103: 873340d773SGleb Smirnoff return "In-band Network Telemetry (INT)"; 883340d773SGleb Smirnoff case 0x0104: 893340d773SGleb Smirnoff return "VMware"; 903340d773SGleb Smirnoff default: 913340d773SGleb Smirnoff if (opt_class <= 0x00ff) 928bdc5a62SPatrick Kelsey return "Standard"; 933340d773SGleb Smirnoff else if (opt_class >= 0xfff0) 948bdc5a62SPatrick Kelsey return "Experimental"; 953340d773SGleb Smirnoff } 963340d773SGleb Smirnoff 978bdc5a62SPatrick Kelsey return "Unknown"; 988bdc5a62SPatrick Kelsey } 998bdc5a62SPatrick Kelsey 1008bdc5a62SPatrick Kelsey static void 1018bdc5a62SPatrick Kelsey geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len) 1028bdc5a62SPatrick Kelsey { 1038bdc5a62SPatrick Kelsey const char *sep = ""; 1048bdc5a62SPatrick Kelsey 1058bdc5a62SPatrick Kelsey while (len > 0) { 1068bdc5a62SPatrick Kelsey uint16_t opt_class; 1078bdc5a62SPatrick Kelsey uint8_t opt_type; 1088bdc5a62SPatrick Kelsey uint8_t opt_len; 1098bdc5a62SPatrick Kelsey 110*ee67461eSJoseph Mingrone ND_PRINT("%s", sep); 1118bdc5a62SPatrick Kelsey sep = ", "; 1128bdc5a62SPatrick Kelsey 113*ee67461eSJoseph Mingrone opt_class = GET_BE_U_2(bp); 114*ee67461eSJoseph Mingrone opt_type = GET_U_1(bp + 2); 115*ee67461eSJoseph Mingrone opt_len = 4 + ((GET_U_1(bp + 3) & OPT_LEN_MASK) * 4); 1168bdc5a62SPatrick Kelsey 117*ee67461eSJoseph Mingrone ND_PRINT("class %s (0x%x) type 0x%x%s len %u", 1188bdc5a62SPatrick Kelsey format_opt_class(opt_class), opt_class, opt_type, 119*ee67461eSJoseph Mingrone opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len); 1208bdc5a62SPatrick Kelsey 1218bdc5a62SPatrick Kelsey if (opt_len > len) { 122*ee67461eSJoseph Mingrone ND_PRINT(" [bad length]"); 1238bdc5a62SPatrick Kelsey return; 1248bdc5a62SPatrick Kelsey } 1258bdc5a62SPatrick Kelsey 1268bdc5a62SPatrick Kelsey if (ndo->ndo_vflag > 1 && opt_len > 4) { 1273340d773SGleb Smirnoff const uint32_t *data = (const uint32_t *)(bp + 4); 1288bdc5a62SPatrick Kelsey int i; 1298bdc5a62SPatrick Kelsey 130*ee67461eSJoseph Mingrone ND_PRINT(" data"); 1318bdc5a62SPatrick Kelsey 1328bdc5a62SPatrick Kelsey for (i = 4; i < opt_len; i += 4) { 133*ee67461eSJoseph Mingrone ND_PRINT(" %08x", GET_BE_U_4(data)); 1343340d773SGleb Smirnoff data++; 1358bdc5a62SPatrick Kelsey } 1368bdc5a62SPatrick Kelsey } 1378bdc5a62SPatrick Kelsey 1388bdc5a62SPatrick Kelsey bp += opt_len; 1398bdc5a62SPatrick Kelsey len -= opt_len; 1408bdc5a62SPatrick Kelsey } 1418bdc5a62SPatrick Kelsey } 1428bdc5a62SPatrick Kelsey 1438bdc5a62SPatrick Kelsey void 1448bdc5a62SPatrick Kelsey geneve_print(netdissect_options *ndo, const u_char *bp, u_int len) 1458bdc5a62SPatrick Kelsey { 1468bdc5a62SPatrick Kelsey uint8_t ver_opt; 1473340d773SGleb Smirnoff u_int version; 1488bdc5a62SPatrick Kelsey uint8_t flags; 1498bdc5a62SPatrick Kelsey uint16_t prot; 1508bdc5a62SPatrick Kelsey uint32_t vni; 1518bdc5a62SPatrick Kelsey uint8_t reserved; 1528bdc5a62SPatrick Kelsey u_int opts_len; 1538bdc5a62SPatrick Kelsey 154*ee67461eSJoseph Mingrone ndo->ndo_protocol = "geneve"; 155*ee67461eSJoseph Mingrone ND_PRINT("Geneve"); 1568bdc5a62SPatrick Kelsey 157*ee67461eSJoseph Mingrone if (len < 8) { 158*ee67461eSJoseph Mingrone ND_PRINT(" [length %u < 8]", len); 159*ee67461eSJoseph Mingrone nd_print_invalid(ndo); 160*ee67461eSJoseph Mingrone return; 161*ee67461eSJoseph Mingrone } 1628bdc5a62SPatrick Kelsey 163*ee67461eSJoseph Mingrone ND_TCHECK_8(bp); 164*ee67461eSJoseph Mingrone 165*ee67461eSJoseph Mingrone ver_opt = GET_U_1(bp); 1668bdc5a62SPatrick Kelsey bp += 1; 1678bdc5a62SPatrick Kelsey len -= 1; 1688bdc5a62SPatrick Kelsey 1698bdc5a62SPatrick Kelsey version = ver_opt >> VER_SHIFT; 1708bdc5a62SPatrick Kelsey if (version != 0) { 171*ee67461eSJoseph Mingrone ND_PRINT(" ERROR: unknown-version %u", version); 1728bdc5a62SPatrick Kelsey return; 1738bdc5a62SPatrick Kelsey } 1748bdc5a62SPatrick Kelsey 175*ee67461eSJoseph Mingrone flags = GET_U_1(bp); 1768bdc5a62SPatrick Kelsey bp += 1; 1778bdc5a62SPatrick Kelsey len -= 1; 1788bdc5a62SPatrick Kelsey 179*ee67461eSJoseph Mingrone prot = GET_BE_U_2(bp); 1808bdc5a62SPatrick Kelsey bp += 2; 1818bdc5a62SPatrick Kelsey len -= 2; 1828bdc5a62SPatrick Kelsey 183*ee67461eSJoseph Mingrone vni = GET_BE_U_3(bp); 1848bdc5a62SPatrick Kelsey bp += 3; 1858bdc5a62SPatrick Kelsey len -= 3; 1868bdc5a62SPatrick Kelsey 187*ee67461eSJoseph Mingrone reserved = GET_U_1(bp); 1888bdc5a62SPatrick Kelsey bp += 1; 1898bdc5a62SPatrick Kelsey len -= 1; 1908bdc5a62SPatrick Kelsey 191*ee67461eSJoseph Mingrone ND_PRINT(", Flags [%s]", 192*ee67461eSJoseph Mingrone bittok2str_nosep(geneve_flag_values, "none", flags)); 193*ee67461eSJoseph Mingrone ND_PRINT(", vni 0x%x", vni); 1948bdc5a62SPatrick Kelsey 1958bdc5a62SPatrick Kelsey if (reserved) 196*ee67461eSJoseph Mingrone ND_PRINT(", rsvd 0x%x", reserved); 1978bdc5a62SPatrick Kelsey 1988bdc5a62SPatrick Kelsey if (ndo->ndo_eflag) 199*ee67461eSJoseph Mingrone ND_PRINT(", proto %s (0x%04x)", 200*ee67461eSJoseph Mingrone tok2str(ethertype_values, "unknown", prot), prot); 2018bdc5a62SPatrick Kelsey 2028bdc5a62SPatrick Kelsey opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4; 2038bdc5a62SPatrick Kelsey 2048bdc5a62SPatrick Kelsey if (len < opts_len) { 205*ee67461eSJoseph Mingrone ND_PRINT(" truncated-geneve - %u bytes missing", 206*ee67461eSJoseph Mingrone opts_len - len); 2078bdc5a62SPatrick Kelsey return; 2088bdc5a62SPatrick Kelsey } 2098bdc5a62SPatrick Kelsey 210*ee67461eSJoseph Mingrone ND_TCHECK_LEN(bp, opts_len); 2118bdc5a62SPatrick Kelsey 2128bdc5a62SPatrick Kelsey if (opts_len > 0) { 213*ee67461eSJoseph Mingrone ND_PRINT(", options ["); 2148bdc5a62SPatrick Kelsey 2158bdc5a62SPatrick Kelsey if (ndo->ndo_vflag) 2168bdc5a62SPatrick Kelsey geneve_opts_print(ndo, bp, opts_len); 2178bdc5a62SPatrick Kelsey else 218*ee67461eSJoseph Mingrone ND_PRINT("%u bytes", opts_len); 2198bdc5a62SPatrick Kelsey 220*ee67461eSJoseph Mingrone ND_PRINT("]"); 2218bdc5a62SPatrick Kelsey } 2228bdc5a62SPatrick Kelsey 2238bdc5a62SPatrick Kelsey bp += opts_len; 2248bdc5a62SPatrick Kelsey len -= opts_len; 2258bdc5a62SPatrick Kelsey 2268bdc5a62SPatrick Kelsey if (ndo->ndo_vflag < 1) 227*ee67461eSJoseph Mingrone ND_PRINT(": "); 2288bdc5a62SPatrick Kelsey else 229*ee67461eSJoseph Mingrone ND_PRINT("\n\t"); 2308bdc5a62SPatrick Kelsey 231*ee67461eSJoseph Mingrone if (ethertype_print(ndo, prot, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL) == 0) { 2328bdc5a62SPatrick Kelsey if (prot == ETHERTYPE_TEB) 233*ee67461eSJoseph Mingrone ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL); 2348bdc5a62SPatrick Kelsey else 235*ee67461eSJoseph Mingrone ND_PRINT("geneve-proto-0x%x", prot); 2368bdc5a62SPatrick Kelsey } 2378bdc5a62SPatrick Kelsey 2388bdc5a62SPatrick Kelsey return; 2398bdc5a62SPatrick Kelsey 2408bdc5a62SPatrick Kelsey trunc: 241*ee67461eSJoseph Mingrone nd_print_trunc(ndo); 2428bdc5a62SPatrick Kelsey } 243