Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-nsh.c
Line
Count
Source
1
/* packet-nsh.c
2
 * Routines for Network Service Header
3
 *
4
 * RFC8300
5
 * Author: Vanson Lim <vlim@cisco.com>
6
 * (c) Copyright 2020, Cisco Systems Inc.
7
 *
8
 * draft-ietf-sfc-nsh-01
9
 * Author: Chidambaram Arunachalam <carunach@cisco.com>
10
 * Copyright 2016, ciscoSystems Inc.
11
 *
12
 * (c) Copyright 2016, Sumit Kumar Jha <sjha3@ncsu.edu>
13
 * Support for VXLAN GPE encapsulation
14
 *
15
 * Wireshark - Network traffic analyzer
16
 * By Gerald Combs <gerald@wireshark.org>
17
 * Copyright 1998 Gerald Combs
18
 *
19
 * SPDX-License-Identifier: GPL-2.0-or-later
20
 */
21
22
#include "config.h"
23
#include <epan/packet.h>
24
#include <epan/etypes.h>
25
#include <epan/expert.h>
26
27
#include <wsutil/ws_roundup.h>
28
29
#include "packet-nsh.h"
30
#include "packet-vxlan.h"
31
#include "packet-iana-data.h"
32
33
3
#define MD_TYPE_1 1
34
34
#define MD_TYPE_2 2
35
36
21
#define MD_MAX_VERSION 0
37
38
/* Prototypes */
39
void proto_reg_handoff_nsh(void);
40
void proto_register_nsh(void);
41
42
static dissector_handle_t nsh_handle;
43
44
static const value_string nsh_next_protocols[] = {
45
  { NSH_NONE, "None" },
46
  { NSH_IPV4, "IPv4" },
47
  { NSH_IPV6, "IPv6" },
48
  { NSH_ETHERNET, "Ethernet" },
49
  { NSH_NSH, "NSH" },
50
  { NSH_MPLS, "MPLS" },
51
  { NSH_EXPERIMENT_1, "Experiment 1" },
52
  { NSH_EXPERIMENT_2, "Experiment 2" },
53
  { 0, NULL }
54
};
55
56
57
static int proto_nsh;
58
static int hf_nsh_version;
59
static int hf_nsh_oam;
60
static int hf_nsh_critical_metadata;
61
static int hf_nsh_ttl;
62
static int hf_nsh_length;
63
static int hf_nsh_md_type;
64
static int hf_nsh_next_proto;
65
static int hf_nsh_service_pathID;
66
static int hf_nsh_service_index;
67
static int hf_nsh_context_header;
68
static int hf_nsh_metadata_class;
69
static int hf_nsh_metadata_type;
70
static int hf_nsh_metadata_length;
71
static int hf_nsh_metadata;
72
73
// RFC9263 TLVs
74
static int hf_nsh_tlv_forwarding_context_type;
75
static int hf_nsh_tlv_forwarding_context_vlan;
76
static int hf_nsh_tlv_forwarding_context_svlan;
77
static int hf_nsh_tlv_forwarding_context_cvlan;
78
static int hf_nsh_tlv_forwarding_context_mpls_vpn_label;
79
static int hf_nsh_tlv_forwarding_context_vni;
80
static int hf_nsh_tlv_forwarding_context_session_id;
81
static int hf_nsh_tlv_tenant_id;
82
static int hf_nsh_tlv_ingress_network_node_info;
83
static int hf_nsh_tlv_ingress_network_source_iface;
84
static int hf_nsh_tlv_flow_id_type;
85
static int hf_nsh_tlv_ipv6_flow_id;
86
static int hf_nsh_tlv_mpls_entropy_label;
87
static int hf_nsh_tlv_source_group;
88
static int hf_nsh_tlv_dest_group;
89
static int hf_nsh_tlv_policy_id;
90
91
// TR-459i2 TLVs
92
static int hf_nsh_bbf_logical_port_id;
93
static int hf_nsh_bbf_logical_port_id_str;
94
static int hf_nsh_bbf_mac;
95
static int hf_nsh_bbf_network_instance;
96
static int hf_nsh_bbf_interface_id;
97
98
static expert_field ei_nsh_length_invalid;
99
static expert_field ei_nsh_tlv_incomplete_dissection;
100
101
static int ett_nsh;
102
static int ett_nsh_tlv;
103
104
static dissector_table_t subdissector_table;
105
static dissector_table_t tlv_table;
106
107
/*
108
 *Dissect Fixed Length Context headers
109
 *
110
 */
