1*05b00f60SXin Li /*
2*05b00f60SXin Li * Copyright (c) 2014 VMware, Inc. All Rights Reserved.
3*05b00f60SXin Li *
4*05b00f60SXin Li * Jesse Gross <[email protected]>
5*05b00f60SXin Li *
6*05b00f60SXin Li * Redistribution and use in source and binary forms, with or without
7*05b00f60SXin Li * modification, are permitted provided that: (1) source code
8*05b00f60SXin Li * distributions retain the above copyright notice and this paragraph
9*05b00f60SXin Li * in its entirety, and (2) distributions including binary code include
10*05b00f60SXin Li * the above copyright notice and this paragraph in its entirety in
11*05b00f60SXin Li * the documentation or other materials provided with the distribution.
12*05b00f60SXin Li * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
13*05b00f60SXin Li * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
14*05b00f60SXin Li * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
15*05b00f60SXin Li * FOR A PARTICULAR PURPOSE.
16*05b00f60SXin Li */
17*05b00f60SXin Li
18*05b00f60SXin Li /* \summary: Generic Network Virtualization Encapsulation (Geneve) printer */
19*05b00f60SXin Li
20*05b00f60SXin Li #ifdef HAVE_CONFIG_H
21*05b00f60SXin Li #include <config.h>
22*05b00f60SXin Li #endif
23*05b00f60SXin Li
24*05b00f60SXin Li #include "netdissect-stdinc.h"
25*05b00f60SXin Li
26*05b00f60SXin Li #include "netdissect.h"
27*05b00f60SXin Li #include "extract.h"
28*05b00f60SXin Li #include "ethertype.h"
29*05b00f60SXin Li
30*05b00f60SXin Li /*
31*05b00f60SXin Li * Geneve header, draft-ietf-nvo3-geneve
32*05b00f60SXin Li *
33*05b00f60SXin Li * 0 1 2 3
34*05b00f60SXin Li * 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
35*05b00f60SXin Li * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36*05b00f60SXin Li * |Ver| Opt Len |O|C| Rsvd. | Protocol Type |
37*05b00f60SXin Li * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38*05b00f60SXin Li * | Virtual Network Identifier (VNI) | Reserved |
39*05b00f60SXin Li * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40*05b00f60SXin Li * | Variable Length Options |
41*05b00f60SXin Li * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42*05b00f60SXin Li *
43*05b00f60SXin Li * Options:
44*05b00f60SXin Li * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45*05b00f60SXin Li * | Option Class | Type |R|R|R| Length |
46*05b00f60SXin Li * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47*05b00f60SXin Li * | Variable Option Data |
48*05b00f60SXin Li * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49*05b00f60SXin Li */
50*05b00f60SXin Li
51*05b00f60SXin Li #define VER_SHIFT 6
52*05b00f60SXin Li #define HDR_OPTS_LEN_MASK 0x3F
53*05b00f60SXin Li
54*05b00f60SXin Li #define FLAG_OAM (1 << 7)
55*05b00f60SXin Li #define FLAG_CRITICAL (1 << 6)
56*05b00f60SXin Li #define FLAG_R1 (1 << 5)
57*05b00f60SXin Li #define FLAG_R2 (1 << 4)
58*05b00f60SXin Li #define FLAG_R3 (1 << 3)
59*05b00f60SXin Li #define FLAG_R4 (1 << 2)
60*05b00f60SXin Li #define FLAG_R5 (1 << 1)
61*05b00f60SXin Li #define FLAG_R6 (1 << 0)
62*05b00f60SXin Li
63*05b00f60SXin Li #define OPT_TYPE_CRITICAL (1 << 7)
64*05b00f60SXin Li #define OPT_LEN_MASK 0x1F
65*05b00f60SXin Li
66*05b00f60SXin Li static const struct tok geneve_flag_values[] = {
67*05b00f60SXin Li { FLAG_OAM, "O" },
68*05b00f60SXin Li { FLAG_CRITICAL, "C" },
69*05b00f60SXin Li { FLAG_R1, "R1" },
70*05b00f60SXin Li { FLAG_R2, "R2" },
71*05b00f60SXin Li { FLAG_R3, "R3" },
72*05b00f60SXin Li { FLAG_R4, "R4" },
73*05b00f60SXin Li { FLAG_R5, "R5" },
74*05b00f60SXin Li { FLAG_R6, "R6" },
75*05b00f60SXin Li { 0, NULL }
76*05b00f60SXin Li };
77*05b00f60SXin Li
78*05b00f60SXin Li static const char *
format_opt_class(uint16_t opt_class)79*05b00f60SXin Li format_opt_class(uint16_t opt_class)
80*05b00f60SXin Li {
81*05b00f60SXin Li switch (opt_class) {
82*05b00f60SXin Li case 0x0100:
83*05b00f60SXin Li return "Linux";
84*05b00f60SXin Li case 0x0101:
85*05b00f60SXin Li return "Open vSwitch";
86*05b00f60SXin Li case 0x0102:
87*05b00f60SXin Li return "Open Virtual Networking (OVN)";
88*05b00f60SXin Li case 0x0103:
89*05b00f60SXin Li return "In-band Network Telemetry (INT)";
90*05b00f60SXin Li case 0x0104:
91*05b00f60SXin Li return "VMware";
92*05b00f60SXin Li default:
93*05b00f60SXin Li if (opt_class <= 0x00ff)
94*05b00f60SXin Li return "Standard";
95*05b00f60SXin Li else if (opt_class >= 0xfff0)
96*05b00f60SXin Li return "Experimental";
97*05b00f60SXin Li }
98*05b00f60SXin Li
99*05b00f60SXin Li return "Unknown";
100*05b00f60SXin Li }
101*05b00f60SXin Li
102*05b00f60SXin Li static void
geneve_opts_print(netdissect_options * ndo,const u_char * bp,u_int len)103*05b00f60SXin Li geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len)
104*05b00f60SXin Li {
105*05b00f60SXin Li const char *sep = "";
106*05b00f60SXin Li
107*05b00f60SXin Li while (len > 0) {
108*05b00f60SXin Li uint16_t opt_class;
109*05b00f60SXin Li uint8_t opt_type;
110*05b00f60SXin Li uint8_t opt_len;
111*05b00f60SXin Li
112*05b00f60SXin Li ND_PRINT("%s", sep);
113*05b00f60SXin Li sep = ", ";
114*05b00f60SXin Li
115*05b00f60SXin Li opt_class = GET_BE_U_2(bp);
116*05b00f60SXin Li opt_type = GET_U_1(bp + 2);
117*05b00f60SXin Li opt_len = 4 + ((GET_U_1(bp + 3) & OPT_LEN_MASK) * 4);
118*05b00f60SXin Li
119*05b00f60SXin Li ND_PRINT("class %s (0x%x) type 0x%x%s len %u",
120*05b00f60SXin Li format_opt_class(opt_class), opt_class, opt_type,
121*05b00f60SXin Li opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len);
122*05b00f60SXin Li
123*05b00f60SXin Li if (opt_len > len) {
124*05b00f60SXin Li ND_PRINT(" [bad length]");
125*05b00f60SXin Li return;
126*05b00f60SXin Li }
127*05b00f60SXin Li
128*05b00f60SXin Li if (ndo->ndo_vflag > 1 && opt_len > 4) {
129*05b00f60SXin Li const uint32_t *data = (const uint32_t *)(bp + 4);
130*05b00f60SXin Li int i;
131*05b00f60SXin Li
132*05b00f60SXin Li ND_PRINT(" data");
133*05b00f60SXin Li
134*05b00f60SXin Li for (i = 4; i < opt_len; i += 4) {
135*05b00f60SXin Li ND_PRINT(" %08x", GET_BE_U_4(data));
136*05b00f60SXin Li data++;
137*05b00f60SXin Li }
138*05b00f60SXin Li }
139*05b00f60SXin Li
140*05b00f60SXin Li bp += opt_len;
141*05b00f60SXin Li len -= opt_len;
142*05b00f60SXin Li }
143*05b00f60SXin Li }
144*05b00f60SXin Li
145*05b00f60SXin Li void
geneve_print(netdissect_options * ndo,const u_char * bp,u_int len)146*05b00f60SXin Li geneve_print(netdissect_options *ndo, const u_char *bp, u_int len)
147*05b00f60SXin Li {
148*05b00f60SXin Li uint8_t ver_opt;
149*05b00f60SXin Li u_int version;
150*05b00f60SXin Li uint8_t flags;
151*05b00f60SXin Li uint16_t prot;
152*05b00f60SXin Li uint32_t vni;
153*05b00f60SXin Li uint8_t reserved;
154*05b00f60SXin Li u_int opts_len;
155*05b00f60SXin Li
156*05b00f60SXin Li ndo->ndo_protocol = "geneve";
157*05b00f60SXin Li ND_PRINT("Geneve");
158*05b00f60SXin Li
159*05b00f60SXin Li if (len < 8) {
160*05b00f60SXin Li ND_PRINT(" [length %u < 8]", len);
161*05b00f60SXin Li nd_print_invalid(ndo);
162*05b00f60SXin Li return;
163*05b00f60SXin Li }
164*05b00f60SXin Li
165*05b00f60SXin Li ND_TCHECK_8(bp);
166*05b00f60SXin Li
167*05b00f60SXin Li ver_opt = GET_U_1(bp);
168*05b00f60SXin Li bp += 1;
169*05b00f60SXin Li len -= 1;
170*05b00f60SXin Li
171*05b00f60SXin Li version = ver_opt >> VER_SHIFT;
172*05b00f60SXin Li if (version != 0) {
173*05b00f60SXin Li ND_PRINT(" ERROR: unknown-version %u", version);
174*05b00f60SXin Li return;
175*05b00f60SXin Li }
176*05b00f60SXin Li
177*05b00f60SXin Li flags = GET_U_1(bp);
178*05b00f60SXin Li bp += 1;
179*05b00f60SXin Li len -= 1;
180*05b00f60SXin Li
181*05b00f60SXin Li prot = GET_BE_U_2(bp);
182*05b00f60SXin Li bp += 2;
183*05b00f60SXin Li len -= 2;
184*05b00f60SXin Li
185*05b00f60SXin Li vni = GET_BE_U_3(bp);
186*05b00f60SXin Li bp += 3;
187*05b00f60SXin Li len -= 3;
188*05b00f60SXin Li
189*05b00f60SXin Li reserved = GET_U_1(bp);
190*05b00f60SXin Li bp += 1;
191*05b00f60SXin Li len -= 1;
192*05b00f60SXin Li
193*05b00f60SXin Li ND_PRINT(", Flags [%s]",
194*05b00f60SXin Li bittok2str_nosep(geneve_flag_values, "none", flags));
195*05b00f60SXin Li ND_PRINT(", vni 0x%x", vni);
196*05b00f60SXin Li
197*05b00f60SXin Li if (reserved)
198*05b00f60SXin Li ND_PRINT(", rsvd 0x%x", reserved);
199*05b00f60SXin Li
200*05b00f60SXin Li if (ndo->ndo_eflag)
201*05b00f60SXin Li ND_PRINT(", proto %s (0x%04x)",
202*05b00f60SXin Li tok2str(ethertype_values, "unknown", prot), prot);
203*05b00f60SXin Li
204*05b00f60SXin Li opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4;
205*05b00f60SXin Li
206*05b00f60SXin Li if (len < opts_len) {
207*05b00f60SXin Li ND_PRINT(" truncated-geneve - %u bytes missing",
208*05b00f60SXin Li opts_len - len);
209*05b00f60SXin Li return;
210*05b00f60SXin Li }
211*05b00f60SXin Li
212*05b00f60SXin Li ND_TCHECK_LEN(bp, opts_len);
213*05b00f60SXin Li
214*05b00f60SXin Li if (opts_len > 0) {
215*05b00f60SXin Li ND_PRINT(", options [");
216*05b00f60SXin Li
217*05b00f60SXin Li if (ndo->ndo_vflag)
218*05b00f60SXin Li geneve_opts_print(ndo, bp, opts_len);
219*05b00f60SXin Li else
220*05b00f60SXin Li ND_PRINT("%u bytes", opts_len);
221*05b00f60SXin Li
222*05b00f60SXin Li ND_PRINT("]");
223*05b00f60SXin Li }
224*05b00f60SXin Li
225*05b00f60SXin Li bp += opts_len;
226*05b00f60SXin Li len -= opts_len;
227*05b00f60SXin Li
228*05b00f60SXin Li if (ndo->ndo_vflag < 1)
229*05b00f60SXin Li ND_PRINT(": ");
230*05b00f60SXin Li else
231*05b00f60SXin Li ND_PRINT("\n\t");
232*05b00f60SXin Li
233*05b00f60SXin Li if (ethertype_print(ndo, prot, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL) == 0) {
234*05b00f60SXin Li if (prot == ETHERTYPE_TEB)
235*05b00f60SXin Li ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
236*05b00f60SXin Li else
237*05b00f60SXin Li ND_PRINT("geneve-proto-0x%x", prot);
238*05b00f60SXin Li }
239*05b00f60SXin Li
240*05b00f60SXin Li return;
241*05b00f60SXin Li
242*05b00f60SXin Li trunc:
243*05b00f60SXin Li nd_print_trunc(ndo);
244*05b00f60SXin Li }
245