Coverage Report

Created: 2026-09-28 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-vpp.c
Line
Count
Source
1
/* packet-vpp.c
2
 *
3
 * Routines for the disassembly of fd.io vpp project
4
 * dispatch captures
5
 *
6
 * Copyright 2019, Dave Barach <wireshark@barachs.net>
7
 *
8
 * Wireshark - Network traffic analyzer
9
 * By Gerald Combs <gerald@wireshark.org>
10
 * Copyright 1998 Gerald Combs
11
 *
12
 * SPDX-License-Identifier: GPL-2.0-or-later
13
 */
14
15
#include "config.h"
16
17
#include <epan/packet.h>
18
#include <epan/expert.h>
19
#include <epan/to_str.h>
20
#include <epan/etypes.h>
21
#include <wiretap/wtap.h>
22
#include "packet-osi.h"
23
24
void proto_register_vpp(void);
25
void proto_reg_handoff_vpp(void);
26
27
static int proto_vpp;
28
static int proto_vpp_metadata;
29
static int proto_vpp_opaque;
30
static int proto_vpp_opaque2;
31
static int proto_vpp_trace;
32
static int hf_vpp_nodename;
33
static int hf_vpp_metadata;
34
static int hf_vpp_buffer_index;
35
static int hf_vpp_buffer_opaque;
36
static int hf_vpp_buffer_opaque2;
37
static int hf_vpp_buffer_trace;
38
static int hf_vpp_major_version;
39
static int hf_vpp_minor_version;
40
static int hf_vpp_protocol_hint;
41
42
static expert_module_t* expert_vpp;
43
44
static expert_field ei_vpp_major_version_error;
45
static expert_field ei_vpp_minor_version_error;
46
static expert_field ei_vpp_protocol_hint_error;
47
48
static int ett_vpp;
49
static int ett_vpp_opaque;
50
static int ett_vpp_opaque2;
51
static int ett_vpp_metadata;
52
static int ett_vpp_trace;
53
54
static dissector_handle_t vpp_dissector_handle;
55
static dissector_handle_t vpp_opaque_dissector_handle;
56
static dissector_handle_t vpp_opaque2_dissector_handle;
57
static dissector_handle_t vpp_metadata_dissector_handle;
58
static dissector_handle_t vpp_trace_dissector_handle;
59
60
0
#define VPP_MAJOR_VERSION       1
61
0
#define VPP_MINOR_VERSION       0
62
0
#define IP4_TYPICAL_VERSION_LENGTH      0x45
63
0
#define IP6_TYPICAL_VERSION_AND_TRAFFIC_CLASS   0x60
64
65
typedef enum
66
  {
67
    VLIB_NODE_PROTO_HINT_NONE = 0,
68
    VLIB_NODE_PROTO_HINT_ETHERNET,
69
    VLIB_NODE_PROTO_HINT_IP4,
70
    VLIB_NODE_PROTO_HINT_IP6,
71
    VLIB_NODE_PROTO_HINT_TCP,
72
    VLIB_NODE_PROTO_HINT_UDP,
73
    VLIB_NODE_N_PROTO_HINTS,
74
  } vlib_node_proto_hint_t;
75
76
static dissector_handle_t next_dissectors[VLIB_NODE_N_PROTO_HINTS];
77
78
/* List of next dissectors hints that we know about */
79
16
#define foreach_next_dissector                          \
80
16
_(VLIB_NODE_PROTO_HINT_ETHERNET, eth_withoutfcs)        \
81
16
_(VLIB_NODE_PROTO_HINT_IP4, ip)                         \
82
16
_(VLIB_NODE_PROTO_HINT_IP6, ipv6)                       \
83
16
_(VLIB_NODE_PROTO_HINT_TCP, tcp)                        \
84
16
_(VLIB_NODE_PROTO_HINT_UDP, udp)
85
86
static void
87
add_multi_line_string_to_tree(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo,
88
                              int start,
89
                              int len, int hf)
90
0
{
91
0
    unsigned next, line_len, data_len;
92
93
0
    while(len > 0) {
94
0
        tvb_find_line_end_length(tvb, start, len, &line_len, &next);
95
0
        data_len = next - start;
96
0
        proto_tree_add_string(tree, hf, tvb, start, data_len,
97
0
                              tvb_format_stringzpad(pinfo->pool, tvb, start, line_len));
98
0
        start += data_len;
99
0
        len -= data_len;
100
0
    }
101
0
}
102
103
static int
104
dissect_vpp_metadata(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
105
                     void* data _U_)