111
static void
112
dissect_nsh_md_type_1(tvbuff_t *tvb, proto_tree *nsh_tree, int offset)
113
3
{
114
3
  proto_tree_add_item(nsh_tree, hf_nsh_context_header, tvb, offset, 4, ENC_NA);
115
3
  proto_tree_add_item(nsh_tree, hf_nsh_context_header, tvb, offset + 4, 4, ENC_NA);
116
3
  proto_tree_add_item(nsh_tree, hf_nsh_context_header, tvb, offset + 8, 4, ENC_NA);
117
3
  proto_tree_add_item(nsh_tree, hf_nsh_context_header, tvb, offset + 12, 4, ENC_NA);
118
3
}
119
120
/*
121
 *Dissect Variable Length Context headers
122
 *
123
 */
124
125
static void
126
dissect_nsh_md_type_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *nsh_tree, int offset, int nsh_bytes_len)
127
30
{
128
230
  while (offset < nsh_bytes_len) {
129
200
    uint16_t tlv_class = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
130
200
    uint8_t  tlv_type = tvb_get_uint8(tvb, offset + 2);
131
200
    uint8_t  tlv_len = tvb_get_uint8(tvb, offset + 3) & 0x7F;
132
133
200
    proto_item *tlv_item;
134
200
    proto_tree *tlv_tree = proto_tree_add_subtree_format(nsh_tree, tvb, offset, 4 + tlv_len, ett_nsh_tlv, &tlv_item, "TLV: Class %u Type %u", tlv_class, tlv_type);
135
136
200
    proto_tree_add_item(tlv_tree, hf_nsh_metadata_class, tvb, offset, 2, ENC_BIG_ENDIAN);
137
200
    proto_tree_add_item(tlv_tree, hf_nsh_metadata_type, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
138
200
    proto_tree_add_item(tlv_tree, hf_nsh_metadata_length, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
139
200
    offset += 4;
140
141
200
    if (tlv_len > 0)
142
80
    {
143
80
      tvbuff_t *tlv_tvb = tvb_new_subset_length(tvb, offset, tlv_len);
144
80
      const uint32_t key = ((uint32_t) tlv_class << 8) | tlv_type;
145
80
      int dissected = dissector_try_uint(tlv_table, key, tlv_tvb, pinfo, tlv_tree);
146
147
80
      if (dissected == 0) {
148
68
        proto_tree_add_item(tlv_tree, hf_nsh_metadata, tlv_tvb, 0, -1, ENC_NA);
149
68
      } else if (dissected > 0 && (unsigned) dissected != tlv_len) {
150
4
        expert_add_info_format(pinfo, tlv_tree, &ei_nsh_tlv_incomplete_dissection, "TLV dissector did not dissect the whole data (%d != %d)", dissected, tlv_len);
151
4
      }
152
153
80
      offset += WS_ROUNDUP_4(tlv_len); // aligned up on 4-byte boundary
154
80
    }
155
200
  }
156
30
}
157
158
159
/*
160
 *Dissect Network Service Header
161
 *
162
 */
163
164
static int
165
dissect_nsh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
166
108
{
167
168
108
  int offset = 0;
169
108
  int md_type = -1;
170
108
  uint32_t nsh_bytes_len;
171
108
  int nsh_next_proto = -1;
172
108
  proto_item *length_pi;
173
108
  tvbuff_t *next_tvb;
174
175
108
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "NSH");
176
108
  col_set_str(pinfo->cinfo, COL_INFO, "Network Service Header");
177
178
108
  proto_item *ti;
179
108
  proto_tree *nsh_tree;
180
181
108
  ti = proto_tree_add_item(tree, proto_nsh, tvb, offset, 2, ENC_NA);
182
108
  nsh_tree = proto_item_add_subtree(ti, ett_nsh);
183
184
  /*NSH Base Header*/
185
186
108
  proto_tree_add_item(nsh_tree, hf_nsh_version, tvb, offset, 2, ENC_BIG_ENDIAN);
187
108
  proto_tree_add_item(nsh_tree, hf_nsh_oam, tvb, offset, 2, ENC_BIG_ENDIAN);
188
108
  proto_tree_add_item(nsh_tree, hf_nsh_critical_metadata, tvb, offset, 2, ENC_BIG_ENDIAN);
189
190
191
  /*NSH Time to live Bits 4 - 9*/
192
108
  proto_tree_add_item(nsh_tree, hf_nsh_ttl, tvb, offset, 2, ENC_BIG_ENDIAN);
193
108
  length_pi = proto_tree_add_item_ret_uint(nsh_tree, hf_nsh_length, tvb, offset, 2, ENC_BIG_ENDIAN, &nsh_bytes_len);
194
108
  nsh_bytes_len *= 4;
195
108
  proto_item_set_len(ti, nsh_bytes_len);
196
197
198
108
  md_type = tvb_get_uint8(tvb, offset + 2);
199
108
  proto_tree_add_item(nsh_tree, hf_nsh_md_type, tvb, offset + 2, 1, ENC_BIG_ENDIAN);
200
201
108
  nsh_next_proto = tvb_get_uint8(tvb, offset + 3);
202
108
  proto_tree_add_item(nsh_tree, hf_nsh_next_proto, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
203
204
  /*NSH Service Path Header */
205
108
  offset = offset + 4;
206
108
  proto_tree_add_item(nsh_tree, hf_nsh_service_pathID, tvb, offset, 3, ENC_BIG_ENDIAN);
207
108
  proto_tree_add_item(nsh_tree, hf_nsh_service_index, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
208
209
  /* Decode Context Headers */
210
108
  offset = offset + 4;
211
108
  switch (md_type) {
212
213
3
  case MD_TYPE_1:
214
    /* The Length MUST be of value 0x6 for MD Type equal to 0x1 */
215
3
    if (nsh_bytes_len != 4 * 6) {
216
2
      expert_add_info_format(pinfo, length_pi, &ei_nsh_length_invalid,
217
2
          "Length MUST be of value 0x6 for MD Type equal to 0x1");
218
2
      nsh_bytes_len = 4 * 6;
219
2
    }
220
3
    dissect_nsh_md_type_1(tvb, nsh_tree, offset);
221
3
    break;
222
223
34
  case MD_TYPE_2:
224
225
    /* The Length MUST be of value 0x2 or greater for MD Type equal to 0x2 */
226
34
    if (nsh_bytes_len < 4 * 2) {
227
2
      expert_add_info_format(pinfo, length_pi, &ei_nsh_length_invalid,
228
2
          "Length MUST be of value 0x2 or greater for MD Type equal to 0x2");
229
2
      nsh_bytes_len = 4 * 2;
230
2
    }
231
    /* MD Type 2 indicates ZERO or more Variable Length Context headers*/
232
34
    if (nsh_bytes_len > 8)
233
30
      dissect_nsh_md_type_2(tvb, pinfo, nsh_tree, offset, nsh_bytes_len);
234
34
    break;
235
236
67
  default:
237
    /*
238
      * Unknown type, but assume presence of at least the NSH
239
      * Base Header (32 bits, 4 bytes).
240
      */
241
67
    if (nsh_bytes_len < 4) {
242
16
      expert_add_info_format(pinfo, length_pi, &ei_nsh_length_invalid,
243
16
          "Length must be at least 0x1 for NSH Base Header");
244
16
      nsh_bytes_len = 4;
245
16
    }
246
67
    break;
247
248
108
  }
249
250
  /*Decode next protocol payload */
251
252
88
  if (tvb_captured_length_remaining(tvb, nsh_bytes_len) > 0) {
253
68
    next_tvb = tvb_new_subset_remaining(tvb, nsh_bytes_len);
254
68
    if (!dissector_try_uint(subdissector_table, nsh_next_proto, next_tvb, pinfo, tree)) {
255
20
      call_data_dissector(next_tvb, pinfo, tree);
256
20
    }
257
68
  }
258
259
88
  return tvb_captured_length(tvb);
260
261
108
}
262
263
typedef struct {
264
  uint16_t    class;
265
  uint8_t     type;
266
  const char* name;
267
  dissector_t dissector;
268
} nsh_tlv;
269
270
static int dissect_tlv_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data, void *cb_data)
271
12
{
272
12
  const nsh_tlv* tlv = cb_data;
273
12
  proto_item_set_text(proto_tree_get_parent(tree), "TLV: %s", tlv->name);
274
12
  return tlv->dissector(tvb, pinfo, tree, data);
275
12
}
276
277
static const value_string forwarding_context_type_vals[] = {
278
    { 0, "VLAN Forwarding Context" },
279
    { 1, "QinQ Forwarding Context" },
280
    { 2, "MPLS VPN Forwarding Context" },
281
    { 3, "VNI Forwarding Context" },
282
    { 4, "Session ID Forwarding Context" },
283
    { 0, NULL },
284
};
285
286
static const value_string flow_id_type_vals[] = {
287
    { 0, "IPv6 Flow ID" },
288
    { 1, "MPLS entropy label" },
289
    { 0, NULL },
290
};
291
292
// https://datatracker.ietf.org/doc/html/rfc9263#name-forwarding-context
293
static int dissect_tlv_forwarding_context(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
294
5
{
295
5
  uint32_t context_type;
296
297
5
  proto_tree_add_item_ret_uint(tree, hf_nsh_tlv_forwarding_context_type, tvb, 0, 1, ENC_BIG_ENDIAN, &context_type);
298
299
5
  switch (context_type)
300
5
  {
301
2
  case 0x00:
302
2
    proto_tree_add_item(tree, hf_nsh_tlv_forwarding_context_vlan, tvb, 1, 2, ENC_BIG_ENDIAN);
303
2
    return 4;
304
0
  case 0x01:
305
0
    proto_tree_add_item(tree, hf_nsh_tlv_forwarding_context_svlan, tvb, 1, 3, ENC_BIG_ENDIAN);
306
0
    proto_tree_add_item(tree, hf_nsh_tlv_forwarding_context_cvlan, tvb, 1, 3, ENC_BIG_ENDIAN);
307
0
    return 4;
308
0
  case 0x02:
309
0
    proto_tree_add_item(tree, hf_nsh_tlv_forwarding_context_mpls_vpn_label, tvb, 1, 3, ENC_BIG_ENDIAN);
310
0
    return 4;
311
0
  case 0x03:
312
0
    proto_tree_add_item(tree, hf_nsh_tlv_forwarding_context_vni, tvb, 1, 3, ENC_BIG_ENDIAN);
313
0
    return 4;
314
1
  case 0x04:
315
1
    proto_tree_add_item(tree, hf_nsh_tlv_forwarding_context_session_id, tvb, 4, 4, ENC_BIG_ENDIAN);
316
1
    return 8;
317
5
  }
318
319
2
  return tvb_reported_length(tvb);
320
5
}
321
322
// https://datatracker.ietf.org/doc/html/rfc9263#name-tenant-id
323
static int dissect_tlv_tenant_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
324
1
{
325
1
  proto_tree_add_item(tree, hf_nsh_tlv_tenant_id, tvb, 0, -1, ENC_NA);
326
327
1
  return tvb_reported_length(tvb);
328
1
}
329
330
// https://datatracker.ietf.org/doc/html/rfc9263#name-ingress-network-node-inform
331
static int dissect_tlv_ingress_network_node_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
332
0
{
333
0
  proto_tree_add_item(tree, hf_nsh_tlv_ingress_network_node_info, tvb, 0, -1, ENC_NA);
334
335
0
  return tvb_reported_length(tvb);
336
0
}
337
338
// https://datatracker.ietf.org/doc/html/rfc9263#name-ingress-node-source-interfa
339
static int dissect_tlv_ingress_network_source_iface(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
340
1
{
341
1
  proto_tree_add_item(tree, hf_nsh_tlv_ingress_network_source_iface, tvb, 0, -1, ENC_NA);
342
343
1
  return tvb_reported_length(tvb);
344
1
}
345
346
// https://datatracker.ietf.org/doc/html/rfc9263#name-flow-id-2
347
static int dissect_tlv_flow_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
348
1
{
349
1
  uint32_t context_type;
350
1
  proto_tree_add_item_ret_uint(tree, hf_nsh_tlv_flow_id_type, tvb, 0, 1, ENC_BIG_ENDIAN, &context_type);
351
352
1
  switch (context_type)
353
1
  {
354
0
  case 0x00:
355
0
    proto_tree_add_item(tree, hf_nsh_tlv_ipv6_flow_id, tvb, 1, 3, ENC_BIG_ENDIAN);
356
0
    break;
357
0
  case 0x01:
358
0
    proto_tree_add_item(tree, hf_nsh_tlv_mpls_entropy_label, tvb, 1, 3, ENC_BIG_ENDIAN);
359
0
    break;
360
1
  }
361
362
1
  return 4;
363
1
}
364
365
// https://datatracker.ietf.org/doc/html/rfc9263#name-source-and-or-destination-gr
366
static int dissect_tlv_source_dest_groups(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
367
1
{
368
1
  proto_tree_add_item(tree, hf_nsh_tlv_source_group, tvb, 0, 4, ENC_NA);
369
1
  proto_tree_add_item(tree, hf_nsh_tlv_dest_group, tvb, 4, 4, ENC_NA);
370
371
1
  return 8;
372
1
}
373
374
375
// https://datatracker.ietf.org/doc/html/rfc9263#name-policy-id
376
static int dissect_tlv_policy_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
377
2
{
378
2
  proto_tree_add_item(tree, hf_nsh_tlv_policy_id, tvb, 0, -1, ENC_NA);
379
380
2
  return tvb_reported_length(tvb);
381
2
}
382
383
static int dissect_tlv_logical_port(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
384
1
{
385
1
  if (tvb_ascii_isprint(tvb, 0, -1))
386
0
  {
387
0
    const uint8_t* string_value;
388
0
    proto_tree_add_item_ret_string(tree, hf_nsh_bbf_logical_port_id_str, tvb, 0, -1, ENC_ASCII | ENC_NA, pinfo->pool, &string_value);
389
0
    proto_item_append_text(proto_tree_get_parent(tree), ": %s", string_value);
390
0
  }
391
1
  else
392
1
  {
393
1
    proto_tree_add_item(tree, hf_nsh_bbf_logical_port_id, tvb, 0, -1, ENC_NA);
394
1
  }
395
396
1
  return tvb_reported_length(tvb);
397
1
}
398
399
static int dissect_tlv_mac(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
400
0
{
401
0
  proto_tree_add_item(tree, hf_nsh_bbf_mac, tvb, 0, 6, ENC_NA);
402
0
  return 6;
403
0
}
404
405
static int dissect_tlv_network_instance(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
406
0
{
407
0
  const uint8_t* string_value;
408
0
  proto_tree_add_item_ret_string(tree, hf_nsh_bbf_network_instance, tvb, 0, -1, ENC_ASCII | ENC_NA, pinfo->pool, &string_value);
409
0
  proto_item_append_text(proto_tree_get_parent(tree), ": %s", string_value);
410
0
  return tvb_reported_length(tvb);
411
0
}
412
413
static int dissect_tlv_iface_identifier(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
414
0
{
415
0
  proto_tree_add_item(tree, hf_nsh_bbf_interface_id, tvb, 0, 8, ENC_NA);
416
0
  return 8;
417
0
}
418
419
static void register_tlv_dissectors(void)
420
14
{
421
  /* The TLV subdissector table contains all dissectors for the TLV data.
422
     The key for the dissector is a combination of class + type.
423
     In order to be able to use a dissector-table easily, these 2 bytes are combined into a
424
     24-bit integer, containing the concatenation of class and type (as they appear on the wire in network-order).
425
426
     Relevant RFC section: https://datatracker.ietf.org/doc/html/rfc8300#section-9.1.4
427
     */
428
14
  static const nsh_tlv tlvs[] = {
429
    // TLVs defined by IETF in RFC9263
430
14
    {0x0000, 0x04, "Forwarding Context",               dissect_tlv_forwarding_context},
431
14
    {0x0000, 0x05, "Tenant ID",                        dissect_tlv_tenant_id},
432
14
    {0x0000, 0x06, "Ingress Network Node Info",        dissect_tlv_ingress_network_node_info},
433
14
    {0x0000, 0x07, "Ingress Network Source Interface", dissect_tlv_ingress_network_source_iface},
434
14
    {0x0000, 0x08, "Flow ID",                          dissect_tlv_flow_id},
435
14
    {0x0000, 0x09, "Source/Dest Groups",               dissect_tlv_source_dest_groups},
436
14
    {0x0000, 0x0A, "Policy ID",                        dissect_tlv_policy_id},
437
    // TLVs defined by BBF in TR-459i2:
438
14
    {0x0200, 0x00, "Logical Port",         dissect_tlv_logical_port},
439
14
    {0x0200, 0x01, "MAC",                  dissect_tlv_mac},
440
14
    {0x0200, 0x02, "Network Instance",     dissect_tlv_network_instance},
441
14
    {0x0200, 0x03, "Interface Identifier", dissect_tlv_iface_identifier},
442
14
  };
443
444
168
  for (unsigned i = 0; i < array_length(tlvs); i++) {
445
154
    const uint32_t key = ((uint32_t) tlvs[i].class << 8) | tlvs[i].type;
446
154
    dissector_add_uint("nsh.tlv", key, create_dissector_handle_with_data(dissect_tlv_data, -1, (void*) &tlvs[i]));
447
154
  }
448
14
}
449
450
static bool
451
dissect_nsh_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
452
24
{
453
24
  const int tvb_length = tvb_captured_length(tvb);
454
24
  if (tvb_length < 8) return false;
455
456
21
  const uint8_t version = tvb_get_uint8(tvb, 0) >> 6;
457
21
  const uint8_t length  = tvb_get_uint8(tvb, 1) & 0x3F;
458
21
  const uint8_t md_type = tvb_get_uint8(tvb, 2) & 0x0F;
459
21
  const uint8_t proto   = tvb_get_uint8(tvb, 3);
460
461
21
  if (version > MD_MAX_VERSION)     return false;
462
17
  if (md_type != 1 && md_type != 2) return false;
463
11
  if (md_type == 1 && length != 6)  return false;
464
9
  if (md_type == 2 && length <  2)  return false;
465
7
  if (length * 4 > tvb_length)      return false;
466
5
  if (proto == 0)                   return false;
467
3
  if (proto > NSH_MAX_PROTOCOL)     return false;
468
469
  // Note: md_type = 0x0 and md_type = 0xf are strictly speaking also valid.
470
  // For the heuristic to work as good as possible, it is best to restrict
471
  // as much as possible and only allow md_type 1 and 2.
472
473
2
  dissect_nsh(tvb, pinfo, tree, data);
474
2
  return true;
475
3
}
476
477
void
478
proto_register_nsh(void)
479
14
{
480
14
  expert_module_t *expert_nsh;
481
482
14
  static hf_register_info nsh_info[] = {
483
484
    /* Network Service Header fields */
485
14
    { &hf_nsh_version,
486
14
    { "Version", "nsh.version",
487
14
    FT_UINT16, BASE_DEC_HEX, NULL, 0xC000,
488
14
    NULL, HFILL }
489
14
    },
490
491
14
    { &hf_nsh_oam,
492
14
    { "O Bit", "nsh.Obit",
493
14
    FT_UINT16, BASE_DEC, NULL, 0x2000,
494
14
    "OAM Bit", HFILL }
495
14
    },
496
497
498
14
    { &hf_nsh_critical_metadata,
499
14
    { "C Bit", "nsh.CBit",
500
14
    FT_UINT16, BASE_DEC, NULL, 0x1000,
501
14
    "Critical Metadata Bit", HFILL }
502
14
    },
503
504
505
14
    { &hf_nsh_ttl,
506
14
    { "Time to live", "nsh.ttl",
507
14
    FT_UINT16, BASE_HEX, NULL, 0x0FC0,
508
14
    "Maximum SFF hops for an SFP, this field is used for service-plane loop detection", HFILL }
509
14
    },
510
511
512
14
    { &hf_nsh_length,
513
14
    { "Length", "nsh.length",
514
14
    FT_UINT16, BASE_DEC_HEX, NULL, 0x003F,
515
14
    "Total length, in 4-byte words, of NSH including Base, Service Path headers and optional variable TLVs", HFILL }
516
14
    },
517
518
519
14
    { &hf_nsh_md_type,
520
14
    { "MD Type", "nsh.mdtype",
521
14
    FT_UINT8, BASE_DEC_HEX, NULL, 0x00,
522
14
    "Metadata Type defines the format of the metadata being carried", HFILL }
523
14
    },
524
525
526
14
    { &hf_nsh_next_proto,
527
14
    { "Next Protocol", "nsh.nextproto",
528
14
    FT_UINT8, BASE_DEC_HEX, VALS(nsh_next_protocols), 0x00,
529
14
    "Protocol type of the original packet", HFILL }
530
14
    },
531
532
533
14
    { &hf_nsh_service_pathID,
534
14
    { "SPI", "nsh.spi",
535
14
    FT_UINT24, BASE_DEC_HEX, NULL, 0x00,
536
14
    "Service Path Identifier", HFILL }
537
14
    },
538
539
540
14
    { &hf_nsh_service_index,
541
14
    { "SI", "nsh.si",
542
14
    FT_UINT8, BASE_DEC_HEX, NULL, 0x00,
543
14
    "Service Index", HFILL }
544
14
    },
545
546
547
548
14
    { &hf_nsh_context_header,
549
14
    { "Context Header", "nsh.contextheader",
550
14
    FT_BYTES, BASE_NONE, NULL, 0x00,
551
14
    "Mandatory Context Header", HFILL }
552
14
    },
553
554
555
14
    { &hf_nsh_metadata_class,
556
14
    { "TLV Class", "nsh.metadataclass",
557
14
    FT_UINT16, BASE_DEC_HEX, NULL, 0x00,
558
14
    "TLV class describes the scope of the metadata type field", HFILL }
559
14
    },
560
561
562
14
    { &hf_nsh_metadata_type,
563
14
    { "Type", "nsh.metadatatype",
564
14
    FT_UINT8, BASE_DEC_HEX, NULL, 0x00,
565
14
    "Type of metadata", HFILL }
566
14
    },
567
568
569
14
    { &hf_nsh_metadata_length,
570
14
    { "Length", "nsh.metadatalen",
571
14
    FT_UINT8, BASE_HEX, NULL, 0x7F,
572
14
    "Length of the variable metadata in bytes", HFILL }
573
14
    },
574
575
576
14
    { &hf_nsh_metadata,
577
14
    { "Variable Metadata", "nsh.metadata",
578
14
    FT_BYTES, BASE_NONE, NULL, 0x00,
579
14
    "Variable length metadata", HFILL }
580
14
    },
581
582
    // RFC9263
583
14
    { &hf_nsh_tlv_forwarding_context_type,
584
14
    { "CT", "nsh.tlv.forwarding_context.type",
585
14
      FT_UINT8, BASE_DEC, VALS(forwarding_context_type_vals), 0xf0,
586
14
      "Context Type", HFILL }
587
14
    },
588
14
    { &hf_nsh_tlv_forwarding_context_vlan,
589
14
    { "VLAN ID", "nsh.tlv.forwarding_context.vlan",
590
14
      FT_UINT16, BASE_DEC, NULL, 0x0fff,
591
14
      NULL, HFILL }
592
14
    },
593
14
    { &hf_nsh_tlv_forwarding_context_svlan,
594
14
    { "Service VLAN ID", "nsh.tlv.forwarding_context.svlan",
595
14
      FT_UINT24, BASE_DEC, NULL, 0xfff000,
596
14
      NULL, HFILL }
597
14
    },
598
14
    { &hf_nsh_tlv_forwarding_context_cvlan,
599
14
    { "Customer VLAN ID", "nsh.tlv.forwarding_context.cvlan",
600
14
      FT_UINT24, BASE_DEC, NULL, 0x000fff,
601
14
      NULL, HFILL }
602
14
    },
603
14
    { &hf_nsh_tlv_forwarding_context_mpls_vpn_label,
604
14
    { "MPLS VPN Label", "nsh.tlv.forwarding_context.mpls_vpn_label",
605
14
      FT_UINT24, BASE_DEC, NULL, 0x0fffff,
606
14
      NULL, HFILL }
607
14
    },
608
14
    { &hf_nsh_tlv_forwarding_context_vni,
609
14
    { "VNI", "nsh.tlv.forwarding_context.vni",
610
14
      FT_UINT24, BASE_DEC, NULL, 0x0,
611
14
      "Virtual Network Identifier", HFILL }
612
14
    },
613
14
    { &hf_nsh_tlv_forwarding_context_session_id,
614
14
    { "Session ID", "nsh.tlv.forwarding_context.session_id",
615
14
      FT_UINT32, BASE_DEC, NULL, 0x0,
616
14
      NULL, HFILL }
617
14
    },
618
14
    { &hf_nsh_tlv_tenant_id,
619
14
    { "Tenant ID", "nsh.tlv.tenant_id",
620
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
621
14
      NULL, HFILL }
622
14
    },
623
14
    { &hf_nsh_tlv_ingress_network_node_info,
624
14
    { "Ingress Network Node Info", "nsh.tlv.ingress_network_node_info",
625
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
626
14
      NULL, HFILL }
627
14
    },
628
14
    { &hf_nsh_tlv_ingress_network_source_iface,
629
14
    { "Ingress Network Node Info", "nsh.tlv.ingress_network_source_iface",
630
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
631
14
      NULL, HFILL }
632
14
    },
633
14
    { &hf_nsh_tlv_flow_id_type,
634
14
    { "CT", "nsh.tlv.flow_id.type",
635
14
      FT_UINT8, BASE_DEC, VALS(flow_id_type_vals), 0xf0,
636
14
      "Context Type", HFILL }
637
14
    },
638
14
    { &hf_nsh_tlv_ipv6_flow_id,
639
14
    { "IPv6 Flow ID", "nsh.tlv.ipv6_flow_id",
640
14
      FT_UINT24, BASE_DEC, NULL, 0x0fffff,
641
14
      NULL, HFILL }
642
14
    },
643
14
    { &hf_nsh_tlv_mpls_entropy_label,
644
14
    { "MPLS Entropy Label", "nsh.tlv.mpls_entropy_label",
645
14
      FT_UINT24, BASE_DEC, NULL, 0x0fffff,
646
14
      NULL, HFILL }
647
14
    },
648
14
    { &hf_nsh_tlv_source_group,
649
14
    { "Source Group", "nsh.tlv.source_group",
650
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
651
14
      NULL, HFILL }
652
14
    },
653
14
    { &hf_nsh_tlv_dest_group,
654
14
    { "Destination Group", "nsh.tlv.dest_group",
655
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
656
14
      NULL, HFILL }
657
14
    },
658
14
    { &hf_nsh_tlv_policy_id,
659
14
    { "Policy ID", "nsh.tlv.policy_id",
660
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
661
14
      NULL, HFILL }
662
14
    },
663
664
    // TR-459i2
665
14
    { &hf_nsh_bbf_logical_port_id,
666
14
    { "Logical Port", "nsh.tlv.bbf.logical_port_id",
667
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
668
14
      NULL, HFILL }
669
14
    },
670
14
    { &hf_nsh_bbf_logical_port_id_str,
671
14
    { "Logical Port", "nsh.tlv.bbf.logical_port_id_str",
672
14
      FT_STRING, BASE_NONE, NULL, 0x0,
673
14
      NULL, HFILL }
674
14
    },
675
14
    { &hf_nsh_bbf_mac,
676
14
    { "MAC Address", "nsh.tlv.bbf.mac",
677
14
      FT_ETHER, BASE_NONE, NULL, 0x0,
678
14
      NULL, HFILL }
679
14
    },
680
14
    { &hf_nsh_bbf_network_instance,
681
14
    { "Network Instance", "nsh.tlv.bbf.network_instance",
682
14
      FT_STRING, BASE_NONE, NULL, 0x0,
683
14
      NULL, HFILL }
684
14
    },
685
14
    { &hf_nsh_bbf_interface_id,
686
14
    { "Interface Identifier", "nsh.tlv.bbf.interface_id",
687
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
688
14
      NULL, HFILL }
689
14
    },
690
691
14
  };
692
693
694
14
  static int *ett[] = {
695
14
    &ett_nsh,
696
14
    &ett_nsh_tlv,
697
14
  };
698
699
14
  static ei_register_info ei[] = {
700
14
    { &ei_nsh_length_invalid, { "nsh.length.invalid", PI_PROTOCOL, PI_WARN, "Invalid total length", EXPFILL }},
701
14
    { &ei_nsh_tlv_incomplete_dissection, { "nsh.tlv.incomplete", PI_PROTOCOL, PI_WARN, "Incomplete TLV dissection", EXPFILL }},
702
14
  };
703
704
14
  proto_nsh = proto_register_protocol("Network Service Header", "NSH", "nsh");
705
14
  proto_register_field_array(proto_nsh, nsh_info, array_length(nsh_info));
706
14
  proto_register_subtree_array(ett, array_length(ett));
707
708
14
  expert_nsh = expert_register_protocol(proto_nsh);
709
14
  expert_register_field_array(expert_nsh, ei, array_length(ei));
710
711
14
  subdissector_table = register_dissector_table("nsh.next_proto", "NSH Next Protocol", proto_nsh, FT_UINT32, BASE_DEC);
712
14
  tlv_table = register_dissector_table("nsh.tlv", "NSH TLV", proto_nsh, FT_UINT24, BASE_HEX);
713
714
14
  register_tlv_dissectors();
715
716
14
  nsh_handle = register_dissector("nsh", dissect_nsh, proto_nsh);
717
14
}
718
719
void
720
proto_reg_handoff_nsh(void)
721
14
{
722
14
  dissector_add_uint("ethertype", ETHERTYPE_NSH, nsh_handle);
723
14
  dissector_add_uint("gre.proto", ETHERTYPE_NSH, nsh_handle);
724
14
  dissector_add_uint("vxlan.next_proto", VXLAN_NSH, nsh_handle);
725
14
  dissector_add_uint("nsh.next_proto", NSH_NSH, nsh_handle);
726
14
  dissector_add_uint("ip.proto", IP_PROTO_NSH, nsh_handle);
727
728
14
  heur_dissector_add("gtp.tpdu", dissect_nsh_heur, "NSH over GTP", "nsh_gtp.tpdu", proto_nsh, HEURISTIC_ENABLE);
729
14
}
730
731
/*
732
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
733
 *
734
 * Local variables:
735
 * c-basic-offset: 4
736
 * tab-width: 8
737
 * indent-tabs-mode: nil
738
 * End:
739
 *
740
 * vi: set shiftwidth=4 tabstop=8 expandtab:
741
 * :indentSize=4:tabSize=8:noTabs=true:
742
 */