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-netlink-psample.c
Line
Count
Source
1
/* packet-netlink-psample.c
2
 * Routines for netlink-psample dissection
3
 * Based on netlink-net_dm and netlink-generic dissectors
4
 * Copyright 2021, Mellanox Technologies Ltd.
5
 * Code by Amit Cohen <amcohen@nvidia.com>
6
 *
7
 * Wireshark - Network traffic analyzer
8
 * By Gerald Combs <gerald@wireshark.org>
9
 * Copyright 1998 Gerald Combs
10
 *
11
 * SPDX-License-Identifier: GPL-2.0-or-later
12
 */
13
14
/* psample is a netlink-based protocol via which alerts
15
 * about sampled packets are sent to user space
16
 *
17
 * Relevant Linux kernel header file:
18
 * include/uapi/linux/psample.h
19
 */
20
21
#include "config.h"
22
23
#include <epan/packet.h>
24
25
#include "packet-netlink.h"
26
#include "packet-sll.h"
27
28
void proto_register_netlink_psample(void);
29
void proto_reg_handoff_netlink_psample(void);
30
31
enum ws_psample_commands {
32
  WS_PSAMPLE_CMD_SAMPLE,
33
  WS_PSAMPLE_CMD_GET_GROUP,
34
  WS_PSAMPLE_CMD_NEW_GROUP,
35
  WS_PSAMPLE_CMD_DEL_GROUP,
36
};
37
38
enum ws_psample_attrs {
39
  WS_PSAMPLE_ATTR_IIFINDEX,
40
  WS_PSAMPLE_ATTR_OIFINDEX,
41
  WS_PSAMPLE_ATTR_ORIGSIZE,
42
  WS_PSAMPLE_ATTR_SAMPLE_GROUP,
43
  WS_PSAMPLE_ATTR_GROUP_SEQ,
44
  WS_PSAMPLE_ATTR_SAMPLE_RATE,
45
  WS_PSAMPLE_ATTR_DATA,
46
  WS_PSAMPLE_ATTR_GROUP_REFCOUNT,
47
  WS_PSAMPLE_ATTR_TUNNEL,
48
  WS_PSAMPLE_ATTR_PAD,
49
  WS_PSAMPLE_ATTR_OUT_TC,
50
  WS_PSAMPLE_ATTR_OUT_TC_OCC,
51
  WS_PSAMPLE_ATTR_LATENCY,
52
  WS_PSAMPLE_ATTR_TIMESTAMP,
53
  WS_PSAMPLE_ATTR_PROTO,
54
};
55
56
struct netlink_psample_info {
57
  packet_info *pinfo;
58
  uint16_t protocol; /* protocol for packet payload */
59
};
60
61
static int proto_netlink_psample;
62
63
static dissector_handle_t netlink_psample_handle;
64
static dissector_table_t sll_ltype_table;
65
66
static int hf_psample_attrs;
67
static int hf_psample_commands;
68
static int hf_psample_group_refcount;
69
static int hf_psample_group_seq;
70
static int hf_psample_iifindex;
71
static int hf_psample_latency;
72
static int hf_psample_oifindex;
73
static int hf_psample_origsize;
74
static int hf_psample_out_tc;
75
static int hf_psample_out_tc_occ;
76
static int hf_psample_proto;
77
static int hf_psample_sample_group;
78
static int hf_psample_sample_rate;
79
static int hf_psample_timestamp;
80
static int hf_psample_tunnel;
81
82
static int ett_psample;
83
static int ett_psample_attrs;
84
85
static const value_string ws_psample_commands_vals[] = {
86
  { WS_PSAMPLE_CMD_SAMPLE,    "Sample" },
87
  { WS_PSAMPLE_CMD_GET_GROUP,   "Get group" },
88
  { WS_PSAMPLE_CMD_NEW_GROUP,   "New group" },
89
  { WS_PSAMPLE_CMD_DEL_GROUP,   "Delete group" },
90
  { 0, NULL },
91
};
92
93
static value_string_ext ws_psample_commands_vals_ext = VALUE_STRING_EXT_INIT(ws_psample_commands_vals);
94
95
static const value_string ws_psample_attrs_vals[] = {
96
  { WS_PSAMPLE_ATTR_IIFINDEX,   "Input interface index" },
97
  { WS_PSAMPLE_ATTR_OIFINDEX,   "Output interface index" },
98
  { WS_PSAMPLE_ATTR_ORIGSIZE,   "Original size" },
99
  { WS_PSAMPLE_ATTR_SAMPLE_GROUP,   "Sample group" },
100
  { WS_PSAMPLE_ATTR_GROUP_SEQ,    "Group sequence number" },
101
  { WS_PSAMPLE_ATTR_SAMPLE_RATE,    "Sample rate" },
102
  { WS_PSAMPLE_ATTR_DATA,     "Data" },
103
  { WS_PSAMPLE_ATTR_GROUP_REFCOUNT, "Group reference count" },
104
  { WS_PSAMPLE_ATTR_TUNNEL,   "Tunnel" },
105
  { WS_PSAMPLE_ATTR_PAD,      "Pad" },
106
  { WS_PSAMPLE_ATTR_OUT_TC,   "Output traffic class" },
107
  { WS_PSAMPLE_ATTR_OUT_TC_OCC,   "Output traffic class occupancy" },
108
  { WS_PSAMPLE_ATTR_LATENCY,    "Latency" },
109
  { WS_PSAMPLE_ATTR_TIMESTAMP,    "Timestamp" },
110
  { WS_PSAMPLE_ATTR_PROTO,    "Protocol" },
111
  { 0, NULL },
112
};
113
114
static value_string_ext ws_psample_attrs_vals_ext = VALUE_STRING_EXT_INIT(ws_psample_attrs_vals);
115
116
static int
117
dissect_psample_attrs(tvbuff_t *tvb, void *data, struct packet_netlink_data *nl_data, proto_tree *tree, int nla_type, int offset, int len)
118
0
{
119
0
  enum ws_psample_attrs type = (enum ws_psample_attrs) nla_type & NLA_TYPE_MASK;
120
0
  struct netlink_psample_info *info = (struct netlink_psample_info *) data;
121
0
  uint64_t value64, timestamp;
122
0
  nstime_t ts_nstime;
123
0
  tvbuff_t *next_tvb;
124
0
  uint32_t value;
125
126
0
  switch (type) {
127
0
  case WS_PSAMPLE_ATTR_IIFINDEX:
128
0
    proto_tree_add_item_ret_uint(tree, hf_psample_iifindex, tvb, offset, len, nl_data->encoding, &value);
129
0
    proto_item_append_text(tree, ": %u", value);
130
0
    return 1;
131
0
  case WS_PSAMPLE_ATTR_OIFINDEX:
132
0
    proto_tree_add_item_ret_uint(tree, hf_psample_oifindex, tvb, offset, len, nl_data->encoding, &value);
133
0
    proto_item_append_text(tree, ": %u", value);
134
0
    return 1;
135
0
  case WS_PSAMPLE_ATTR_ORIGSIZE:
136
0
    proto_tree_add_item_ret_uint(tree, hf_psample_origsize, tvb, offset, len, nl_data->encoding, &value);
137
0
    proto_item_append_text(tree, ": %u", value);
138
0
    return 1;
139
0
  case WS_PSAMPLE_ATTR_SAMPLE_GROUP:
140
0
    proto_tree_add_item_ret_uint(tree, hf_psample_sample_group, tvb, offset, len, nl_data->encoding, &value);
141
0
    proto_item_append_text(tree, ": %u", value);
142
0
    return 1;
143
0
  case WS_PSAMPLE_ATTR_GROUP_SEQ:
144
0
    proto_tree_add_item_ret_uint(tree, hf_psample_group_seq, tvb, offset, len, nl_data->encoding, &value);
145
0
    proto_item_append_text(tree, ": %u", value);
146
0
    return 1;
147
0
  case WS_PSAMPLE_ATTR_SAMPLE_RATE:
148
0
    proto_tree_add_item_ret_uint(tree, hf_psample_sample_rate, tvb, offset, len, nl_data->encoding, &value);
149
0
    proto_item_append_text(tree, ": %u", value);
150
0
    return 1;
151
0
  case WS_PSAMPLE_ATTR_DATA:
152
0
    next_tvb = tvb_new_subset_length(tvb, offset, len);
153
0
    if (!dissector_try_uint(sll_ltype_table, info->protocol, next_tvb, info->pinfo, tree))
154
0
      call_data_dissector(next_tvb, info->pinfo, tree);
155
0
    return 1;
156
0
  case WS_PSAMPLE_ATTR_GROUP_REFCOUNT:
157
0
    proto_tree_add_item_ret_uint(tree, hf_psample_group_refcount, tvb, offset, len, nl_data->encoding, &value);
158
0
    proto_item_append_text(tree, ": %u", value);
159
0
    return 1;
160
0
  case WS_PSAMPLE_ATTR_TUNNEL:
161
    /* Currently there is no support for tunnel dissection. */
162
0
    return 0;
163
0
  case WS_PSAMPLE_ATTR_OUT_TC:
164
0
    proto_tree_add_item_ret_uint(tree, hf_psample_out_tc, tvb, offset, len, nl_data->encoding, &value);
165
0
    proto_item_append_text(tree, ": %u", value);
166
0
    return 1;
167
0
  case WS_PSAMPLE_ATTR_OUT_TC_OCC:
168
0
    proto_tree_add_item_ret_uint64(tree, hf_psample_out_tc_occ, tvb, offset, len, nl_data->encoding, &value64);
169
0
    proto_item_append_text(tree, ": %"PRIu64, value64);
170
0
    return 1;
171
0
  case WS_PSAMPLE_ATTR_LATENCY:
172
0
    proto_tree_add_item_ret_uint64(tree, hf_psample_latency, tvb, offset, len, nl_data->encoding, &value64);
173
0
    proto_item_append_text(tree, ": %"PRIu64, value64);
174
0
    return 1;
175
0
  case WS_PSAMPLE_ATTR_TIMESTAMP:
176
0
    timestamp = tvb_get_uint64(tvb, offset, nl_data->encoding);
177
0
    ts_nstime.secs = timestamp / 1000000000;
178
0
    ts_nstime.nsecs = timestamp % 1000000000;
179
0
    proto_tree_add_time(tree, hf_psample_timestamp, tvb, offset, 8, &ts_nstime);
180
0
    return 1;
181
0
  case WS_PSAMPLE_ATTR_PROTO:
182
0
    info->protocol = tvb_get_uint16(tvb, offset, nl_data->encoding);
183
    /* This attribute encodes 'skb->protocol' and if it is greater
184
     * than or equal to 1536 (0x0600), then it is an Ethertype and
185
     * we need to treat the packet as Ethernet.
186
     */
187
0
    if (info->protocol >= 1536 || info->protocol == LINUX_SLL_P_802_2)
188
0
      info->protocol = LINUX_SLL_P_ETHERNET;
189
0
    proto_tree_add_item(tree, hf_psample_proto, tvb, offset, len, nl_data->encoding);
190
0
    return 1;
191
0
  default:
192
0
    return 0;
193
0
  }
194
0
}
195
196
static int
197
dissect_netlink_psample(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
198
0
{
199
0
  genl_info_t *genl_info = (genl_info_t *)data;
200
0
  struct netlink_psample_info info;
201
0
  proto_tree *nlmsg_tree;
202
0
  proto_item *pi;
203
0
  int offset;
204
205
0
  DISSECTOR_ASSERT(genl_info);
206
207
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "psample");
208
0
  col_clear(pinfo->cinfo, COL_INFO);
209
210
  /* Generic netlink header */
211
0
  offset = dissect_genl_header(tvb, genl_info, genl_info->nl_data, hf_psample_commands);
212
213
  /* Not all commands have a payload */
214
0
  if (!tvb_reported_length_remaining(tvb, offset))
215
    /* XXX If you do not set the protocol item, you cannot filter on these messages */
216
0
    return offset;
217
218
0
  pi = proto_tree_add_item(tree, proto_netlink_psample, tvb, offset, -1, ENC_NA);
219
0
  nlmsg_tree = proto_item_add_subtree(pi, ett_psample);
220
221
0
  info.pinfo = pinfo;
222
0
  info.protocol = 0;
223
224
0
  offset = dissect_netlink_attributes_to_end(tvb, hf_psample_attrs, ett_psample_attrs, &info, genl_info->nl_data, nlmsg_tree, offset, dissect_psample_attrs);
225
226
0
  return offset;
227
0
}
228
229
void
230
proto_register_netlink_psample(void)
231
14
{
232
14
  static hf_register_info hf[] = {
233
14
    { &hf_psample_commands,
234
14
      { "Command", "psample.cmd",
235
14
        FT_UINT8, BASE_DEC | BASE_EXT_STRING, &ws_psample_commands_vals_ext, 0x00,
236
14
        NULL, HFILL }
237
14
    },
238
14
    { &hf_psample_attrs,
239
14
      { "Attribute type", "psample.attr_type",
240
14
        FT_UINT16, BASE_DEC | BASE_EXT_STRING, &ws_psample_attrs_vals_ext, NLA_TYPE_MASK,
241
14
        NULL, HFILL }
242
14
    },
243
14
    { &hf_psample_iifindex,
244
14
      { "Input interface index", "psample.iifindex",
245
14
        FT_UINT16, BASE_HEX, NULL, 0x00,
246
14
        NULL, HFILL }
247
14
    },
248
14
    { &hf_psample_oifindex,
249
14
      { "Output interface index", "psample.oifindex",
250
14
        FT_UINT16, BASE_HEX, NULL, 0x00,
251
14
        NULL, HFILL }
252
14
    },
253
14
    { &hf_psample_origsize,
254
14
      { "Original size", "psample.origsize",
255
14
        FT_UINT32, BASE_HEX, NULL, 0x00,
256
14
        NULL, HFILL }
257
14
    },
258
14
    { &hf_psample_sample_group,
259
14
      { "Sample group", "psample.sample_group",
260
14
        FT_UINT32, BASE_DEC, NULL, 0x00,
261
14
        NULL, HFILL }
262
14
    },
263
14
    { &hf_psample_group_seq,
264
14
      { "Group sequence number", "psample.group_seq_num",
265
14
        FT_UINT32, BASE_DEC, NULL, 0x00,
266
14
        NULL, HFILL }
267
14
    },
268
14
    { &hf_psample_sample_rate,
269
14
      { "Sample rate", "psample.sample_rate",
270
14
        FT_UINT32, BASE_DEC, NULL, 0x00,
271
14
        NULL, HFILL }
272
14
    },
273
14
    { &hf_psample_tunnel,
274
14
      { "Tunnel", "psample.tunnel",
275
14
        FT_UINT32, BASE_HEX, NULL, 0x00,
276
14
        NULL, HFILL }
277
14
    },
278
14
    { &hf_psample_group_refcount,
279
14
      { "Group reference count", "psample.group_refcount",
280
14
        FT_UINT32, BASE_HEX, NULL, 0x00,
281
14
        NULL, HFILL }
282
14
    },
283
14
    { &hf_psample_out_tc,
284
14
      { "Output traffic class", "psample.out_tc",
285
14
        FT_UINT16, BASE_DEC, NULL, 0x00,
286
14
        NULL, HFILL }
287
14
    },
288
14
    { &hf_psample_out_tc_occ,
289
14
      { "Output traffic class occupancy", "psample.out_tc_occ",
290
14
        FT_UINT64, BASE_DEC, NULL, 0x00,
291
14
        NULL, HFILL }
292
14
    },
293
14
    { &hf_psample_latency,
294
14
      { "Latency", "psample.latency",
295
14
        FT_UINT64, BASE_DEC, NULL, 0x00,
296
14
        NULL, HFILL }
297
14
    },
298
14
    { &hf_psample_timestamp,
299
14
      { "Timestamp", "psample.timestamp",
300
14
        FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
301
14
        NULL, HFILL }
302
14
    },
303
14
    { &hf_psample_proto,
304
14
      { "Protocol", "psample.proto",
305
14
        FT_UINT16, BASE_HEX, NULL, 0x00,
306
14
        NULL, HFILL }
307
14
    },
308
14
  };
309
310
14
  static int *ett[] = {
311
14
    &ett_psample,
312
14
    &ett_psample_attrs,
313
14
  };
314
315
14
  proto_netlink_psample = proto_register_protocol("Linux psample protocol", "psample", "psample");
316
14
  proto_register_field_array(proto_netlink_psample, hf, array_length(hf));
317
14
  proto_register_subtree_array(ett, array_length(ett));
318
319
14
  netlink_psample_handle = register_dissector("psample", dissect_netlink_psample, proto_netlink_psample);
320
14
}
321
322
void
323
proto_reg_handoff_netlink_psample(void)
324
14
{
325
14
  dissector_add_string("genl.family", "psample", netlink_psample_handle);
326
14
  sll_ltype_table = find_dissector_table("sll.ltype");
327
14
}
328
329
/*
330
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
331
 *
332
 * Local variables:
333
 * c-basic-offset: 8
334
 * tab-width: 8
335
 * indent-tabs-mode: t
336
 * End:
337
 *
338
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
339
 * :indentSize=8:tabSize=8:noTabs=false:
340
 */