106
0
{
107
0
    unsigned offset = 0;
108
0
    proto_item *ti;
109
0
    proto_tree *metadata_tree;
110
0
    int metadata_string_length;
111
112
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Metadata");
113
0
    col_clear(pinfo->cinfo, COL_INFO);
114
115
0
    ti = proto_tree_add_item(tree, proto_vpp_metadata, tvb, offset, -1, ENC_NA);
116
0
    metadata_tree = proto_item_add_subtree(ti, ett_vpp_metadata);
117
118
    /* How long is the metadata string? */
119
0
    metadata_string_length = tvb_strsize(tvb, offset);
120
121
0
    add_multi_line_string_to_tree(metadata_tree, tvb, pinfo, 0,
122
0
                                  metadata_string_length,
123
0
                                  hf_vpp_metadata);
124
0
    return tvb_captured_length(tvb);
125
0
}
126
127
static int
128
dissect_vpp_trace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
129
                  void* data _U_)
130
0
{
131
0
    unsigned offset = 0;
132
0
    proto_item *ti;
133
0
    proto_tree *trace_tree;
134
0
    int trace_string_length;
135
136
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Trace");
137
0
    col_clear(pinfo->cinfo, COL_INFO);
138
139
0
    ti = proto_tree_add_item(tree, proto_vpp_trace, tvb, offset, -1, ENC_NA);
140
0
    trace_tree = proto_item_add_subtree(ti, ett_vpp_trace);
141
142
    /* How long is the trace string? */
143
0
    trace_string_length = tvb_strsize(tvb, offset);
144
145
0
    add_multi_line_string_to_tree(trace_tree, tvb, pinfo, 0,
146
0
                                  trace_string_length,
147
0
                                  hf_vpp_buffer_trace);
148
0
    return tvb_captured_length(tvb);
149
0
}
150
151
152
static int
153
dissect_vpp_opaque(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
154
                   void* data _U_)
155
0
{
156
0
    unsigned offset = 0;
157
0
    proto_item *ti;
158
0
    proto_tree *opaque_tree;
159
0
    int opaque_string_length;
160
161
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Opaque");
162
0
    col_clear(pinfo->cinfo, COL_INFO);
163
164
0
    ti = proto_tree_add_item(tree, proto_vpp_opaque, tvb, offset, -1, ENC_NA);
165
0
    opaque_tree = proto_item_add_subtree(ti, ett_vpp_opaque);
166
167
0
    opaque_string_length = tvb_strsize(tvb, offset);
168
0
    add_multi_line_string_to_tree(opaque_tree, tvb, pinfo, 0, opaque_string_length,
169
0
                                  hf_vpp_buffer_opaque);
170
171
0
    return tvb_captured_length(tvb);
172
0
}
173
174
static int
175
dissect_vpp_opaque2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
176
                    void* data _U_)
177
0
{
178
0
    unsigned offset = 0;
179
0
    proto_item *ti;
180
0
    proto_tree *opaque2_tree;
181
0
    int opaque2_string_length;
182
183
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP-Opaque2");
184
0
    col_clear(pinfo->cinfo, COL_INFO);
185
186
0
    ti = proto_tree_add_item(tree, proto_vpp_opaque2, tvb, offset, -1, ENC_NA);
187
0
    opaque2_tree = proto_item_add_subtree(ti, ett_vpp_opaque2);
188
189
0
    opaque2_string_length = tvb_strsize(tvb, offset);
190
0
    add_multi_line_string_to_tree(opaque2_tree, tvb, pinfo, 0, opaque2_string_length,
191
0
                                  hf_vpp_buffer_opaque2);
192
193
0
    return tvb_captured_length(tvb);
194
0
}
195
196
197
static int
198
dissect_vpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
199
0
{
200
0
    proto_item *ti;
201
0
    proto_tree *vpp_tree;
202
0
    tvbuff_t *metadata_tvb, *opaque_tvb, *opaque2_tvb, *eth_tvb, *trace_tvb;
203
0
    unsigned offset = 0;
204
0
    uint8_t major_version, minor_version, string_count, protocol_hint;
205
0
    char *name;
206
0
    unsigned len;
207
0
    uint8_t maybe_protocol_id;
208
0
    dissector_handle_t use_this_dissector;
209
210
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "VPP");
211
0
    col_clear(pinfo->cinfo, COL_INFO);
212
213
0
    ti = proto_tree_add_item(tree, proto_vpp, tvb, offset, -1, ENC_NA);
