3 * Routines for the disassembly of fd.io vpp project
6 * Copyright (c) 2018 Cisco and/or its affiliates.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at:
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 * This version is not to be upstreamed as-is, since it hooks up the
20 * vpp dissector to WTAP_ENCAP_USER13, a test encap type.
25 #include <epan/packet.h>
26 #include <epan/expert.h>
27 #include <epan/to_str.h>
28 #include <epan/in_cksum.h>
29 #include <epan/nlpid.h>
30 #include <epan/etypes.h>
32 #include <wsutil/ws_printf.h>
34 void proto_register_vpp(void);
35 void proto_reg_handoff_vpp(void);
37 static int proto_vpp = -1;
38 static int proto_vpp_metadata = -1;
39 static int proto_vpp_opaque = -1;
40 static int proto_vpp_opaque2 = -1;
41 static int proto_vpp_trace = -1;
42 static int hf_vpp_nodename = -1;
43 static int hf_vpp_metadata = -1;
44 static int hf_vpp_buffer_index = -1;
45 static int hf_vpp_buffer_opaque = -1;
46 static int hf_vpp_buffer_opaque2 = -1;
47 static int hf_vpp_buffer_trace = -1;
49 static gint ett_vpp = -1;
50 static gint ett_vpp_opaque = -1;
51 static gint ett_vpp_opaque2 = -1;
52 static gint ett_vpp_metadata = -1;
53 static gint ett_vpp_trace = -1;
55 static dissector_handle_t vpp_dissector_handle;
56 static dissector_handle_t vpp_opaque_dissector_handle;
57 static dissector_handle_t vpp_opaque2_dissector_handle;
58 static dissector_handle_t vpp_metadata_dissector_handle;
59 static dissector_handle_t vpp_trace_dissector_handle;
63 VLIB_NODE_PROTO_HINT_NONE = 0,
64 VLIB_NODE_PROTO_HINT_ETHERNET,
65 VLIB_NODE_PROTO_HINT_IP4,
66 VLIB_NODE_PROTO_HINT_IP6,
67 VLIB_NODE_PROTO_HINT_TCP,
68 VLIB_NODE_PROTO_HINT_UDP,
69 VLIB_NODE_N_PROTO_HINTS,
70 } vlib_node_proto_hint_t;
72 static dissector_handle_t next_dissectors[VLIB_NODE_N_PROTO_HINTS];
74 /* List of next dissectors hints that we know about */
75 #define foreach_next_dissector \
76 _(VLIB_NODE_PROTO_HINT_ETHERNET, eth_maybefcs) \
77 _(VLIB_NODE_PROTO_HINT_IP4, ip) \
78 _(VLIB_NODE_PROTO_HINT_IP6, ipv6) \
79 _(VLIB_NODE_PROTO_HINT_TCP, tcp) \
80 _(VLIB_NODE_PROTO_HINT_UDP, udp)
83 add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
91 line_len = tvb_find_line_end(tvb, start, len, &next, FALSE);
92 data_len = next - start;
93 proto_tree_add_string(tree, hf, tvb, start, data_len,
94 tvb_format_stringzpad(tvb, start, line_len));
101 dissect_vpp_metadata (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
106 proto_tree *metadata_tree;
107 gint metadata_string_length;
109 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Metadata");
110 col_clear(pinfo->cinfo, COL_INFO);
112 ti = proto_tree_add_item(tree, proto_vpp_metadata, tvb, offset, -1, ENC_NA);
113 metadata_tree = proto_item_add_subtree(ti, ett_vpp_metadata);
115 /* How long is the metadata string? */
116 metadata_string_length = tvb_strsize (tvb, offset);
118 add_multi_line_string_to_tree (metadata_tree, tvb, 0,
119 metadata_string_length,
121 return tvb_captured_length(tvb);
125 dissect_vpp_trace (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
130 proto_tree *trace_tree;
131 gint trace_string_length;
133 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Trace");
134 col_clear(pinfo->cinfo, COL_INFO);
136 ti = proto_tree_add_item(tree, proto_vpp_trace, tvb, offset, -1, ENC_NA);
137 trace_tree = proto_item_add_subtree(ti, ett_vpp_trace);
139 /* How long is the trace string? */
140 trace_string_length = tvb_strsize (tvb, offset);
142 add_multi_line_string_to_tree (trace_tree, tvb, 0,
144 hf_vpp_buffer_trace);
145 return tvb_captured_length(tvb);
150 dissect_vpp_opaque (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
155 proto_tree *opaque_tree;
156 gint opaque_string_length;
158 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Opaque");
159 col_clear(pinfo->cinfo, COL_INFO);
161 ti = proto_tree_add_item(tree, proto_vpp_opaque, tvb, offset, -1, ENC_NA);
162 opaque_tree = proto_item_add_subtree(ti, ett_vpp_opaque);
164 opaque_string_length = tvb_strsize (tvb, offset);
165 add_multi_line_string_to_tree (opaque_tree, tvb, 0, opaque_string_length,
166 hf_vpp_buffer_opaque);
168 return tvb_captured_length(tvb);
172 dissect_vpp_opaque2 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
177 proto_tree *opaque2_tree;
178 gint opaque2_string_length;
180 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Opaque2");
181 col_clear(pinfo->cinfo, COL_INFO);
183 ti = proto_tree_add_item(tree, proto_vpp_opaque2, tvb, offset, -1, ENC_NA);
184 opaque2_tree = proto_item_add_subtree(ti, ett_vpp_opaque2);
186 opaque2_string_length = tvb_strsize (tvb, offset);
187 add_multi_line_string_to_tree (opaque2_tree, tvb, 0, opaque2_string_length,
188 hf_vpp_buffer_opaque2);
190 return tvb_captured_length(tvb);
195 dissect_vpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
198 proto_tree *vpp_tree;
199 tvbuff_t *metadata_tvb, *opaque_tvb, *opaque2_tvb, *eth_tvb, *trace_tvb;
201 guint8 major_version, minor_version, string_count, protocol_hint;
204 guint8 maybe_protocol_id;
205 dissector_handle_t use_this_dissector;
207 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP");
208 col_clear(pinfo->cinfo, COL_INFO);
210 ti = proto_tree_add_item(tree, proto_vpp, tvb, offset, -1, ENC_NA);
211 vpp_tree = proto_item_add_subtree(ti, ett_vpp);
213 major_version = tvb_get_guint8 (tvb, offset);
216 minor_version = tvb_get_guint8 (tvb, offset);
219 if (major_version != 1 || minor_version != 0)
220 ws_debug_printf ("WARNING: version mismatch (%d, %d)",
221 major_version, minor_version);
223 /* Number of counted strings in this trace record */
224 string_count = tvb_get_guint8 (tvb, offset);
228 * Hint: protocol which should be at b->data[b->current_data]
229 * It will be a while before vpp sends useful hints for every
230 * possible node, see heuristic below
232 protocol_hint = tvb_get_guint8 (tvb, offset);
236 proto_tree_add_item(vpp_tree, hf_vpp_buffer_index, tvb,
237 offset, 4, ENC_BIG_ENDIAN);
241 len = tvb_strsize (tvb, offset);
242 name = tvb_get_string_enc (wmem_packet_scope(), tvb, offset, len,
244 proto_tree_add_string (tree, hf_vpp_nodename, tvb, offset, len, name);
248 len = tvb_strsize (tvb, offset);
249 metadata_tvb = tvb_new_subset_remaining (tvb, offset);
250 call_dissector (vpp_metadata_dissector_handle, metadata_tvb, pinfo, tree);
254 len = tvb_strsize (tvb, offset);
255 opaque_tvb = tvb_new_subset_remaining (tvb, offset);
256 call_dissector (vpp_opaque_dissector_handle, opaque_tvb, pinfo, tree);
260 len = tvb_strsize (tvb, offset);
261 opaque2_tvb = tvb_new_subset_remaining (tvb, offset);
262 call_dissector (vpp_opaque2_dissector_handle, opaque2_tvb, pinfo, tree);
265 /* Trace, if present */
266 if (string_count > 4)
268 len = tvb_strsize (tvb, offset);
269 trace_tvb = tvb_new_subset_remaining (tvb, offset);
270 call_dissector (vpp_trace_dissector_handle, trace_tvb, pinfo, tree);
274 eth_tvb = tvb_new_subset_remaining (tvb, offset);
277 * Delegate the rest of the packet dissection to the per-node
278 * next dissector in the foreach_node_to_dissector_pair list
280 * Failing that, pretend its an ethernet packet
282 if (protocol_hint >= array_length(next_dissectors)) {
283 ws_debug_printf ("protocol_hint %d out of range (max %d)",
285 (int) array_length(next_dissectors));
288 /* See setup for hint == 0 below */
289 use_this_dissector = next_dissectors [protocol_hint];
290 if (protocol_hint == 0) {
291 maybe_protocol_id = tvb_get_guint8 (tvb, offset);
293 switch (maybe_protocol_id) {
295 use_this_dissector = next_dissectors[VLIB_NODE_PROTO_HINT_IP4];
298 use_this_dissector = next_dissectors[VLIB_NODE_PROTO_HINT_IP6];
304 call_dissector (use_this_dissector, eth_tvb, pinfo, tree);
305 return tvb_captured_length(tvb);
309 proto_register_vpp(void)
311 static hf_register_info vpp_hf[] = {
312 { &hf_vpp_buffer_index,
313 { "BufferIndex", "vpp.BufferIndex", FT_UINT32, BASE_HEX, NULL, 0x0,
317 { "NodeName", "vpp.NodeName", FT_STRINGZ, BASE_NONE, NULL, 0x0,
322 static hf_register_info metadata_hf[] = {
324 { "Metadata", "vpp.metadata",
325 FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
329 static hf_register_info opaque_hf[] = {
330 { &hf_vpp_buffer_opaque,
331 { "Opaque", "vpp.opaque",
332 FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
336 static hf_register_info opaque2_hf[] = {
337 { &hf_vpp_buffer_opaque2,
338 { "Opaque2", "vpp.opaque2",
339 FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
343 static hf_register_info trace_hf[] = {
344 { &hf_vpp_buffer_trace,
345 { "Trace", "vpp.trace", FT_STRINGZ, BASE_NONE, NULL, 0x0,
350 static gint *vpp_ett[] = {
353 static gint *ett_metadata[] = {
356 static gint *ett_opaque[] = {
359 static gint *ett_opaque2[] = {
362 static gint *ett_trace[] = {
366 proto_vpp = proto_register_protocol("VPP Dispatch Trace", "VPP", "vpp");
367 proto_register_field_array(proto_vpp, vpp_hf, array_length(vpp_hf));
368 proto_register_subtree_array (vpp_ett, array_length(vpp_ett));
369 register_dissector("vpp", dissect_vpp, proto_vpp);
371 proto_vpp_metadata = proto_register_protocol("VPP Buffer Metadata",
374 proto_register_field_array(proto_vpp_metadata, metadata_hf,
375 array_length(metadata_hf));
376 proto_register_subtree_array (ett_metadata, array_length(ett_metadata));
377 register_dissector("vppMetadata", dissect_vpp_metadata, proto_vpp_metadata);
379 proto_vpp_opaque = proto_register_protocol("VPP Buffer Opaque", "VPP-Opaque",
381 proto_register_field_array(proto_vpp_opaque, opaque_hf,
382 array_length(opaque_hf));
383 proto_register_subtree_array (ett_opaque, array_length(ett_opaque));
384 register_dissector("vppOpaque", dissect_vpp_opaque, proto_vpp_opaque);
386 proto_vpp_opaque2 = proto_register_protocol("VPP Buffer Opaque2", "VPP-Opaque2",
388 proto_register_field_array(proto_vpp_opaque2, opaque2_hf,
389 array_length(opaque2_hf));
390 proto_register_subtree_array (ett_opaque2, array_length(ett_opaque2));
391 register_dissector("vppOpaque2", dissect_vpp_opaque2, proto_vpp_opaque2);
394 proto_vpp_trace = proto_register_protocol("VPP Buffer Trace", "VPP-Trace",
396 proto_register_field_array(proto_vpp_trace, trace_hf,
397 array_length(trace_hf));
398 proto_register_subtree_array (ett_trace, array_length(ett_trace));
399 register_dissector("vppTrace", dissect_vpp_trace, proto_vpp_trace);
401 #define _(idx,dname) next_dissectors[idx] = find_dissector (#dname);
402 foreach_next_dissector;
405 /* if all else fails, dissect data as if ethernet MAC */
406 next_dissectors[VLIB_NODE_PROTO_HINT_NONE] =
407 next_dissectors [VLIB_NODE_PROTO_HINT_ETHERNET];
411 proto_reg_handoff_vpp(void)
413 vpp_dissector_handle = find_dissector("vpp");
414 vpp_metadata_dissector_handle = find_dissector("vppMetadata");
415 vpp_opaque_dissector_handle = find_dissector("vppOpaque");
416 vpp_opaque2_dissector_handle = find_dissector("vppOpaque2");
417 vpp_trace_dissector_handle = find_dissector("vppTrace");
418 dissector_add_uint("wtap_encap", WTAP_ENCAP_USER13, vpp_dissector_handle);
422 * Editor modelines - http://www.wireshark.org/tools/modelines.html
427 * indent-tabs-mode: nil
430 * vi: set shiftwidth=4 tabstop=8 expandtab:
431 * :indentSize=4:tabSize=8:noTabs=true: