/src/wireshark/epan/dissectors/packet-geneve.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* packet-geneve.c |
2 | | * Routines for Geneve - Generic Network Virtualization Encapsulation |
3 | | * https://tools.ietf.org/html/rfc8926 |
4 | | * |
5 | | * Copyright (c) 2024 cPacket Networks, Inc. All Rights Reserved. |
6 | | * Author: Martin Greenberg <mgreenberg@cpacket.com> |
7 | | * |
8 | | * Copyright (c) 2014 VMware, Inc. All Rights Reserved. |
9 | | * Author: Jesse Gross <jesse@nicira.com> |
10 | | * |
11 | | * Copyright 2021, Atul Sharma <asharm37@ncsu.edu> |
12 | | * |
13 | | * Wireshark - Network traffic analyzer |
14 | | * By Gerald Combs <gerald@wireshark.org> |
15 | | * Copyright 1998 Gerald Combs |
16 | | * |
17 | | * SPDX-License-Identifier: GPL-2.0-or-later |
18 | | */ |
19 | | |
20 | | |
21 | | #include "config.h" |
22 | | |
23 | | #include <epan/packet.h> |
24 | | #include <epan/etypes.h> |
25 | | #include <epan/expert.h> |
26 | | #include <epan/value_string.h> |
27 | | #include <epan/tfs.h> |
28 | | #include <epan/unit_strings.h> |
29 | | |
30 | 14 | #define UDP_PORT_GENEVE 6081 |
31 | 4.11k | #define GENEVE_VER 0 |
32 | | |
33 | 4.11k | #define VER_SHIFT 6 |
34 | 4.11k | #define HDR_OPTS_LEN_MASK 0x3F |
35 | | |
36 | 4.11k | #define FLAG_OAM (1 << 7) |
37 | | |
38 | 1.08k | #define OPT_TYPE_CRITICAL (1 << 7) |
39 | 1.08k | #define OPT_FLAGS_SHIFT 5 |
40 | 1.95k | #define OPT_LEN_MASK 0x1F |
41 | | |
42 | | /* https://www.iana.org/assignments/nvo3/nvo3.xhtml#geneve-option-class last update 2024-12-20 */ |
43 | | |
44 | | static const range_string class_id_names[] = { |
45 | | { 0, 0xFF, "Standard" }, |
46 | | { 0x0100, 0x0100, "Linux" }, |
47 | | { 0x0101, 0x0101, "Open vSwitch" }, |
48 | | { 0x0102, 0x0102, "Open Virtual Networking (OVN)" }, |
49 | | { 0x0103, 0x0103, "In-band Network Telemetry (INT)" }, |
50 | | { 0x0104, 0x0104, "VMware" }, |
51 | | { 0x0105, 0x0105, "Amazon.com, Inc."}, |
52 | | { 0x0106, 0x0106, "Cisco Systems, Inc." }, |
53 | | { 0x0107, 0x0107, "Oracle Corporation" }, |
54 | | { 0x0108, 0x0110, "Amazon.com, Inc." }, |
55 | | { 0x0111, 0x0118, "IBM" }, |
56 | | { 0x0119, 0x0128, "Ericsson" }, |
57 | | { 0x0129, 0x0129, "Oxide Computer Company" }, |
58 | | { 0x0130, 0x0131, "Cisco Systems, Inc." }, |
59 | | { 0x0132, 0x0135, "Google LLC" }, |
60 | | { 0x0136, 0x0136, "InfoQuick Global Connection Tech Ltd." }, |
61 | | { 0x0137, 0x0140, "Alibaba, inc" }, |
62 | | { 0x0141, 0x0144, "Palo Alto Networks" }, |
63 | | { 0x0145, 0x0149, "Huawei Technologies Co., Ltd" }, |
64 | | { 0x014A, 0x014A, "EMnify GmbH" }, |
65 | | { 0x014B, 0x014B, "Cilium" }, |
66 | | { 0x014C, 0x014C, "Corelight, Inc." }, |
67 | | { 0x014D, 0x014D, "1NCE GmbH" }, |
68 | | { 0x014E, 0x0157, "Cloud of China Telecom (CTYUN)" }, |
69 | | { 0x0158, 0x0161, "Volcengine, inc" }, |
70 | | { 0x0162, 0x0162, "nat64.net" }, |
71 | | { 0x0163, 0x0163, "Multi Segment SD-WAN" }, |
72 | | { 0x0164, 0x0164, "cPacket Networks, Inc." }, |
73 | | { 0x0165, 0x0167, "Tencent" }, |
74 | | { 0x0168, 0x0168, "ExtraHop Networks, Inc." }, |
75 | | { 0x0169, 0x0169, "Soosan INT Co., Ltd." }, |
76 | | { 0x016A, 0xFEFF, "Unassigned" }, |
77 | | { 0xFFF0, 0xFFFF, "Experimental" }, |
78 | | { 0, 0, NULL } |
79 | | }; |
80 | | |
81 | 1 | #define GENEVE_GCP_VNID 0x013201 |
82 | 1 | #define GENEVE_GCP_ENDPOINT 0x013202 |
83 | 0 | #define GENEVE_GCP_PROFILE 0x013203 |
84 | 0 | #define GENEVE_CILIUM_SERVICE 0x014B81 |
85 | 1 | #define GENEVE_CPACKET_METADATA 0x016400 |
86 | | |
87 | | static const val64_string option_names[] = { |
88 | | { GENEVE_GCP_VNID, "GCP Virtual Network ID" }, |
89 | | { GENEVE_GCP_ENDPOINT, "GCP Endpoint ID" }, |
90 | | { GENEVE_GCP_PROFILE, "GCP Profile ID" }, |
91 | | { GENEVE_CILIUM_SERVICE, "Cilium Service IP" }, |
92 | | { GENEVE_CPACKET_METADATA, "cPacket Meta-data" }, |
93 | | { 0, NULL } |
94 | | }; |
95 | | |
96 | | void proto_register_geneve(void); |
97 | | void proto_reg_handoff_geneve(void); |
98 | | |
99 | | static dissector_handle_t geneve_handle; |
100 | | |
101 | | static int proto_geneve; |
102 | | |
103 | | static int hf_geneve_version; |
104 | | static int hf_geneve_flags; |
105 | | static int hf_geneve_flag_oam; |
106 | | static int hf_geneve_flag_critical; |
107 | | static int hf_geneve_flag_reserved; |
108 | | static int hf_geneve_proto_type; |
109 | | static int hf_geneve_vni; |
110 | | static int hf_geneve_reserved; |
111 | | static int hf_geneve_options; |
112 | | static int hf_geneve_option_class; |
113 | | static int hf_geneve_option_type; |
114 | | static int hf_geneve_option_type_critical; |
115 | | static int hf_geneve_option_flags; |
116 | | static int hf_geneve_option_flags_reserved; |
117 | | static int hf_geneve_option_length; |
118 | | static int hf_geneve_option; |
119 | | static int hf_geneve_opt_gcp_vnid; |
120 | | static int hf_geneve_opt_gcp_reserved; |
121 | | static int hf_geneve_opt_gcp_direction; |
122 | | static int hf_geneve_opt_gcp_endpoint; |
123 | | static int hf_geneve_opt_gcp_profile; |
124 | | static int hf_geneve_opt_cilium_service_ipv4; |
125 | | static int hf_geneve_opt_cilium_service_ipv6; |
126 | | static int hf_geneve_opt_cilium_service_port; |
127 | | static int hf_geneve_opt_cilium_service_pad; |
128 | | static int hf_geneve_opt_cpkt_seqnum; |
129 | | static int hf_geneve_opt_cpkt_origlen; |
130 | | static int hf_geneve_opt_cpkt_reserved; |
131 | | static int hf_geneve_opt_cpkt_timestamp; |
132 | | static int hf_geneve_opt_cpkt_ts_sec; |
133 | | static int hf_geneve_opt_cpkt_ts_nsec; |
134 | | static int hf_geneve_opt_cpkt_ts_fracns; |
135 | | static int hf_geneve_opt_cpkt_version; |
136 | | static int hf_geneve_opt_cpkt_devid; |
137 | | static int hf_geneve_opt_cpkt_portid; |
138 | | |
139 | | static int hf_geneve_opt_unknown_data; |
140 | | |
141 | | static int ett_geneve; |
142 | | static int ett_geneve_flags; |
143 | | static int ett_geneve_opt_flags; |
144 | | static int ett_geneve_options; |
145 | | static int ett_geneve_opt_data; |
146 | | |
147 | | static expert_field ei_geneve_ver_unknown; |
148 | | static expert_field ei_geneve_opt_len_invalid; |
149 | | |
150 | | static dissector_table_t ethertype_dissector_table; |
151 | | |
152 | | static const struct true_false_string tfs_geneve_gcp_direction = { |
153 | | "Egress", |
154 | | "Ingress" |
155 | | }; |
156 | | |
157 | | static const char * |
158 | | format_option_name(wmem_allocator_t *scope, uint16_t opt_class, uint8_t opt_type) |
159 | 1.95k | { |
160 | 1.95k | const char *name; |
161 | | |
162 | 1.95k | name = wmem_strdup_printf(scope, |
163 | 1.95k | "%s, Class: %s (0x%04x) Type: 0x%02x", |
164 | 1.95k | val64_to_str_const(((uint64_t)opt_class << 8) | opt_type, |
165 | 1.95k | option_names, "Unknown"), |
166 | 1.95k | rval_to_str_const(opt_class, class_id_names, "Unknown"), |
167 | 1.95k | opt_class, opt_type); |
168 | | |
169 | 1.95k | return name; |
170 | 1.95k | } |
171 | | |
172 | | static void |
173 | | dissect_option(wmem_allocator_t *scope, tvbuff_t *tvb, proto_tree *opts_tree, int offset, |
174 | | uint16_t opt_class, uint8_t opt_type, int len) |
175 | 1.08k | { |
176 | 1.08k | proto_item *opt_item, *type_item, *hidden_item, *flag_item; |
177 | 1.08k | proto_tree *opt_tree, *flag_tree; |
178 | 1.08k | const char *critical; |
179 | 1.08k | uint8_t flags; |
180 | | |
181 | 1.08k | critical = opt_type & OPT_TYPE_CRITICAL ? "Critical" : "Non-critical"; |
182 | | |
183 | 1.08k | opt_item = proto_tree_add_item(opts_tree, hf_geneve_option, |
184 | 1.08k | tvb, offset, len, ENC_NA); |
185 | 1.08k | proto_item_set_text(opt_item, "%s (%s)", |
186 | 1.08k | format_option_name(scope, opt_class, opt_type), |
187 | 1.08k | critical); |
188 | | |
189 | 1.08k | opt_tree = proto_item_add_subtree(opt_item, ett_geneve_opt_data); |
190 | | |
191 | 1.08k | proto_tree_add_item(opt_tree, hf_geneve_option_class, tvb, |
192 | 1.08k | offset, 2, ENC_BIG_ENDIAN); |
193 | 1.08k | offset += 2; |
194 | | |
195 | 1.08k | type_item = proto_tree_add_item(opt_tree, hf_geneve_option_type, tvb, |
196 | 1.08k | offset, 1, ENC_BIG_ENDIAN); |
197 | 1.08k | proto_item_append_text(type_item, " (%s)", critical); |
198 | 1.08k | hidden_item = proto_tree_add_item(opt_tree, hf_geneve_option_type_critical, |
199 | 1.08k | tvb, offset, 1, ENC_BIG_ENDIAN); |
200 | 1.08k | proto_item_set_hidden(hidden_item); |
201 | 1.08k | offset += 1; |
202 | | |
203 | 1.08k | flags = tvb_get_uint8(tvb, offset) >> OPT_FLAGS_SHIFT; |
204 | 1.08k | flag_item = proto_tree_add_uint(opt_tree, hf_geneve_option_flags, tvb, |
205 | 1.08k | offset, 1, flags); |
206 | 1.08k | flag_tree = proto_item_add_subtree(flag_item, ett_geneve_opt_flags); |
207 | 1.08k | proto_tree_add_item(flag_tree, hf_geneve_option_flags_reserved, tvb, |
208 | 1.08k | offset, 1, ENC_BIG_ENDIAN); |
209 | 1.08k | if (flags) { |
210 | 392 | proto_item_append_text(flag_item, " (RSVD)"); |
211 | 694 | } else { |
212 | 694 | proto_item_set_hidden(flag_item); |
213 | 694 | } |
214 | | |
215 | 1.08k | proto_tree_add_uint(opt_tree, hf_geneve_option_length, tvb, offset, 1, len); |
216 | 1.08k | offset += 1; |
217 | | |
218 | 1.08k | switch (((uint64_t)opt_class << 8) | opt_type) { |
219 | 1 | case GENEVE_GCP_VNID: |
220 | 1 | proto_tree_add_bits_item(opt_tree, hf_geneve_opt_gcp_vnid, tvb, offset * 8, |
221 | 1 | 28, ENC_BIG_ENDIAN); |
222 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_gcp_direction, tvb, offset, |
223 | 1 | 4, ENC_BIG_ENDIAN); |
224 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_gcp_reserved, tvb, offset, |
225 | 1 | 4, ENC_BIG_ENDIAN); |
226 | 1 | break; |
227 | 1 | case GENEVE_GCP_ENDPOINT: |
228 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_gcp_endpoint, tvb, offset, |
229 | 1 | len - 4, ENC_NA); |
230 | 1 | break; |
231 | 0 | case GENEVE_GCP_PROFILE: |
232 | 0 | proto_tree_add_item(opt_tree, hf_geneve_opt_gcp_profile, tvb, offset, |
233 | 0 | len - 4, ENC_BIG_ENDIAN); |
234 | 0 | break; |
235 | 0 | case GENEVE_CILIUM_SERVICE: |
236 | 0 | switch (len) { |
237 | 0 | case 12: { |
238 | 0 | proto_tree_add_item(opt_tree, hf_geneve_opt_cilium_service_ipv4, tvb, offset, |
239 | 0 | 4, ENC_BIG_ENDIAN); |
240 | 0 | offset += 4; |
241 | 0 | proto_tree_add_item(opt_tree, hf_geneve_opt_cilium_service_port, tvb, offset, |
242 | 0 | 2, ENC_BIG_ENDIAN); |
243 | 0 | offset += 2; |
244 | 0 | proto_tree_add_item(opt_tree, hf_geneve_opt_cilium_service_pad, tvb, offset, |
245 | 0 | 2, ENC_NA); |
246 | 0 | } |
247 | 0 | break; |
248 | 0 | case 24: { |
249 | 0 | proto_tree_add_item(opt_tree, hf_geneve_opt_cilium_service_ipv6, tvb, offset, |
250 | 0 | 16, ENC_NA); |
251 | 0 | offset += 16; |
252 | 0 | proto_tree_add_item(opt_tree, hf_geneve_opt_cilium_service_port, tvb, offset, |
253 | 0 | 2, ENC_BIG_ENDIAN); |
254 | 0 | offset += 2; |
255 | 0 | proto_tree_add_item(opt_tree, hf_geneve_opt_cilium_service_pad, tvb, offset, |
256 | 0 | 2, ENC_NA); |
257 | 0 | } |
258 | 0 | break; |
259 | 0 | default: |
260 | 0 | proto_tree_add_item(opt_tree, hf_geneve_opt_unknown_data, tvb, offset, |
261 | 0 | len - 4, ENC_NA); |
262 | 0 | break; |
263 | 0 | } |
264 | 0 | break; |
265 | 1 | case GENEVE_CPACKET_METADATA: |
266 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_cpkt_seqnum, tvb, offset, |
267 | 1 | 4, ENC_BIG_ENDIAN); |
268 | 1 | offset += 4; |
269 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_cpkt_origlen, tvb, offset, |
270 | 1 | 2, ENC_BIG_ENDIAN); |
271 | 1 | offset += 2; |
272 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_cpkt_reserved, tvb, offset, |
273 | 1 | 1, ENC_BIG_ENDIAN); |
274 | 1 | offset += 1; |
275 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_cpkt_version, tvb, offset, |
276 | 1 | 1, ENC_BIG_ENDIAN); |
277 | 1 | offset += 1; |
278 | | // PTPv2 timestamp has more resolution than NStime supports/displays, |
279 | | // but parse appropriate subsection of into NStime for user convenience |
280 | 1 | proto_tree_add_time_item(opt_tree, hf_geneve_opt_cpkt_timestamp, tvb, offset+2, 8, |
281 | 1 | ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN, NULL, NULL, NULL); |
282 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_cpkt_ts_sec, tvb, offset, |
283 | 1 | 6, ENC_BIG_ENDIAN); |
284 | 1 | offset += 6; |
285 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_cpkt_ts_nsec, tvb, offset, |
286 | 1 | 4, ENC_BIG_ENDIAN); |
287 | 1 | offset += 4; |
288 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_cpkt_ts_fracns, tvb, offset, |
289 | 1 | 2, ENC_BIG_ENDIAN); |
290 | 1 | offset += 2; |
291 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_cpkt_devid, tvb, offset, |
292 | 1 | 2, ENC_BIG_ENDIAN); |
293 | 1 | offset += 2; |
294 | 1 | proto_tree_add_item(opt_tree, hf_geneve_opt_cpkt_portid, tvb, offset, |
295 | 1 | 2, ENC_BIG_ENDIAN); |
296 | 1 | break; |
297 | 1.08k | default: |
298 | 1.08k | proto_tree_add_item(opt_tree, hf_geneve_opt_unknown_data, tvb, offset, |
299 | 1.08k | len - 4, ENC_NA); |
300 | 1.08k | break; |
301 | 1.08k | } |
302 | 1.08k | } |
303 | | |
304 | | static void |
305 | | dissect_geneve_options(tvbuff_t *tvb, packet_info *pinfo, |
306 | | proto_tree *geneve_tree, int offset, int len) |
307 | 920 | { |
308 | 920 | proto_item *opts_item; |
309 | 920 | proto_tree *opts_tree; |
310 | 920 | uint16_t opt_class; |
311 | 920 | uint8_t opt_type; |
312 | 920 | uint8_t opt_len; |
313 | | |
314 | 920 | opts_item = proto_tree_add_item(geneve_tree, hf_geneve_options, tvb, |
315 | 920 | offset, len, ENC_NA); |
316 | 920 | proto_item_set_text(opts_item, "Options: (%u bytes)", len); |
317 | 920 | opts_tree = proto_item_add_subtree(opts_item, ett_geneve_options); |
318 | | |
319 | 2.00k | while (len > 0) { |
320 | 1.95k | opt_class = tvb_get_ntohs(tvb, offset); |
321 | 1.95k | opt_type = tvb_get_uint8(tvb, offset + 2); |
322 | 1.95k | opt_len = 4 + ((tvb_get_uint8(tvb, offset + 3) & OPT_LEN_MASK) * 4); |
323 | | |
324 | 1.95k | if (opt_len > len) { |
325 | 865 | proto_tree_add_expert_format(opts_tree, pinfo, |
326 | 865 | &ei_geneve_opt_len_invalid, tvb, |
327 | 865 | offset + 3, 1, |
328 | 865 | "%s (length of %u is past end of options)", |
329 | 865 | format_option_name(pinfo->pool, opt_class, opt_type), |
330 | 865 | opt_len); |
331 | 865 | return; |
332 | 865 | } |
333 | | |
334 | 1.08k | dissect_option(pinfo->pool, tvb, opts_tree, offset, opt_class, opt_type, opt_len); |
335 | | |
336 | 1.08k | offset += opt_len; |
337 | 1.08k | len -= opt_len; |
338 | 1.08k | }; |
339 | 55 | } |
340 | | |
341 | | static int |
342 | | dissect_geneve(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
343 | 4.11k | { |
344 | 4.11k | proto_item *ti, *rsvd_item; |
345 | 4.11k | proto_tree *geneve_tree; |
346 | 4.11k | tvbuff_t *next_tvb; |
347 | 4.11k | int offset = 0; |
348 | 4.11k | uint8_t ver_opt; |
349 | 4.11k | uint8_t ver; |
350 | 4.11k | uint8_t flags; |
351 | 4.11k | uint16_t proto_type; |
352 | 4.11k | int opts_len; |
353 | 4.11k | static int * const flag_fields[] = { |
354 | 4.11k | &hf_geneve_flag_oam, |
355 | 4.11k | &hf_geneve_flag_critical, |
356 | 4.11k | &hf_geneve_flag_reserved, |
357 | 4.11k | NULL |
358 | 4.11k | }; |
359 | | |
360 | 4.11k | col_set_str(pinfo->cinfo, COL_PROTOCOL, "Geneve"); |
361 | 4.11k | col_clear(pinfo->cinfo, COL_INFO); |
362 | | |
363 | 4.11k | ti = proto_tree_add_item(tree, proto_geneve, tvb, offset, -1, ENC_NA); |
364 | 4.11k | geneve_tree = proto_item_add_subtree(ti, ett_geneve); |
365 | | |
366 | | /* Version. */ |
367 | 4.11k | ver_opt = tvb_get_uint8(tvb, offset); |
368 | 4.11k | ver = ver_opt >> VER_SHIFT; |
369 | 4.11k | proto_tree_add_uint(geneve_tree, hf_geneve_version, tvb, |
370 | 4.11k | offset, 1, ver); |
371 | | |
372 | 4.11k | if (ver != GENEVE_VER) { |
373 | 1.47k | proto_tree_add_expert_format(geneve_tree, pinfo, |
374 | 1.47k | &ei_geneve_ver_unknown, tvb, offset, 1, |
375 | 1.47k | "Unknown version %u", ver); |
376 | 1.47k | col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown Geneve version %u", ver); |
377 | 1.47k | } |
378 | | |
379 | | /* Option length. */ |
380 | 4.11k | opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4; |
381 | 4.11k | proto_tree_add_uint(geneve_tree, hf_geneve_option_length, tvb, |
382 | 4.11k | offset, 1, opts_len); |
383 | 4.11k | offset += 1; |
384 | | |
385 | | /* Flags. */ |
386 | 4.11k | flags = tvb_get_uint8(tvb, offset); |
387 | 4.11k | proto_tree_add_bitmask(geneve_tree, tvb, offset, hf_geneve_flags, ett_geneve_flags, flag_fields, ENC_BIG_ENDIAN); |
388 | 4.11k | offset += 1; |
389 | | |
390 | | /* Protocol Type. */ |
391 | 4.11k | proto_tree_add_item(geneve_tree, hf_geneve_proto_type, tvb, |
392 | 4.11k | offset, 2, ENC_BIG_ENDIAN); |
393 | | |
394 | 4.11k | proto_type = tvb_get_ntohs(tvb, offset); |
395 | 4.11k | col_add_fstr(pinfo->cinfo, COL_INFO, "Encapsulated %s", |
396 | 4.11k | val_to_str(proto_type, etype_vals, "0x%04x (unknown)")); |
397 | | |
398 | 4.11k | offset += 2; |
399 | | |
400 | | /* VNI. */ |
401 | 4.11k | proto_tree_add_item(geneve_tree, hf_geneve_vni, tvb, offset, 3, |
402 | 4.11k | ENC_BIG_ENDIAN); |
403 | 4.11k | proto_item_append_text(ti, ", VNI: 0x%06x%s", tvb_get_ntoh24(tvb, offset), |
404 | 4.11k | flags & FLAG_OAM ? ", OAM" : ""); |
405 | 4.11k | offset += 3; |
406 | | |
407 | | /* Reserved. */ |
408 | 4.11k | rsvd_item = proto_tree_add_item(geneve_tree, hf_geneve_reserved, tvb, |
409 | 4.11k | offset, 1, ENC_BIG_ENDIAN); |
410 | 4.11k | if (!tvb_get_uint8(tvb, offset)) { |
411 | 495 | proto_item_set_hidden(rsvd_item); |
412 | 495 | } |
413 | 4.11k | offset += 1; |
414 | | |
415 | | /* Options. */ |
416 | 4.11k | if (tree && opts_len) { |
417 | 920 | dissect_geneve_options(tvb, pinfo, geneve_tree, offset, opts_len); |
418 | 920 | } |
419 | 4.11k | offset += opts_len; |
420 | | |
421 | 4.11k | proto_item_set_len(ti, offset); |
422 | | |
423 | 4.11k | next_tvb = tvb_new_subset_remaining(tvb, offset); |
424 | 4.11k | if (!dissector_try_uint(ethertype_dissector_table, proto_type, next_tvb, pinfo, tree)) |
425 | 56 | call_data_dissector(next_tvb, pinfo, tree); |
426 | | |
427 | 4.11k | return tvb_captured_length(tvb); |
428 | 4.11k | } |
429 | | |
430 | | /* Register Geneve with Wireshark */ |
431 | | void |
432 | | proto_register_geneve(void) |
433 | 14 | { |
434 | 14 | static hf_register_info hf[] = { |
435 | 14 | { &hf_geneve_version, |
436 | 14 | { "Version", "geneve.version", |
437 | 14 | FT_UINT8, BASE_DEC, NULL, 0x00, |
438 | 14 | NULL, HFILL } |
439 | 14 | }, |
440 | 14 | { &hf_geneve_flags, |
441 | 14 | { "Flags", "geneve.flags", |
442 | 14 | FT_UINT8, BASE_HEX, NULL, 0x00, |
443 | 14 | NULL, HFILL } |
444 | 14 | }, |
445 | 14 | { &hf_geneve_flag_oam, |
446 | 14 | { "Operations, Administration and Management Frame", "geneve.flags.oam", |
447 | 14 | FT_BOOLEAN, 8, NULL, 0x80, |
448 | 14 | NULL, HFILL } |
449 | 14 | }, |
450 | 14 | { &hf_geneve_flag_critical, |
451 | 14 | { "Critical Options Present", "geneve.flags.critical", |
452 | 14 | FT_BOOLEAN, 8, NULL, 0x40, |
453 | 14 | NULL, HFILL } |
454 | 14 | }, |
455 | 14 | { &hf_geneve_flag_reserved, |
456 | 14 | { "Reserved", "geneve.flags.reserved", |
457 | 14 | FT_BOOLEAN, 8, NULL, 0x3F, |
458 | 14 | NULL, HFILL } |
459 | 14 | }, |
460 | 14 | { &hf_geneve_proto_type, |
461 | 14 | { "Protocol Type", "geneve.proto_type", |
462 | 14 | FT_UINT16, BASE_HEX, VALS(etype_vals), 0x0, |
463 | 14 | NULL, HFILL } |
464 | 14 | }, |
465 | 14 | { &hf_geneve_vni, |
466 | 14 | { "Virtual Network Identifier (VNI)", "geneve.vni", |
467 | 14 | FT_UINT24, BASE_HEX_DEC, NULL, 0x0, |
468 | 14 | NULL, HFILL } |
469 | 14 | }, |
470 | 14 | { &hf_geneve_reserved, |
471 | 14 | { "Reserved", "geneve.reserved", |
472 | 14 | FT_UINT8, BASE_HEX, NULL, 0x00, |
473 | 14 | NULL, HFILL } |
474 | 14 | }, |
475 | 14 | { &hf_geneve_options, |
476 | 14 | { "Geneve Options", "geneve.options", |
477 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
478 | 14 | NULL, HFILL } |
479 | 14 | }, |
480 | 14 | { &hf_geneve_option_class, |
481 | 14 | { "Class", "geneve.option.class", |
482 | 14 | FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(class_id_names), 0x00, |
483 | 14 | NULL, HFILL } |
484 | 14 | }, |
485 | 14 | { &hf_geneve_option_type, |
486 | 14 | { "Type", "geneve.option.type", |
487 | 14 | FT_UINT8, BASE_HEX, NULL, 0x00, |
488 | 14 | NULL, HFILL } |
489 | 14 | }, |
490 | 14 | { &hf_geneve_option_type_critical, |
491 | 14 | { "Critical Option", "geneve.option.type.critical", |
492 | 14 | FT_BOOLEAN, 8, NULL, 0x80, |
493 | 14 | NULL, HFILL } |
494 | 14 | }, |
495 | 14 | { &hf_geneve_option_flags, |
496 | 14 | { "Flags", "geneve.option.flags", |
497 | 14 | FT_UINT8, BASE_HEX, NULL, 0x00, |
498 | 14 | NULL, HFILL } |
499 | 14 | }, |
500 | 14 | { &hf_geneve_option_flags_reserved, |
501 | 14 | { "Reserved", "geneve.option.flags.reserved", |
502 | 14 | FT_BOOLEAN, 8, NULL, 0xE0, |
503 | 14 | NULL, HFILL } |
504 | 14 | }, |
505 | 14 | { &hf_geneve_option_length, |
506 | 14 | { "Length", "geneve.option.length", |
507 | 14 | FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x00, |
508 | 14 | NULL, HFILL } |
509 | 14 | }, |
510 | 14 | { &hf_geneve_option, |
511 | 14 | { "Option", "geneve.option", |
512 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
513 | 14 | NULL, HFILL } |
514 | 14 | }, |
515 | 14 | { &hf_geneve_opt_gcp_vnid, |
516 | 14 | { "GCP Virtual Network ID", "geneve.option.gcp.vnid", |
517 | 14 | FT_UINT32, BASE_DEC, NULL, 0x00, |
518 | 14 | NULL, HFILL } |
519 | 14 | }, |
520 | 14 | { &hf_geneve_opt_gcp_reserved, |
521 | 14 | { "GCP Reserved bits", "geneve.option.gcp.reserved", |
522 | 14 | FT_BOOLEAN, 32, NULL, 0x0000000E, |
523 | 14 | NULL, HFILL } |
524 | 14 | }, |
525 | 14 | { &hf_geneve_opt_gcp_direction, |
526 | 14 | { "GCP Traffic Direction", "geneve.option.gcp.direction", |
527 | 14 | FT_BOOLEAN, 32, TFS(&tfs_geneve_gcp_direction), 0x00000001, |
528 | 14 | NULL, HFILL } |
529 | 14 | }, |
530 | 14 | { &hf_geneve_opt_gcp_endpoint, |
531 | 14 | { "GCP Endpoint ID", "geneve.option.gcp.endpoint", |
532 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
533 | 14 | NULL, HFILL } |
534 | 14 | }, |
535 | 14 | { &hf_geneve_opt_gcp_profile, |
536 | 14 | { "GCP Profile ID", "geneve.option.gcp.profile", |
537 | 14 | FT_UINT64, BASE_DEC, NULL, 0x00, |
538 | 14 | NULL, HFILL } |
539 | 14 | }, |
540 | 14 | { &hf_geneve_opt_cilium_service_ipv4, |
541 | 14 | { "Cilium Service IPv4", "geneve.option.cilium.service.ipv4", |
542 | 14 | FT_IPv4, BASE_NONE, NULL, 0x00, |
543 | 14 | NULL, HFILL } |
544 | 14 | }, |
545 | 14 | { &hf_geneve_opt_cilium_service_ipv6, |
546 | 14 | { "Cilium Service IPv6", "geneve.option.cilium.service.ipv6", |
547 | 14 | FT_IPv6, BASE_NONE, NULL, 0x00, |
548 | 14 | NULL, HFILL } |
549 | 14 | }, |
550 | 14 | { &hf_geneve_opt_cilium_service_port, |
551 | 14 | { "Cilium Service Port", "geneve.option.cilium.service.port", |
552 | 14 | FT_UINT16, BASE_DEC, NULL, 0x00, |
553 | 14 | NULL, HFILL } |
554 | 14 | }, |
555 | 14 | { &hf_geneve_opt_cilium_service_pad, |
556 | 14 | { "Pad", "geneve.option.cilium.service.pad", |
557 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
558 | 14 | NULL, HFILL } |
559 | 14 | }, |
560 | 14 | { &hf_geneve_opt_cpkt_seqnum, |
561 | 14 | { "cPacket Packet ID", "geneve.option.cPacket.packetid", |
562 | 14 | FT_UINT32, BASE_DEC, NULL, 0x00, |
563 | 14 | NULL, HFILL } |
564 | 14 | }, |
565 | 14 | { &hf_geneve_opt_cpkt_origlen, |
566 | 14 | { "cPacket Original length", "geneve.option.cPacket.orig_len", |
567 | 14 | FT_UINT16, BASE_DEC, NULL, 0x00, |
568 | 14 | NULL, HFILL } |
569 | 14 | }, |
570 | 14 | { &hf_geneve_opt_cpkt_reserved, |
571 | 14 | { "cPacket Reserved", "geneve.option.cPacket.reserved", |
572 | 14 | FT_UINT8, BASE_HEX, NULL, 0x00, |
573 | 14 | NULL, HFILL } |
574 | 14 | }, |
575 | 14 | { &hf_geneve_opt_cpkt_version, |
576 | 14 | { "cPacket Metadata version", "geneve.option.cPacket.version", |
577 | 14 | FT_UINT8, BASE_DEC, NULL, 0x00, |
578 | 14 | NULL, HFILL } |
579 | 14 | }, |
580 | 14 | { &hf_geneve_opt_cpkt_timestamp, |
581 | 14 | { "cPacket Timestamp", "geneve.option.cPacket.timestamp", |
582 | 14 | FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x00, |
583 | 14 | NULL, HFILL } |
584 | 14 | }, |
585 | 14 | { &hf_geneve_opt_cpkt_ts_sec, |
586 | 14 | { "cPacket Timestamp (s)", "geneve.option.cPacket.ts_sec", |
587 | 14 | FT_UINT48, BASE_DEC, NULL, 0x00, |
588 | 14 | NULL, HFILL } |
589 | 14 | }, |
590 | 14 | { &hf_geneve_opt_cpkt_ts_nsec, |
591 | 14 | { "cPacket Timestamp (ns)", "geneve.option.cPacket.ts_nsec", |
592 | 14 | FT_UINT32, BASE_DEC, NULL, 0x00, |
593 | 14 | NULL, HFILL } |
594 | 14 | }, |
595 | 14 | { &hf_geneve_opt_cpkt_ts_fracns, |
596 | 14 | { "cPacket Timestamp (frac. ns)", "geneve.option.cPacket.ts_fracns", |
597 | 14 | FT_UINT16, BASE_DEC, NULL, 0x00, |
598 | 14 | NULL, HFILL } |
599 | 14 | }, |
600 | 14 | { &hf_geneve_opt_cpkt_devid, |
601 | 14 | { "cPacket Device ID", "geneve.option.cPacket.device_id", |
602 | 14 | FT_UINT16, BASE_DEC, NULL, 0x00, |
603 | 14 | NULL, HFILL } |
604 | 14 | }, |
605 | 14 | { &hf_geneve_opt_cpkt_portid, |
606 | 14 | { "cPacket Port ID", "geneve.option.cPacket.port_id", |
607 | 14 | FT_UINT16, BASE_DEC, NULL, 0x00, |
608 | 14 | NULL, HFILL } |
609 | 14 | }, |
610 | 14 | { &hf_geneve_opt_unknown_data, |
611 | 14 | { "Unknown Option Data", "geneve.option.unknown.data", |
612 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
613 | 14 | NULL, HFILL } |
614 | 14 | }, |
615 | 14 | }; |
616 | | |
617 | 14 | static int *ett[] = { |
618 | 14 | &ett_geneve, |
619 | 14 | &ett_geneve_flags, |
620 | 14 | &ett_geneve_options, |
621 | 14 | &ett_geneve_opt_flags, |
622 | 14 | &ett_geneve_opt_data, |
623 | 14 | }; |
624 | | |
625 | 14 | static ei_register_info ei[] = { |
626 | 14 | { &ei_geneve_ver_unknown, { "geneve.version.unknown", |
627 | 14 | PI_PROTOCOL, PI_WARN, "Unknown version", EXPFILL }}, |
628 | 14 | { &ei_geneve_opt_len_invalid, { "geneve.option.length.invalid", |
629 | 14 | PI_PROTOCOL, PI_WARN, "Invalid length for option", EXPFILL }}, |
630 | 14 | }; |
631 | | |
632 | 14 | expert_module_t *expert_geneve; |
633 | | |
634 | | /* Register the protocol name and description */ |
635 | 14 | proto_geneve = proto_register_protocol("Generic Network Virtualization Encapsulation", |
636 | 14 | "Geneve", "geneve"); |
637 | | |
638 | 14 | proto_register_field_array(proto_geneve, hf, array_length(hf)); |
639 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
640 | | |
641 | 14 | expert_geneve = expert_register_protocol(proto_geneve); |
642 | 14 | expert_register_field_array(expert_geneve, ei, array_length(ei)); |
643 | | |
644 | 14 | geneve_handle = register_dissector("geneve", dissect_geneve, proto_geneve); |
645 | 14 | } |
646 | | |
647 | | void |
648 | | proto_reg_handoff_geneve(void) |
649 | 14 | { |
650 | 14 | dissector_add_uint_with_preference("udp.port", UDP_PORT_GENEVE, geneve_handle); |
651 | | |
652 | 14 | ethertype_dissector_table = find_dissector_table("ethertype"); |
653 | 14 | } |
654 | | |
655 | | /* |
656 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
657 | | * |
658 | | * Local variables: |
659 | | * c-basic-offset: 4 |
660 | | * tab-width: 8 |
661 | | * indent-tabs-mode: nil |
662 | | * End: |
663 | | * |
664 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
665 | | * :indentSize=4:tabSize=8:noTabs=true: |
666 | | */ |