]> The Tcpdump Group git mirrors - tcpdump/blob - print-geneve.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / print-geneve.c
1 /*
2 * Copyright (c) 2014 VMware, Inc. All Rights Reserved.
3 *
4 * Jesse Gross <jesse@nicira.com>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that: (1) source code
8 * distributions retain the above copyright notice and this paragraph
9 * in its entirety, and (2) distributions including binary code include
10 * the above copyright notice and this paragraph in its entirety in
11 * the documentation or other materials provided with the distribution.
12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
13 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
14 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
15 * FOR A PARTICULAR PURPOSE.
16 */
17
18 /* \summary: Generic Network Virtualization Encapsulation (Geneve) printer */
19 /* specification: RFC 8926 */
20
21 #include <config.h>
22
23 #include "netdissect-stdinc.h"
24
25 #define ND_LONGJMP_FROM_TCHECK
26 #include "netdissect.h"
27 #include "extract.h"
28 #include "ethertype.h"
29
30 /*
31 * Geneve header:
32 *
33 * 0 1 2 3
34 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * |Ver| Opt Len |O|C| Rsvd. | Protocol Type |
37 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 * | Virtual Network Identifier (VNI) | Reserved |
39 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 * | |
41 * ~ Variable-Length Options ~
42 * | |
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 *
45 * Options:
46 * 0 1 2 3
47 * 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
48 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49 * | Option Class | Type |R|R|R| Length |
50 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 * | |
52 * ~ Variable-Length Option Data ~
53 * | |
54 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 */
56
57 #define VER_SHIFT 6
58 #define HDR_OPTS_LEN_MASK 0x3F
59
60 #define FLAG_OAM (1 << 7)
61 #define FLAG_CRITICAL (1 << 6)
62 #define FLAG_R1 (1 << 5)
63 #define FLAG_R2 (1 << 4)
64 #define FLAG_R3 (1 << 3)
65 #define FLAG_R4 (1 << 2)
66 #define FLAG_R5 (1 << 1)
67 #define FLAG_R6 (1 << 0)
68
69 #define OPT_TYPE_CRITICAL (1 << 7)
70 #define OPT_LEN_MASK 0x1F
71
72 static const struct tok geneve_flag_values[] = {
73 { FLAG_OAM, "O" },
74 { FLAG_CRITICAL, "C" },
75 { FLAG_R1, "R1" },
76 { FLAG_R2, "R2" },
77 { FLAG_R3, "R3" },
78 { FLAG_R4, "R4" },
79 { FLAG_R5, "R5" },
80 { FLAG_R6, "R6" },
81 { 0, NULL }
82 };
83
84 static const char *
85 format_opt_class(const uint16_t opt_class)
86 {
87 switch (opt_class) {
88 case 0x0100:
89 return "Linux";
90 case 0x0101:
91 return "Open vSwitch";
92 case 0x0102:
93 return "Open Virtual Networking (OVN)";
94 case 0x0103:
95 return "In-band Network Telemetry (INT)";
96 case 0x0104:
97 return "VMware";
98 case 0x0105:
99 case 0x0108:
100 case 0x0109:
101 case 0x010A:
102 case 0x010B:
103 case 0x010C:
104 case 0x010D:
105 case 0x010E:
106 case 0x010F:
107 case 0x0110:
108 return "Amazon";
109 case 0x0106:
110 case 0x0130:
111 case 0x0131:
112 return "Cisco";
113 case 0x0107:
114 return "Oracle";
115 case 0x0111:
116 case 0x0112:
117 case 0x0113:
118 case 0x0114:
119 case 0x0115:
120 case 0x0116:
121 case 0x0117:
122 case 0x0118:
123 return "IBM";
124 case 0x0119:
125 case 0x011A:
126 case 0x011B:
127 case 0x011C:
128 case 0x011D:
129 case 0x011E:
130 case 0x011F:
131 case 0x0120:
132 case 0x0121:
133 case 0x0122:
134 case 0x0123:
135 case 0x0124:
136 case 0x0125:
137 case 0x0126:
138 case 0x0127:
139 case 0x0128:
140 return "Ericsson";
141 case 0x0129:
142 return "Oxide";
143 case 0x0132:
144 case 0x0133:
145 case 0x0134:
146 case 0x0135:
147 return "Google";
148 case 0x0136:
149 return "InfoQuick";
150 default:
151 if (opt_class <= 0x00ff)
152 return "Standard";
153 else if (opt_class >= 0xfff0)
154 return "Experimental";
155 }
156
157 return "Unknown";
158 }
159
160 static unsigned
161 geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len)
162 {
163 const char *sep = "";
164
165 while (len != 0) {
166 uint16_t opt_class;
167 uint8_t opt_type;
168 uint8_t opt_len;
169
170 ND_ICHECKMSG_U("remaining options length", len, <, 4);
171 ND_PRINT("%s", sep);
172 sep = ", ";
173
174 opt_class = GET_BE_U_2(bp);
175 opt_type = GET_U_1(bp + 2);
176 opt_len = 4 + ((GET_U_1(bp + 3) & OPT_LEN_MASK) * 4);
177
178 ND_PRINT("class %s (0x%x) type 0x%x%s len %u",
179 format_opt_class(opt_class), opt_class, opt_type,
180 opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len);
181
182 if (opt_len > len) {
183 ND_PRINT(" [bad length]");
184 goto invalid;
185 }
186
187 if (ndo->ndo_vflag > 1 && opt_len > 4) {
188 const uint32_t *data = (const uint32_t *)(bp + 4);
189 int i;
190
191 ND_PRINT(" data");
192
193 for (i = 4; i < opt_len; i += 4) {
194 ND_PRINT(" %08x", GET_BE_U_4(data));
195 data++;
196 }
197 } else
198 ND_TCHECK_LEN(bp, opt_len);
199
200 bp += opt_len;
201 len -= opt_len;
202 }
203 return 1;
204 invalid:
205 ND_TCHECK_LEN(bp, len);
206 return 0;
207 }
208
209 void
210 geneve_print(netdissect_options *ndo, const u_char *bp, u_int len)
211 {
212 uint8_t ver_opt;
213 u_int version;
214 uint8_t flags;
215 uint16_t prot;
216 uint32_t vni;
217 uint8_t reserved;
218 u_int opts_len;
219
220 ndo->ndo_protocol = "geneve";
221 ND_PRINT("Geneve");
222
223 ND_ICHECK_U(len, <, 8);
224
225 ver_opt = GET_U_1(bp);
226 bp += 1;
227 len -= 1;
228
229 version = ver_opt >> VER_SHIFT;
230 if (version != 0) {
231 ND_PRINT(" ERROR: unknown-version %u", version);
232 goto invalid;
233 }
234
235 flags = GET_U_1(bp);
236 bp += 1;
237 len -= 1;
238
239 prot = GET_BE_U_2(bp);
240 bp += 2;
241 len -= 2;
242
243 vni = GET_BE_U_3(bp);
244 bp += 3;
245 len -= 3;
246
247 reserved = GET_U_1(bp);
248 bp += 1;
249 len -= 1;
250
251 ND_PRINT(", Flags [%s]",
252 bittok2str_nosep(geneve_flag_values, "none", flags));
253 ND_PRINT(", vni 0x%x", vni);
254
255 if (reserved)
256 ND_PRINT(", rsvd 0x%x", reserved);
257
258 if (ndo->ndo_eflag)
259 ND_PRINT(", proto %s (0x%04x)",
260 tok2str(ethertype_values, "unknown", prot), prot);
261
262 opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4;
263
264 if (len < opts_len) {
265 ND_PRINT(" (opts_len %u > %u", opts_len, len);
266 goto invalid;
267 }
268
269 if (opts_len > 0) {
270 ND_PRINT(", options [");
271
272 if (ndo->ndo_vflag) {
273 if (! geneve_opts_print(ndo, bp, opts_len))
274 goto invalid;
275 } else {
276 ND_TCHECK_LEN(bp, opts_len);
277 ND_PRINT("%u bytes", opts_len);
278 }
279
280 ND_PRINT("]");
281 }
282
283 bp += opts_len;
284 len -= opts_len;
285
286 if (ndo->ndo_vflag < 1)
287 ND_PRINT(": ");
288 else
289 ND_PRINT("\n\t");
290
291 if (ethertype_print(ndo, prot, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL) == 0) {
292 if (prot == ETHERTYPE_TEB)
293 ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
294 else {
295 ND_PRINT("geneve-proto-0x%x", prot);
296 ND_TCHECK_LEN(bp, len);
297 }
298 }
299
300 return;
301
302 invalid:
303 nd_print_invalid(ndo);
304 }