214
0
    vpp_tree = proto_item_add_subtree(ti, ett_vpp);
215
216
0
    major_version = tvb_get_uint8(tvb, offset);
217
    /* If the major version doesn't match, quit on the spot */
218
0
    if(major_version != VPP_MAJOR_VERSION) {
219
0
        proto_item *major_version_item;
220
0
        major_version_item =
221
0
            proto_tree_add_item(tree, hf_vpp_major_version,
222
0
                                tvb, offset, 1, ENC_NA);
223
0
        expert_add_info_format(pinfo, major_version_item,
224
0
                               &ei_vpp_major_version_error,
225
0
                               "Major Version Mismatch read %d not %d",
226
0
                               (int)major_version, VPP_MAJOR_VERSION);
227
0
        return tvb_captured_length(tvb);
228
0
    }
229
0
    offset++;
230
231
0
    minor_version = tvb_get_uint8(tvb, offset);
232
    /* If the minor version doesn't match, make a note and try to continue */
233
0
    if(minor_version != VPP_MINOR_VERSION) {
234
0
        proto_item *minor_version_item;
235
0
        minor_version_item =
236
0
            proto_tree_add_item(tree, hf_vpp_minor_version,
237
0
                                tvb, offset, 1, ENC_NA);
238
0
        expert_add_info_format(pinfo, minor_version_item,
239
0
                               &ei_vpp_minor_version_error,
240
0
                               "Minor Version Mismatch read %d not %d",
241
0
                               (int)minor_version, VPP_MINOR_VERSION);
242
0
    }
243
0
    offset++;
244
245
    /* Number of counted strings in this trace record */
246
0
    string_count = tvb_get_uint8(tvb, offset);
247
0
    offset++;
248
249
    /*
250
     * Hint: protocol which should be at b->data[b->current_data]
251
     * It will be a while before vpp sends useful hints for every
252
     * possible node, see heuristic below.
253
     */
254
0
    protocol_hint = tvb_get_uint8(tvb, offset);
255
256
0
    if(protocol_hint >= array_length(next_dissectors)) {
257
0
        proto_item *protocol_hint_item;
258
0
        protocol_hint_item =
259
0
            proto_tree_add_item(tree, hf_vpp_protocol_hint,
260
0
                                tvb, offset, 1, ENC_NA);
261
0
        expert_add_info_format(pinfo, protocol_hint_item,
262
0
                               &ei_vpp_protocol_hint_error,
263
0
                               "Protocol hint %d out of range, max %d",
264
0
                               (int)protocol_hint,
265
0
                               (int)array_length(next_dissectors));
266
0
        protocol_hint = 0;
267
0
    }
268
269
0
    offset++;
270
271
    /* Buffer Index */
272
0
    proto_tree_add_item(vpp_tree, hf_vpp_buffer_index, tvb,
273
0
                        offset, 4, ENC_BIG_ENDIAN);
274
0
    offset += 4;
275
276
    /* Nodename */
277
0
    len = tvb_strsize(tvb, offset);
278
0
    name = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, len,
279
0
                              ENC_ASCII);
280
0
    proto_tree_add_string(tree, hf_vpp_nodename, tvb, offset, len, name);
281
0
    offset += len;
282
283
    /* Metadata */
284
0
    len = tvb_strsize(tvb, offset);
285
0
    metadata_tvb = tvb_new_subset_remaining(tvb, offset);
286
0
    call_dissector(vpp_metadata_dissector_handle, metadata_tvb, pinfo, tree);
287
0
    offset += len;
288
289
    /* Opaque */
290
0
    len = tvb_strsize(tvb, offset);
291
0
    opaque_tvb = tvb_new_subset_remaining(tvb, offset);
292
0
    call_dissector(vpp_opaque_dissector_handle, opaque_tvb, pinfo, tree);
293
0
    offset += len;
294
295
    /* Opaque2 */
296
0
    len = tvb_strsize(tvb, offset);
297
0
    opaque2_tvb = tvb_new_subset_remaining(tvb, offset);
298
0
    call_dissector(vpp_opaque2_dissector_handle, opaque2_tvb, pinfo, tree);
299
0
    offset += len;
300
301
    /* Trace, if present */
302
0
    if(string_count > 4) {
303
0
        len = tvb_strsize(tvb, offset);
304
0
        trace_tvb = tvb_new_subset_remaining(tvb, offset);
305
0
        call_dissector(vpp_trace_dissector_handle, trace_tvb, pinfo, tree);
306
0
        offset += len;
307
0
    }
