1411677aeSAaron LI /*
2411677aeSAaron LI * Copyright (c) 2014 VMware, Inc. All Rights Reserved.
3411677aeSAaron LI *
4411677aeSAaron LI * Jesse Gross <jesse@nicira.com>
5411677aeSAaron LI *
6411677aeSAaron LI * Redistribution and use in source and binary forms, with or without
7411677aeSAaron LI * modification, are permitted provided that: (1) source code
8411677aeSAaron LI * distributions retain the above copyright notice and this paragraph
9411677aeSAaron LI * in its entirety, and (2) distributions including binary code include
10411677aeSAaron LI * the above copyright notice and this paragraph in its entirety in
11411677aeSAaron LI * the documentation or other materials provided with the distribution.
12411677aeSAaron LI * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
13411677aeSAaron LI * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
14411677aeSAaron LI * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
15411677aeSAaron LI * FOR A PARTICULAR PURPOSE.
16411677aeSAaron LI */
17411677aeSAaron LI
18411677aeSAaron LI /* \summary: Generic Network Virtualization Encapsulation (Geneve) printer */
19411677aeSAaron LI
20411677aeSAaron LI #ifdef HAVE_CONFIG_H
21*ed775ee7SAntonio Huete Jimenez #include <config.h>
22411677aeSAaron LI #endif
23411677aeSAaron LI
24*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
25411677aeSAaron LI
26411677aeSAaron LI #include "netdissect.h"
27411677aeSAaron LI #include "extract.h"
28411677aeSAaron LI #include "ethertype.h"
29411677aeSAaron LI
30411677aeSAaron LI /*
31411677aeSAaron LI * Geneve header, draft-ietf-nvo3-geneve
32411677aeSAaron LI *
33411677aeSAaron LI * 0 1 2 3
34411677aeSAaron 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
35411677aeSAaron LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36411677aeSAaron LI * |Ver| Opt Len |O|C| Rsvd. | Protocol Type |
37411677aeSAaron LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38411677aeSAaron LI * | Virtual Network Identifier (VNI) | Reserved |
39411677aeSAaron LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40411677aeSAaron LI * | Variable Length Options |
41411677aeSAaron LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42411677aeSAaron LI *
43411677aeSAaron LI * Options:
44411677aeSAaron LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45411677aeSAaron LI * | Option Class | Type |R|R|R| Length |
46411677aeSAaron LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47411677aeSAaron LI * | Variable Option Data |
48411677aeSAaron LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49411677aeSAaron LI */
50411677aeSAaron LI
51411677aeSAaron LI #define VER_SHIFT 6
52411677aeSAaron LI #define HDR_OPTS_LEN_MASK 0x3F
53411677aeSAaron LI
54411677aeSAaron LI #define FLAG_OAM (1 << 7)
55411677aeSAaron LI #define FLAG_CRITICAL (1 << 6)
56411677aeSAaron LI #define FLAG_R1 (1 << 5)
57411677aeSAaron LI #define FLAG_R2 (1 << 4)
58411677aeSAaron LI #define FLAG_R3 (1 << 3)
59411677aeSAaron LI #define FLAG_R4 (1 << 2)
60411677aeSAaron LI #define FLAG_R5 (1 << 1)
61411677aeSAaron LI #define FLAG_R6 (1 << 0)
62411677aeSAaron LI
63411677aeSAaron LI #define OPT_TYPE_CRITICAL (1 << 7)
64411677aeSAaron LI #define OPT_LEN_MASK 0x1F
65411677aeSAaron LI
66411677aeSAaron LI static const struct tok geneve_flag_values[] = {
67411677aeSAaron LI { FLAG_OAM, "O" },
68411677aeSAaron LI { FLAG_CRITICAL, "C" },
69411677aeSAaron LI { FLAG_R1, "R1" },
70411677aeSAaron LI { FLAG_R2, "R2" },
71411677aeSAaron LI { FLAG_R3, "R3" },
72411677aeSAaron LI { FLAG_R4, "R4" },
73411677aeSAaron LI { FLAG_R5, "R5" },
74411677aeSAaron LI { FLAG_R6, "R6" },
75411677aeSAaron LI { 0, NULL }
76411677aeSAaron LI };
77411677aeSAaron LI
78411677aeSAaron LI static const char *
format_opt_class(uint16_t opt_class)79411677aeSAaron LI format_opt_class(uint16_t opt_class)
80411677aeSAaron LI {
81411677aeSAaron LI switch (opt_class) {
82411677aeSAaron LI case 0x0100:
83411677aeSAaron LI return "Linux";
84411677aeSAaron LI case 0x0101:
85411677aeSAaron LI return "Open vSwitch";
86411677aeSAaron LI case 0x0102:
87411677aeSAaron LI return "Open Virtual Networking (OVN)";
88411677aeSAaron LI case 0x0103:
89411677aeSAaron LI return "In-band Network Telemetry (INT)";
90411677aeSAaron LI case 0x0104:
91411677aeSAaron LI return "VMware";
92411677aeSAaron LI default:
93411677aeSAaron LI if (opt_class <= 0x00ff)
94411677aeSAaron LI return "Standard";
95411677aeSAaron LI else if (opt_class >= 0xfff0)
96411677aeSAaron LI return "Experimental";
97411677aeSAaron LI }
98411677aeSAaron LI
99411677aeSAaron LI return "Unknown";
100411677aeSAaron LI }
101411677aeSAaron LI
102411677aeSAaron LI static void
geneve_opts_print(netdissect_options * ndo,const u_char * bp,u_int len)103411677aeSAaron LI geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len)
104411677aeSAaron LI {
105411677aeSAaron LI const char *sep = "";
106411677aeSAaron LI
107411677aeSAaron LI while (len > 0) {
108411677aeSAaron LI uint16_t opt_class;
109411677aeSAaron LI uint8_t opt_type;
110411677aeSAaron LI uint8_t opt_len;
111411677aeSAaron LI
112*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s", sep);
113411677aeSAaron LI sep = ", ";
114411677aeSAaron LI
115*ed775ee7SAntonio Huete Jimenez opt_class = GET_BE_U_2(bp);
116*ed775ee7SAntonio Huete Jimenez opt_type = GET_U_1(bp + 2);
117*ed775ee7SAntonio Huete Jimenez opt_len = 4 + ((GET_U_1(bp + 3) & OPT_LEN_MASK) * 4);
118411677aeSAaron LI
119*ed775ee7SAntonio Huete Jimenez ND_PRINT("class %s (0x%x) type 0x%x%s len %u",
120411677aeSAaron LI format_opt_class(opt_class), opt_class, opt_type,
121*ed775ee7SAntonio Huete Jimenez opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len);
122411677aeSAaron LI
123411677aeSAaron LI if (opt_len > len) {
124*ed775ee7SAntonio Huete Jimenez ND_PRINT(" [bad length]");
125411677aeSAaron LI return;
126411677aeSAaron LI }
127411677aeSAaron LI
128411677aeSAaron LI if (ndo->ndo_vflag > 1 && opt_len > 4) {
129411677aeSAaron LI const uint32_t *data = (const uint32_t *)(bp + 4);
130411677aeSAaron LI int i;
131411677aeSAaron LI
132*ed775ee7SAntonio Huete Jimenez ND_PRINT(" data");
133411677aeSAaron LI
134411677aeSAaron LI for (i = 4; i < opt_len; i += 4) {
135*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %08x", GET_BE_U_4(data));
136411677aeSAaron LI data++;
137411677aeSAaron LI }
138411677aeSAaron LI }
139411677aeSAaron LI
140411677aeSAaron LI bp += opt_len;
141411677aeSAaron LI len -= opt_len;
142411677aeSAaron LI }
143411677aeSAaron LI }
144411677aeSAaron LI
145411677aeSAaron LI void
geneve_print(netdissect_options * ndo,const u_char * bp,u_int len)146411677aeSAaron LI geneve_print(netdissect_options *ndo, const u_char *bp, u_int len)
147411677aeSAaron LI {
148411677aeSAaron LI uint8_t ver_opt;
149411677aeSAaron LI u_int version;
150411677aeSAaron LI uint8_t flags;
151411677aeSAaron LI uint16_t prot;
152411677aeSAaron LI uint32_t vni;
153411677aeSAaron LI uint8_t reserved;
154411677aeSAaron LI u_int opts_len;
155411677aeSAaron LI
156*ed775ee7SAntonio Huete Jimenez ndo->ndo_protocol = "geneve";
157*ed775ee7SAntonio Huete Jimenez ND_PRINT("Geneve");
158411677aeSAaron LI
159*ed775ee7SAntonio Huete Jimenez if (len < 8) {
160*ed775ee7SAntonio Huete Jimenez ND_PRINT(" [length %u < 8]", len);
161*ed775ee7SAntonio Huete Jimenez nd_print_invalid(ndo);
162*ed775ee7SAntonio Huete Jimenez return;
163*ed775ee7SAntonio Huete Jimenez }
164411677aeSAaron LI
165*ed775ee7SAntonio Huete Jimenez ND_TCHECK_8(bp);
166*ed775ee7SAntonio Huete Jimenez
167*ed775ee7SAntonio Huete Jimenez ver_opt = GET_U_1(bp);
168411677aeSAaron LI bp += 1;
169411677aeSAaron LI len -= 1;
170411677aeSAaron LI
171411677aeSAaron LI version = ver_opt >> VER_SHIFT;
172411677aeSAaron LI if (version != 0) {
173*ed775ee7SAntonio Huete Jimenez ND_PRINT(" ERROR: unknown-version %u", version);
174411677aeSAaron LI return;
175411677aeSAaron LI }
176411677aeSAaron LI
177*ed775ee7SAntonio Huete Jimenez flags = GET_U_1(bp);
178411677aeSAaron LI bp += 1;
179411677aeSAaron LI len -= 1;
180411677aeSAaron LI
181*ed775ee7SAntonio Huete Jimenez prot = GET_BE_U_2(bp);
182411677aeSAaron LI bp += 2;
183411677aeSAaron LI len -= 2;
184411677aeSAaron LI
185*ed775ee7SAntonio Huete Jimenez vni = GET_BE_U_3(bp);
186411677aeSAaron LI bp += 3;
187411677aeSAaron LI len -= 3;
188411677aeSAaron LI
189*ed775ee7SAntonio Huete Jimenez reserved = GET_U_1(bp);
190411677aeSAaron LI bp += 1;
191411677aeSAaron LI len -= 1;
192411677aeSAaron LI
193*ed775ee7SAntonio Huete Jimenez ND_PRINT(", Flags [%s]",
194*ed775ee7SAntonio Huete Jimenez bittok2str_nosep(geneve_flag_values, "none", flags));
195*ed775ee7SAntonio Huete Jimenez ND_PRINT(", vni 0x%x", vni);
196411677aeSAaron LI
197411677aeSAaron LI if (reserved)
198*ed775ee7SAntonio Huete Jimenez ND_PRINT(", rsvd 0x%x", reserved);
199411677aeSAaron LI
200411677aeSAaron LI if (ndo->ndo_eflag)
201*ed775ee7SAntonio Huete Jimenez ND_PRINT(", proto %s (0x%04x)",
202*ed775ee7SAntonio Huete Jimenez tok2str(ethertype_values, "unknown", prot), prot);
203411677aeSAaron LI
204411677aeSAaron LI opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4;
205411677aeSAaron LI
206411677aeSAaron LI if (len < opts_len) {
207*ed775ee7SAntonio Huete Jimenez ND_PRINT(" truncated-geneve - %u bytes missing",
208*ed775ee7SAntonio Huete Jimenez opts_len - len);
209411677aeSAaron LI return;
210411677aeSAaron LI }
211411677aeSAaron LI
212*ed775ee7SAntonio Huete Jimenez ND_TCHECK_LEN(bp, opts_len);
213411677aeSAaron LI
214411677aeSAaron LI if (opts_len > 0) {
215*ed775ee7SAntonio Huete Jimenez ND_PRINT(", options [");
216411677aeSAaron LI
217411677aeSAaron LI if (ndo->ndo_vflag)
218411677aeSAaron LI geneve_opts_print(ndo, bp, opts_len);
219411677aeSAaron LI else
220*ed775ee7SAntonio Huete Jimenez ND_PRINT("%u bytes", opts_len);
221411677aeSAaron LI
222*ed775ee7SAntonio Huete Jimenez ND_PRINT("]");
223411677aeSAaron LI }
224411677aeSAaron LI
225411677aeSAaron LI bp += opts_len;
226411677aeSAaron LI len -= opts_len;
227411677aeSAaron LI
228411677aeSAaron LI if (ndo->ndo_vflag < 1)
229*ed775ee7SAntonio Huete Jimenez ND_PRINT(": ");
230411677aeSAaron LI else
231*ed775ee7SAntonio Huete Jimenez ND_PRINT("\n\t");
232411677aeSAaron LI
233*ed775ee7SAntonio Huete Jimenez if (ethertype_print(ndo, prot, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL) == 0) {
234411677aeSAaron LI if (prot == ETHERTYPE_TEB)
235*ed775ee7SAntonio Huete Jimenez ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
236411677aeSAaron LI else
237*ed775ee7SAntonio Huete Jimenez ND_PRINT("geneve-proto-0x%x", prot);
238411677aeSAaron LI }
239411677aeSAaron LI
240411677aeSAaron LI return;
241411677aeSAaron LI
242411677aeSAaron LI trunc:
243*ed775ee7SAntonio Huete Jimenez nd_print_trunc(ndo);
244411677aeSAaron LI }
245