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 *
format_opt_class(uint16_t opt_class)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
geneve_opts_print(netdissect_options * ndo,const u_char * bp,u_int len)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
geneve_print(netdissect_options * ndo,const u_char * bp,u_int len)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