1285191Spkelsey/* 2285191Spkelsey * Copyright (c) 2014 VMware, Inc. All Rights Reserved. 3285191Spkelsey * 4285191Spkelsey * Jesse Gross <jesse@nicira.com> 5285191Spkelsey * 6285191Spkelsey * Redistribution and use in source and binary forms, with or without 7285191Spkelsey * modification, are permitted provided that: (1) source code 8285191Spkelsey * distributions retain the above copyright notice and this paragraph 9285191Spkelsey * in its entirety, and (2) distributions including binary code include 10285191Spkelsey * the above copyright notice and this paragraph in its entirety in 11285191Spkelsey * the documentation or other materials provided with the distribution. 12285191Spkelsey * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 13285191Spkelsey * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 14285191Spkelsey * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 15285191Spkelsey * FOR A PARTICULAR PURPOSE. 16285191Spkelsey */ 17285191Spkelsey 18285191Spkelsey#define NETDISSECT_REWORKED 19285191Spkelsey#ifdef HAVE_CONFIG_H 20285191Spkelsey#include "config.h" 21285191Spkelsey#endif 22285191Spkelsey 23285191Spkelsey#include <tcpdump-stdinc.h> 24285191Spkelsey 25285191Spkelsey#include "interface.h" 26285191Spkelsey#include "extract.h" 27285191Spkelsey#include "ethertype.h" 28285191Spkelsey 29285191Spkelsey/* 30285191Spkelsey * Geneve header, draft-gross-geneve-02 31285191Spkelsey * 32285191Spkelsey * 0 1 2 3 33285191Spkelsey * 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 34285191Spkelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 35285191Spkelsey * |Ver| Opt Len |O|C| Rsvd. | Protocol Type | 36285191Spkelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37285191Spkelsey * | Virtual Network Identifier (VNI) | Reserved | 38285191Spkelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 39285191Spkelsey * | Variable Length Options | 40285191Spkelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 41285191Spkelsey * 42285191Spkelsey * Options: 43285191Spkelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 44285191Spkelsey * | Option Class | Type |R|R|R| Length | 45285191Spkelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 46285191Spkelsey * | Variable Option Data | 47285191Spkelsey * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 48285191Spkelsey */ 49285191Spkelsey 50285191Spkelsey#define VER_SHIFT 6 51285191Spkelsey#define HDR_OPTS_LEN_MASK 0x3F 52285191Spkelsey 53285191Spkelsey#define FLAG_OAM (1 << 7) 54285191Spkelsey#define FLAG_CRITICAL (1 << 6) 55285191Spkelsey#define FLAG_R1 (1 << 5) 56285191Spkelsey#define FLAG_R2 (1 << 4) 57285191Spkelsey#define FLAG_R3 (1 << 3) 58285191Spkelsey#define FLAG_R4 (1 << 2) 59285191Spkelsey#define FLAG_R5 (1 << 1) 60285191Spkelsey#define FLAG_R6 (1 << 0) 61285191Spkelsey 62285191Spkelsey#define OPT_TYPE_CRITICAL (1 << 7) 63285191Spkelsey#define OPT_LEN_MASK 0x1F 64285191Spkelsey 65285191Spkelseystatic const struct tok geneve_flag_values[] = { 66285191Spkelsey { FLAG_OAM, "O" }, 67285191Spkelsey { FLAG_CRITICAL, "C" }, 68285191Spkelsey { FLAG_R1, "R1" }, 69285191Spkelsey { FLAG_R2, "R2" }, 70285191Spkelsey { FLAG_R3, "R3" }, 71285191Spkelsey { FLAG_R4, "R4" }, 72285191Spkelsey { FLAG_R5, "R5" }, 73285191Spkelsey { FLAG_R6, "R6" }, 74285191Spkelsey { 0, NULL } 75285191Spkelsey}; 76285191Spkelsey 77285191Spkelseystatic const char * 78285191Spkelseyformat_opt_class(uint16_t opt_class) 79285191Spkelsey{ 80285191Spkelsey if (opt_class <= 0xff) 81285191Spkelsey return "Standard"; 82285191Spkelsey else if (opt_class == 0xffff) 83285191Spkelsey return "Experimental"; 84285191Spkelsey else 85285191Spkelsey return "Unknown"; 86285191Spkelsey} 87285191Spkelsey 88285191Spkelseystatic void 89285191Spkelseygeneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len) 90285191Spkelsey{ 91285191Spkelsey const char *sep = ""; 92285191Spkelsey 93285191Spkelsey while (len > 0) { 94285191Spkelsey uint16_t opt_class; 95285191Spkelsey uint8_t opt_type; 96285191Spkelsey uint8_t opt_len; 97285191Spkelsey 98285191Spkelsey ND_PRINT((ndo, "%s", sep)); 99285191Spkelsey sep = ", "; 100285191Spkelsey 101285191Spkelsey opt_class = EXTRACT_16BITS(bp); 102285191Spkelsey opt_type = *(bp + 2); 103285191Spkelsey opt_len = 4 + ((*(bp + 3) & OPT_LEN_MASK) * 4); 104285191Spkelsey 105285191Spkelsey ND_PRINT((ndo, "class %s (0x%x) type 0x%x%s len %u", 106285191Spkelsey format_opt_class(opt_class), opt_class, opt_type, 107285191Spkelsey opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len)); 108285191Spkelsey 109285191Spkelsey if (opt_len > len) { 110285191Spkelsey ND_PRINT((ndo, " [bad length]")); 111285191Spkelsey return; 112285191Spkelsey } 113285191Spkelsey 114285191Spkelsey if (ndo->ndo_vflag > 1 && opt_len > 4) { 115285191Spkelsey uint32_t *print_data = (uint32_t *)(bp + 4); 116285191Spkelsey int i; 117285191Spkelsey 118285191Spkelsey ND_PRINT((ndo, " data")); 119285191Spkelsey 120285191Spkelsey for (i = 4; i < opt_len; i += 4) { 121285191Spkelsey ND_PRINT((ndo, " %08x", EXTRACT_32BITS(print_data))); 122285191Spkelsey print_data++; 123285191Spkelsey } 124285191Spkelsey } 125285191Spkelsey 126285191Spkelsey bp += opt_len; 127285191Spkelsey len -= opt_len; 128285191Spkelsey } 129285191Spkelsey} 130285191Spkelsey 131285191Spkelseyvoid 132285191Spkelseygeneve_print(netdissect_options *ndo, const u_char *bp, u_int len) 133285191Spkelsey{ 134285191Spkelsey uint8_t ver_opt; 135285191Spkelsey uint version; 136285191Spkelsey uint8_t flags; 137285191Spkelsey uint16_t prot; 138285191Spkelsey uint32_t vni; 139285191Spkelsey uint8_t reserved; 140285191Spkelsey u_int opts_len; 141285191Spkelsey 142285191Spkelsey ND_PRINT((ndo, "Geneve")); 143285191Spkelsey 144285191Spkelsey ND_TCHECK2(*bp, 8); 145285191Spkelsey 146285191Spkelsey ver_opt = *bp; 147285191Spkelsey bp += 1; 148285191Spkelsey len -= 1; 149285191Spkelsey 150285191Spkelsey version = ver_opt >> VER_SHIFT; 151285191Spkelsey if (version != 0) { 152285191Spkelsey ND_PRINT((ndo, " ERROR: unknown-version %u", version)); 153285191Spkelsey return; 154285191Spkelsey } 155285191Spkelsey 156285191Spkelsey flags = *bp; 157285191Spkelsey bp += 1; 158285191Spkelsey len -= 1; 159285191Spkelsey 160285191Spkelsey prot = EXTRACT_16BITS(bp); 161285191Spkelsey bp += 2; 162285191Spkelsey len -= 2; 163285191Spkelsey 164285191Spkelsey vni = EXTRACT_24BITS(bp); 165285191Spkelsey bp += 3; 166285191Spkelsey len -= 3; 167285191Spkelsey 168285191Spkelsey reserved = *bp; 169285191Spkelsey bp += 1; 170285191Spkelsey len -= 1; 171285191Spkelsey 172285191Spkelsey ND_PRINT((ndo, ", Flags [%s]", 173285191Spkelsey bittok2str_nosep(geneve_flag_values, "none", flags))); 174285191Spkelsey ND_PRINT((ndo, ", vni 0x%x", vni)); 175285191Spkelsey 176285191Spkelsey if (reserved) 177285191Spkelsey ND_PRINT((ndo, ", rsvd 0x%x", reserved)); 178285191Spkelsey 179285191Spkelsey if (ndo->ndo_eflag) 180285191Spkelsey ND_PRINT((ndo, ", proto %s (0x%04x)", 181285191Spkelsey tok2str(ethertype_values, "unknown", prot), prot)); 182285191Spkelsey 183285191Spkelsey opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4; 184285191Spkelsey 185285191Spkelsey if (len < opts_len) { 186285191Spkelsey ND_PRINT((ndo, " truncated-geneve - %u bytes missing", 187285191Spkelsey len - opts_len)); 188285191Spkelsey return; 189285191Spkelsey } 190285191Spkelsey 191285191Spkelsey ND_TCHECK2(*bp, opts_len); 192285191Spkelsey 193285191Spkelsey if (opts_len > 0) { 194285191Spkelsey ND_PRINT((ndo, ", options [")); 195285191Spkelsey 196285191Spkelsey if (ndo->ndo_vflag) 197285191Spkelsey geneve_opts_print(ndo, bp, opts_len); 198285191Spkelsey else 199285191Spkelsey ND_PRINT((ndo, "%u bytes", opts_len)); 200285191Spkelsey 201285191Spkelsey ND_PRINT((ndo, "]")); 202285191Spkelsey } 203285191Spkelsey 204285191Spkelsey bp += opts_len; 205285191Spkelsey len -= opts_len; 206285191Spkelsey 207285191Spkelsey if (ndo->ndo_vflag < 1) 208285191Spkelsey ND_PRINT((ndo, ": ")); 209285191Spkelsey else 210285191Spkelsey ND_PRINT((ndo, "\n\t")); 211285191Spkelsey 212285191Spkelsey if (ethertype_print(ndo, prot, bp, len, len) == 0) { 213285191Spkelsey if (prot == ETHERTYPE_TEB) 214285191Spkelsey ether_print(ndo, bp, len, len, NULL, NULL); 215285191Spkelsey else 216285191Spkelsey ND_PRINT((ndo, "geneve-proto-0x%x", prot)); 217285191Spkelsey } 218285191Spkelsey 219285191Spkelsey return; 220285191Spkelsey 221285191Spkelseytrunc: 222285191Spkelsey ND_PRINT((ndo, " [|geneve]")); 223285191Spkelsey} 224