308
309
0
    eth_tvb = tvb_new_subset_remaining(tvb, offset);
310
311
    /*
312
     * Delegate the rest of the packet dissection to the per-node
313
     * next dissector in the foreach_node_to_dissector_pair list
314
     *
315
     * Failing that, pretend its an ethernet packet
316
     */
317
    /* See setup for hint == 0 below */
318
0
    use_this_dissector = next_dissectors [protocol_hint];
319
0
    if(protocol_hint == 0) {
320
0
        maybe_protocol_id = tvb_get_uint8(tvb, offset);
321
322
0
        switch(maybe_protocol_id) {
323
0
        case IP4_TYPICAL_VERSION_LENGTH:
324
0
            use_this_dissector = next_dissectors[VLIB_NODE_PROTO_HINT_IP4];
325
0
            break;
326
0
        case IP6_TYPICAL_VERSION_AND_TRAFFIC_CLASS:
327
0
            use_this_dissector = next_dissectors[VLIB_NODE_PROTO_HINT_IP6];
328
0
            break;
329
0
        default:
330
0
            break;
331
0
        }
332
0
    }
333
0
    call_dissector(use_this_dissector, eth_tvb, pinfo, tree);
334
0
    return tvb_captured_length(tvb);
335
0
}
336
337
void
338
proto_register_vpp(void)
339
16
{
340
16
    static hf_register_info vpp_hf[] = {
341
16
        { &hf_vpp_buffer_index,
342
16
          { "BufferIndex", "vpp.BufferIndex",  FT_UINT32, BASE_HEX, NULL, 0x0,
343
16
            NULL, HFILL },
344
16
        },
345
16
        { &hf_vpp_nodename,
346
16
          { "NodeName", "vpp.NodeName",  FT_STRINGZ, BASE_NONE, NULL, 0x0,
347
16
            NULL, HFILL },
348
16
        },
349
16
        { &hf_vpp_major_version,
350
16
          { "MajorVersion", "vpp.MajorVersion",  FT_UINT8, BASE_DEC, NULL, 0x0,
351
16
            NULL, HFILL },
352
16
        },
353
16
        { &hf_vpp_minor_version,
354
16
          { "MinorVersion", "vpp.MinorVersion",  FT_UINT8, BASE_DEC, NULL, 0x0,
355
16
            NULL, HFILL },
356
16
        },
357
16
        { &hf_vpp_protocol_hint,
358
16
          { "ProtocolHint", "vpp.ProtocolHint",  FT_UINT8, BASE_DEC, NULL, 0x0,
359
16
            NULL, HFILL },
360
16
        },
361
16
    };
362
363
16
    static ei_register_info vpp_ei[] = {
364
16
        { &ei_vpp_major_version_error,
365
16
          { "vpp.bad_major_version", PI_MALFORMED, PI_ERROR,
366
16
            "Bad Major Version", EXPFILL }},
367
16
        { &ei_vpp_minor_version_error,
368
16
          { "vpp.bad_minor_version", PI_UNDECODED, PI_WARN,
369
16
            "Bad Minor Version", EXPFILL }},
370
16
        { &ei_vpp_protocol_hint_error,
371
16
          { "vpp.bad_protocol_hint", PI_PROTOCOL, PI_WARN,
372
16
            "Bad Protocol Hint", EXPFILL }},
373
16
    };
374
375
16
    static hf_register_info metadata_hf[] = {
376
16
        { &hf_vpp_metadata,
377
16
          { "Metadata", "vpp.metadata",
378
16
            FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
379
16
        },
380
16
    };
381
382
16
    static hf_register_info opaque_hf[] = {
383
16
        { &hf_vpp_buffer_opaque,
384
16
          { "Opaque", "vpp.opaque",
385
16
            FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
386
16
        },
387
16
    };
388
389
16
    static hf_register_info opaque2_hf[] = {
390
16
        { &hf_vpp_buffer_opaque2,
391
16
          { "Opaque2", "vpp.opaque2",
392
16
            FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
393
16
        },
394
16
    };
395
396
16
    static hf_register_info trace_hf[] = {
397
16
        { &hf_vpp_buffer_trace,
398
16
          { "Trace", "vpp.trace",  FT_STRINGZ, BASE_NONE, NULL, 0x0,
399
16
            NULL, HFILL },
400
16
        },
401
16
    };
402
403
16
    static int *vpp_ett[] = {
404
16
        &ett_vpp,
405
16
    };
406
16
    static int *ett_metadata[] = {
407
16
        &ett_vpp_metadata,
408
16
    };
409
16
    static int *ett_opaque[] = {
410
16
        &ett_vpp_opaque,
411
16
    };
412
16
    static int *ett_opaque2[] = {
413
16
        &ett_vpp_opaque2,
414
16
    };
415
16
    static int *ett_trace[] = {
416
16
        &ett_vpp_trace,
417
16
    };
418
419
16
    proto_vpp = proto_register_protocol("VPP Dispatch Trace", "VPP", "vpp");
420
16
    proto_register_field_array(proto_vpp, vpp_hf, array_length(vpp_hf));
421
16
    proto_register_subtree_array(vpp_ett, array_length(vpp_ett));
422
16
    register_dissector("vpp", dissect_vpp, proto_vpp);
423
424
16
    expert_vpp = expert_register_protocol(proto_vpp);
425
16
    expert_register_field_array(expert_vpp, vpp_ei, array_length(vpp_ei));
426
427
16
    proto_vpp_metadata = proto_register_protocol("VPP Buffer Metadata",
428
16
                                                 "VPP-Metadata",
429
16
                                                 "vpp-metadata");
430
16
    proto_register_field_array(proto_vpp_metadata, metadata_hf,
431
16
                               array_length(metadata_hf));
432
16
    proto_register_subtree_array(ett_metadata, array_length(ett_metadata));
433
16
    register_dissector("vppMetadata", dissect_vpp_metadata, proto_vpp_metadata);
434
435
16
    proto_vpp_opaque = proto_register_protocol("VPP Buffer Opaque", "VPP-Opaque",
436
16
                                               "vpp-opaque");
437
16
    proto_register_field_array(proto_vpp_opaque, opaque_hf,
438
16
                               array_length(opaque_hf));
439
16
    proto_register_subtree_array(ett_opaque, array_length(ett_opaque));
440
16
    register_dissector("vppOpaque", dissect_vpp_opaque, proto_vpp_opaque);
441
442
16
    proto_vpp_opaque2 = proto_register_protocol("VPP Buffer Opaque2",
443
16
                                                "VPP-Opaque2", "vpp-opaque2");
444
16
    proto_register_field_array(proto_vpp_opaque2, opaque2_hf,
445
16
                               array_length(opaque2_hf));
446
16
    proto_register_subtree_array(ett_opaque2, array_length(ett_opaque2));
447
16
    register_dissector("vppOpaque2", dissect_vpp_opaque2, proto_vpp_opaque2);
448
449
450
16
    proto_vpp_trace = proto_register_protocol("VPP Buffer Trace", "VPP-Trace",
451
16
                                              "vpp-trace");
452
16
    proto_register_field_array(proto_vpp_trace, trace_hf,
453
16
                               array_length(trace_hf));
454
16
    proto_register_subtree_array(ett_trace, array_length(ett_trace));
455
16
    register_dissector("vppTrace", dissect_vpp_trace, proto_vpp_trace);
456
457
80
#define _(idx,dname) next_dissectors[idx] = find_dissector(#dname);
458
16
    foreach_next_dissector;
459
16
#undef _
460
461
    /* if all else fails, dissect data as if ethernet MAC */
462
16
    next_dissectors[VLIB_NODE_PROTO_HINT_NONE] =
463
16
        next_dissectors [VLIB_NODE_PROTO_HINT_ETHERNET];
464
16
}
465
466
void
467
proto_reg_handoff_vpp(void)
468
16
{
469
16
    vpp_dissector_handle = find_dissector("vpp");
470
16
    vpp_metadata_dissector_handle = find_dissector("vppMetadata");
471
16
    vpp_opaque_dissector_handle = find_dissector("vppOpaque");
472
16
    vpp_opaque2_dissector_handle = find_dissector("vppOpaque2");
473
16
    vpp_trace_dissector_handle = find_dissector("vppTrace");
474
16
    dissector_add_uint("wtap_encap", WTAP_ENCAP_VPP, vpp_dissector_handle);
475
16
}
476
477
/*
478
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
479
 *
480
 * Local variables:
481
 * c-basic-offset: 4
482
 * tab-width: 8
483
 * indent-tabs-mode: nil
484
 * End:
485
 *
486
 * vi: set shiftwidth=4 tabstop=8 expandtab:
487
 * :indentSize=4:tabSize=8:noTabs=true:
488
 */