blob: 5094f5d0066759249830d97d84d117190e31aaf5 [file] [log] [blame]
Dave Barach1dda3862018-11-20 20:15:37 -05001/* packet-vpp.c
2 *
3 * Routines for the disassembly of fd.io vpp project
4 * dispatch captures
5 *
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:
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
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.
18 *
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.
21 */
22
23#include "config.h"
24
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>
31#include <stdio.h>
32#include <wsutil/ws_printf.h>
33
34void proto_register_vpp(void);
35void proto_reg_handoff_vpp(void);
36
37static int proto_vpp = -1;
Dave Barach7fff3d22018-11-27 16:52:59 -050038static int proto_vpp_metadata = -1;
Dave Barach1dda3862018-11-20 20:15:37 -050039static int proto_vpp_opaque = -1;
Dave Barach7fff3d22018-11-27 16:52:59 -050040static int proto_vpp_opaque2 = -1;
Dave Barach1dda3862018-11-20 20:15:37 -050041static int proto_vpp_trace = -1;
42static int hf_vpp_nodename = -1;
Dave Barach7fff3d22018-11-27 16:52:59 -050043static int hf_vpp_metadata = -1;
Dave Barach1dda3862018-11-20 20:15:37 -050044static int hf_vpp_buffer_index = -1;
Dave Barach7fff3d22018-11-27 16:52:59 -050045static int hf_vpp_buffer_opaque = -1;
46static int hf_vpp_buffer_opaque2 = -1;
Dave Barach1dda3862018-11-20 20:15:37 -050047static int hf_vpp_buffer_trace = -1;
48
49static gint ett_vpp = -1;
50static gint ett_vpp_opaque = -1;
Dave Barach7fff3d22018-11-27 16:52:59 -050051static gint ett_vpp_opaque2 = -1;
52static gint ett_vpp_metadata = -1;
Dave Barach1dda3862018-11-20 20:15:37 -050053static gint ett_vpp_trace = -1;
54
55static dissector_handle_t vpp_dissector_handle;
56static dissector_handle_t vpp_opaque_dissector_handle;
Dave Barach7fff3d22018-11-27 16:52:59 -050057static dissector_handle_t vpp_opaque2_dissector_handle;
58static dissector_handle_t vpp_metadata_dissector_handle;
Dave Barach1dda3862018-11-20 20:15:37 -050059static dissector_handle_t vpp_trace_dissector_handle;
60
Dave Barach7fff3d22018-11-27 16:52:59 -050061typedef enum
62 {
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;
Dave Barach1dda3862018-11-20 20:15:37 -050071
Dave Barach7fff3d22018-11-27 16:52:59 -050072static dissector_handle_t next_dissectors[VLIB_NODE_N_PROTO_HINTS];
73
74/* List of next dissectors hints that we know about */
Dave Barachc2b4dc52018-11-24 18:29:26 -050075#define foreach_next_dissector \
Dave Barach7fff3d22018-11-27 16:52:59 -050076_(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)
Dave Barach1dda3862018-11-20 20:15:37 -050081
82static void
83add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, gint start,
84 gint len, int hf)
85{
86 gint next;
87 int line_len;
88 int data_len;
89
90 while (len > 0) {
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));
95 start += data_len;
96 len -= data_len;
97 }
98}
99
100static int
Dave Barach7fff3d22018-11-27 16:52:59 -0500101dissect_vpp_metadata (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
102 void* data _U_)
103{
104 int offset = 0;
105 proto_item *ti;
106 proto_tree *metadata_tree;
107 gint metadata_string_length;
108
109 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Metadata");
110 col_clear(pinfo->cinfo, COL_INFO);
111
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);
114
115 /* How long is the metadata string? */
116 metadata_string_length = tvb_strsize (tvb, offset);
117
118 add_multi_line_string_to_tree (metadata_tree, tvb, 0,
119 metadata_string_length,
120 hf_vpp_metadata);
121 return tvb_captured_length(tvb);
122}
123
124static int
Dave Barach1dda3862018-11-20 20:15:37 -0500125dissect_vpp_trace (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
126 void* data _U_)
127{
128 int offset = 0;
129 proto_item *ti;
130 proto_tree *trace_tree;
131 gint trace_string_length;
132
133 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Trace");
134 col_clear(pinfo->cinfo, COL_INFO);
135
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);
138
139 /* How long is the trace string? */
Dave Barach7fff3d22018-11-27 16:52:59 -0500140 trace_string_length = tvb_strsize (tvb, offset);
Dave Barach1dda3862018-11-20 20:15:37 -0500141
142 add_multi_line_string_to_tree (trace_tree, tvb, 0,
143 trace_string_length,
144 hf_vpp_buffer_trace);
145 return tvb_captured_length(tvb);
146}
147
Dave Barach1dda3862018-11-20 20:15:37 -0500148
149static int
150dissect_vpp_opaque (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
151 void* data _U_)
152{
153 int offset = 0;
154 proto_item *ti;
155 proto_tree *opaque_tree;
Dave Barach7fff3d22018-11-27 16:52:59 -0500156 gint opaque_string_length;
Dave Barach1dda3862018-11-20 20:15:37 -0500157
158 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Opaque");
159 col_clear(pinfo->cinfo, COL_INFO);
160
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);
163
Dave Barach7fff3d22018-11-27 16:52:59 -0500164 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);
Dave Barach1dda3862018-11-20 20:15:37 -0500167
Dave Barach7fff3d22018-11-27 16:52:59 -0500168 return tvb_captured_length(tvb);
169}
Dave Barach1dda3862018-11-20 20:15:37 -0500170
Dave Barach7fff3d22018-11-27 16:52:59 -0500171static int
172dissect_vpp_opaque2 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
173 void* data _U_)
174{
175 int offset = 0;
176 proto_item *ti;
177 proto_tree *opaque2_tree;
178 gint opaque2_string_length;
Dave Barach1dda3862018-11-20 20:15:37 -0500179
Dave Barach7fff3d22018-11-27 16:52:59 -0500180 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Opaque2");
181 col_clear(pinfo->cinfo, COL_INFO);
Dave Barach1dda3862018-11-20 20:15:37 -0500182
Dave Barach7fff3d22018-11-27 16:52:59 -0500183 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);
Dave Barach1dda3862018-11-20 20:15:37 -0500185
Dave Barach7fff3d22018-11-27 16:52:59 -0500186 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);
Dave Barach1dda3862018-11-20 20:15:37 -0500189
190 return tvb_captured_length(tvb);
191}
192
193
194static int
195dissect_vpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
196{
197 proto_item *ti;
198 proto_tree *vpp_tree;
Dave Barach7fff3d22018-11-27 16:52:59 -0500199 tvbuff_t *metadata_tvb, *opaque_tvb, *opaque2_tvb, *eth_tvb, *trace_tvb;
Dave Barach1dda3862018-11-20 20:15:37 -0500200 int offset = 0;
Dave Barach7fff3d22018-11-27 16:52:59 -0500201 guint8 major_version, minor_version, string_count, protocol_hint;
Dave Barach1dda3862018-11-20 20:15:37 -0500202 guint8 *name;
Dave Barach7fff3d22018-11-27 16:52:59 -0500203 guint len;
204 guint8 maybe_protocol_id;
205 dissector_handle_t use_this_dissector;
Dave Barach1dda3862018-11-20 20:15:37 -0500206
207 col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP");
208 col_clear(pinfo->cinfo, COL_INFO);
209
210 ti = proto_tree_add_item(tree, proto_vpp, tvb, offset, -1, ENC_NA);
211 vpp_tree = proto_item_add_subtree(ti, ett_vpp);
212
213 major_version = tvb_get_guint8 (tvb, offset);
214 offset++;
215
216 minor_version = tvb_get_guint8 (tvb, offset);
217 offset++;
218
219 if (major_version != 1 || minor_version != 0)
220 ws_debug_printf ("WARNING: version mismatch (%d, %d)",
221 major_version, minor_version);
222
Dave Barach7fff3d22018-11-27 16:52:59 -0500223 /* Number of counted strings in this trace record */
224 string_count = tvb_get_guint8 (tvb, offset);
Dave Barach1dda3862018-11-20 20:15:37 -0500225 offset++;
226
Dave Barach7fff3d22018-11-27 16:52:59 -0500227 /*
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
231 */
232 protocol_hint = tvb_get_guint8 (tvb, offset);
Dave Barach1dda3862018-11-20 20:15:37 -0500233 offset++;
234
Dave Barach7fff3d22018-11-27 16:52:59 -0500235 /* Buffer Index */
Dave Barach1dda3862018-11-20 20:15:37 -0500236 proto_tree_add_item(vpp_tree, hf_vpp_buffer_index, tvb,
Dave Barach7fff3d22018-11-27 16:52:59 -0500237 offset, 4, ENC_BIG_ENDIAN);
Dave Barach1dda3862018-11-20 20:15:37 -0500238 offset += 4;
239
Dave Barach7fff3d22018-11-27 16:52:59 -0500240 /* Nodename */
241 len = tvb_strsize (tvb, offset);
242 name = tvb_get_string_enc (wmem_packet_scope(), tvb, offset, len,
243 ENC_ASCII);
244 proto_tree_add_string (tree, hf_vpp_nodename, tvb, offset, len, name);
245 offset += len;
Dave Barach1dda3862018-11-20 20:15:37 -0500246
Dave Barach7fff3d22018-11-27 16:52:59 -0500247 /* Metadata */
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);
251 offset += len;
Dave Barach1dda3862018-11-20 20:15:37 -0500252
Dave Barach7fff3d22018-11-27 16:52:59 -0500253 /* Opaque */
254 len = tvb_strsize (tvb, offset);
Dave Barach1dda3862018-11-20 20:15:37 -0500255 opaque_tvb = tvb_new_subset_remaining (tvb, offset);
256 call_dissector (vpp_opaque_dissector_handle, opaque_tvb, pinfo, tree);
Dave Barach7fff3d22018-11-27 16:52:59 -0500257 offset += len;
Dave Barach1dda3862018-11-20 20:15:37 -0500258
Dave Barach7fff3d22018-11-27 16:52:59 -0500259 /* Opaque2 */
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);
263 offset += len;
Dave Barach1dda3862018-11-20 20:15:37 -0500264
Dave Barach7fff3d22018-11-27 16:52:59 -0500265 /* Trace, if present */
266 if (string_count > 4)
267 {
268 len = tvb_strsize (tvb, offset);
Dave Barach1dda3862018-11-20 20:15:37 -0500269 trace_tvb = tvb_new_subset_remaining (tvb, offset);
Dave Barach1dda3862018-11-20 20:15:37 -0500270 call_dissector (vpp_trace_dissector_handle, trace_tvb, pinfo, tree);
Dave Barach7fff3d22018-11-27 16:52:59 -0500271 offset += len;
Dave Barach1dda3862018-11-20 20:15:37 -0500272 }
273
274 eth_tvb = tvb_new_subset_remaining (tvb, offset);
275
Dave Barachc2b4dc52018-11-24 18:29:26 -0500276 /*
277 * Delegate the rest of the packet dissection to the per-node
278 * next dissector in the foreach_node_to_dissector_pair list
279 *
280 * Failing that, pretend its an ethernet packet
281 */
Dave Barach7fff3d22018-11-27 16:52:59 -0500282 if (protocol_hint >= array_length(next_dissectors)) {
283 ws_debug_printf ("protocol_hint %d out of range (max %d)",
284 (int) protocol_hint,
285 (int) array_length(next_dissectors));
286 protocol_hint = 0;
287 }
288 /* See setup for hint == 0 below */
289 use_this_dissector = next_dissectors [protocol_hint];
290 if (protocol_hint == 0) {
Dave Barachf970d2f2018-11-26 18:34:33 -0500291 maybe_protocol_id = tvb_get_guint8 (tvb, offset);
Dave Barach7fff3d22018-11-27 16:52:59 -0500292
Dave Barachf970d2f2018-11-26 18:34:33 -0500293 switch (maybe_protocol_id) {
294 case 0x45:
Dave Barach7fff3d22018-11-27 16:52:59 -0500295 use_this_dissector = next_dissectors[VLIB_NODE_PROTO_HINT_IP4];
Dave Barachf970d2f2018-11-26 18:34:33 -0500296 break;
297 case 0x60:
Dave Barach7fff3d22018-11-27 16:52:59 -0500298 use_this_dissector = next_dissectors[VLIB_NODE_PROTO_HINT_IP6];
Dave Barachf970d2f2018-11-26 18:34:33 -0500299 break;
300 default:
301 break;
302 }
Dave Barachf970d2f2018-11-26 18:34:33 -0500303 }
Dave Barach7fff3d22018-11-27 16:52:59 -0500304 call_dissector (use_this_dissector, eth_tvb, pinfo, tree);
Dave Barach1dda3862018-11-20 20:15:37 -0500305 return tvb_captured_length(tvb);
306}
307
308void
309proto_register_vpp(void)
310{
Dave Barach7fff3d22018-11-27 16:52:59 -0500311 static hf_register_info vpp_hf[] = {
Dave Barach1dda3862018-11-20 20:15:37 -0500312 { &hf_vpp_buffer_index,
Dave Barach7fff3d22018-11-27 16:52:59 -0500313 { "BufferIndex", "vpp.BufferIndex", FT_UINT32, BASE_HEX, NULL, 0x0,
Dave Barach1dda3862018-11-20 20:15:37 -0500314 NULL, HFILL },
315 },
316 { &hf_vpp_nodename,
Dave Barach7fff3d22018-11-27 16:52:59 -0500317 { "NodeName", "vpp.NodeName", FT_STRINGZ, BASE_NONE, NULL, 0x0,
Dave Barach1dda3862018-11-20 20:15:37 -0500318 NULL, HFILL },
319 },
320 };
321
Dave Barach7fff3d22018-11-27 16:52:59 -0500322 static hf_register_info metadata_hf[] = {
323 { &hf_vpp_metadata,
324 { "Metadata", "vpp.metadata",
325 FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
Dave Barach1dda3862018-11-20 20:15:37 -0500326 },
Dave Barach7fff3d22018-11-27 16:52:59 -0500327 };
328
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 },
333 },
334 };
335
336 static hf_register_info opaque2_hf[] = {
337 { &hf_vpp_buffer_opaque2,
338 { "Opaque2", "vpp.opaque2",
Dave Barach1dda3862018-11-20 20:15:37 -0500339 FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
340 },
341 };
342
343 static hf_register_info trace_hf[] = {
344 { &hf_vpp_buffer_trace,
Dave Barach7fff3d22018-11-27 16:52:59 -0500345 { "Trace", "vpp.trace", FT_STRINGZ, BASE_NONE, NULL, 0x0,
Dave Barach1dda3862018-11-20 20:15:37 -0500346 NULL, HFILL },
347 },
348 };
349
Dave Barach7fff3d22018-11-27 16:52:59 -0500350 static gint *vpp_ett[] = {
Dave Barach1dda3862018-11-20 20:15:37 -0500351 &ett_vpp,
352 };
Dave Barach7fff3d22018-11-27 16:52:59 -0500353 static gint *ett_metadata[] = {
354 &ett_vpp_metadata,
355 };
Dave Barach1dda3862018-11-20 20:15:37 -0500356 static gint *ett_opaque[] = {
357 &ett_vpp_opaque,
358 };
Dave Barach7fff3d22018-11-27 16:52:59 -0500359 static gint *ett_opaque2[] = {
360 &ett_vpp_opaque2,
361 };
Dave Barach1dda3862018-11-20 20:15:37 -0500362 static gint *ett_trace[] = {
363 &ett_vpp_trace,
364 };
365
Dave Barach7fff3d22018-11-27 16:52:59 -0500366 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));
Dave Barach1dda3862018-11-20 20:15:37 -0500369 register_dissector("vpp", dissect_vpp, proto_vpp);
370
Dave Barach7fff3d22018-11-27 16:52:59 -0500371 proto_vpp_metadata = proto_register_protocol("VPP Buffer Metadata",
372 "VPP-Metadata",
373 "vpp-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);
378
Dave Barach1dda3862018-11-20 20:15:37 -0500379 proto_vpp_opaque = proto_register_protocol("VPP Buffer Opaque", "VPP-Opaque",
380 "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);
385
Dave Barach7fff3d22018-11-27 16:52:59 -0500386 proto_vpp_opaque2 = proto_register_protocol("VPP Buffer Opaque2", "VPP-Opaque2",
387 "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);
392
393
Dave Barach1dda3862018-11-20 20:15:37 -0500394 proto_vpp_trace = proto_register_protocol("VPP Buffer Trace", "VPP-Trace",
395 "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);
400
Dave Barach7fff3d22018-11-27 16:52:59 -0500401#define _(idx,dname) next_dissectors[idx] = find_dissector (#dname);
402 foreach_next_dissector;
Dave Barach1dda3862018-11-20 20:15:37 -0500403#undef _
Dave Barach7fff3d22018-11-27 16:52:59 -0500404
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];
Dave Barach1dda3862018-11-20 20:15:37 -0500408}
409
410void
411proto_reg_handoff_vpp(void)
412{
413 vpp_dissector_handle = find_dissector("vpp");
Dave Barach7fff3d22018-11-27 16:52:59 -0500414 vpp_metadata_dissector_handle = find_dissector("vppMetadata");
Dave Barach1dda3862018-11-20 20:15:37 -0500415 vpp_opaque_dissector_handle = find_dissector("vppOpaque");
Dave Barach7fff3d22018-11-27 16:52:59 -0500416 vpp_opaque2_dissector_handle = find_dissector("vppOpaque2");
Dave Barach1dda3862018-11-20 20:15:37 -0500417 vpp_trace_dissector_handle = find_dissector("vppTrace");
418 dissector_add_uint("wtap_encap", WTAP_ENCAP_USER13, vpp_dissector_handle);
419}
420
421/*
422 * Editor modelines - http://www.wireshark.org/tools/modelines.html
423 *
424 * Local variables:
425 * c-basic-offset: 4
426 * tab-width: 8
427 * indent-tabs-mode: nil
428 * End:
429 *
430 * vi: set shiftwidth=4 tabstop=8 expandtab:
431 * :indentSize=4:tabSize=8:noTabs=true:
432 */