Coverage Report

Created: 2026-01-02 06:13

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