<!--startmeta
custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/crates/netflow-plugin/integrations/decapsulation.md"
meta_yaml: "https://github.com/netdata/netdata/edit/master/src/crates/netflow-plugin/metadata.yaml"
sidebar_label: "Decapsulation"
learn_status: "Published"
learn_rel_path: "Network Performance Monitoring/Network Flows/Enrichment Methods"
keywords: ['decapsulation', 'srv6', 'vxlan', 'tunnel', 'overlay', 'inner packet', 'dataLinkFrameSection', 'layer2packetSectionData', 'ipfix ie 315', 'netflow v9 ie 104', 'sampled header']
message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE FLOWS' metadata.yaml FILE"
endmeta-->

<!-- markdownlint-disable-file -->

# Decapsulation


<img src="https://netdata.cloud/img/network-wired.svg" width="150"/>


Plugin: netflow-plugin
Module: decapsulation

<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />

## Overview

Enrich network flows with inner source and destination endpoints from VXLAN or
SRv6 encapsulated traffic. Decapsulation rewrites the 5-tuple of a flow record
from the **outer** (tunnel) endpoints to the **inner** (real) endpoints when the
exporter ships the encapsulated frame bytes alongside the standard fields. Without
it, every VM-to-VM conversation on a VXLAN fabric or every inner flow on an SRv6
transit shows up as the same tunnel pair (hypervisor-to-hypervisor or PE-to-PE),
which tells you nothing about the actual traffic.

Two encapsulations are supported, selected globally for the plugin. The mode set is
`none`, `srv6`, or `vxlan`; the default is `none`.

| Mode    | Strips                                           | Surfaces                                         |
|---------|--------------------------------------------------|--------------------------------------------------|
| `none`  | nothing                                          | the outer-header view (default)                  |
| `srv6`  | IPv6 outer + extension headers + SRH (type 4)    | the inner IPv4 (next-header 4) or IPv6 (41)      |
| `vxlan` | outer Eth/IP + UDP/4789 + 8-byte VXLAN header    | the inner Ethernet frame, then its L3/L4         |

The plugin only reaches the decap path when the flow record carries the inner
frame bytes in a Layer-2 packet section field. Three transport-level paths feed it:

- **NetFlow v9 IE 104** -- `Layer2packetSectionData` (RFC 5102 / RFC 7270).
- **IPFIX IE 315** -- `dataLinkFrameSection` (RFC 7133).
- **sFlow `SampledHeader`** -- always present in header-sampling mode.

When decap succeeds, the inner 5-tuple replaces the outer one in the resulting
journal record: `SRC_ADDR`, `DST_ADDR`, `SRC_PORT`, `DST_PORT`, `PROTOCOL`,
`ETYPE`, `IPTOS`, `IPTTL`, `IPV6_FLOW_LABEL`, `TCP_FLAGS`, `IP_FRAGMENT_ID`,
`IP_FRAGMENT_OFFSET`, ICMP type/code, MPLS labels (if present), and `BYTES`
(set to the inner L3 length so byte counts represent inner payload, not outer
overhead). For VXLAN, `SRC_MAC`, `DST_MAC`, `SRC_VLAN`, `DST_VLAN` come from the
inner Ethernet frame -- the outer MACs and VLANs are lost. The VXLAN VNI is
parsed but not exposed as a journal field; pure VNI-based segmentation is
not visible.

The `vxlan` parser matches **only UDP destination port 4789** (RFC 7348).
VXLAN-GPE on 4790 and any vendor-custom port are not recognised. The `srv6`
parser walks IPv6 extension headers and the Routing Header type 4 (SRH), then
surfaces the inner IPv4 or IPv6 packet pointed to by next-header 4 or 41.

For the cross-cutting concept (how decap composes with the rest of the enrichment
pipeline, the non-tunnel "drop, do not fall back" semantics, and per-source
dependence on the L2-section path), see
[Decapsulation](https://github.com/netdata/netdata/blob/master/docs/npm/network-flows/enrichment.md).


Set `protocols.decapsulation_mode` in `netflow.yaml` to `srv6` or `vxlan`. The
plugin then runs the inner-packet parser whenever a flow record carries an L2
frame section (NetFlow v9 IE 104 / IPFIX IE 315 / sFlow `SampledHeader`). Plain
NetFlow / IPFIX records that do **not** carry an L2 section pass through
unchanged regardless of the setting -- so enabling decap will not break a mixed
stream where only a subset of exporters ship the frame bytes. Enabling decap is
half the work; the exporter must also be configured to ship the inner frame.


This integration is supported on all platforms.

This integration runs as a single instance per Netdata Agent.


### Default Behavior

#### Auto-Detection

Disabled by default (`decapsulation_mode: none`). You must opt in by setting the mode explicitly.

#### Limits

One mode is active at a time -- the plugin cannot decap VXLAN and SRv6 simultaneously. If your fleet mixes both, choose the one your L2-section-bearing exporters carry exclusively.

#### Performance Impact

Decapsulation runs in the flow hot path for records carrying L2 frame sections. It adds protocol parsing work and drops L2-section records that do not match the configured tunnel mode.

## Setup


### Prerequisites

#### Confirm your exporter ships the L2 frame section

Decapsulation requires the exporter to include the inner frame bytes. Verify
before enabling the mode:

- **NetFlow v9** -- the template must contain field type 104
  (`Layer2packetSectionData`). Capture a packet with `tcpdump`, decode with
  Wireshark, and inspect the template.
- **IPFIX** -- the template must contain Information Element 315
  (`dataLinkFrameSection`, RFC 7133). Same verification path.
- **sFlow** -- header sampling is the default for sFlow agents and ships the
  truncated raw packet inside `SampledHeader`. No special configuration is
  required beyond enabling sFlow.

Section length matters. VXLAN over Ethernet over IPv4 fits in roughly 96-128
bytes of inner-frame capture; SRv6 with a Routing Header type 4 needs more
(256 bytes is a safe starting point). Truncated captures fail the inner
parser and the flow is dropped (see the failure modes on the concept page).


#### Configure your exporter to emit the L2 section

Vendor support varies. Recommended exporter paths are:

- **Juniper inline-monitoring (IPFIX 315)** on platforms supporting
  `services { inline-monitoring { ... } }` -- the template includes
  `datalink-frame-size` and a `maximum-clip-length` controls how much of the
  frame is captured. Reference recipe in the
  [Akvorado documentation](https://demo.akvorado.net/docs/operations#ipfix-315).
- **sFlow** with header sampling -- supported by Juniper QFX, Arista EOS,
  Mellanox/NVIDIA, MikroTik, and others. Header sampling is the default for
  most agents; verify the agent emits `SampledHeader` rather than only
  `SampledIPv4` / `SampledIPv6` records (the latter do not carry inner
  bytes).

Cisco IOS-XE and IOS-XR Flexible NetFlow support for Layer-2 frame
sections is platform-dependent. Before deploying Cisco decapsulation,
inspect the exported template and look for IE 104 (v9) or IE 315 (IPFIX).
Do not copy `collect datalink frame-section` snippets into production
unless the platform template confirms that the L2 section is exported.



### Configuration

#### Options

Decapsulation has a single configuration knob -- `protocols.decapsulation_mode`.


<details open><summary>Config options</summary>



| Option | Description | Default | Required |
|:-----|:------------|:--------|:---------:|
| protocols.decapsulation_mode | One of `none` (default), `srv6`, `vxlan`. The mode applies globally; the plugin cannot decode both VXLAN and SRv6 in the same instance. Setting this only affects records that travel through the L2-section path (NetFlow v9 IE 104 / IPFIX IE 315 / sFlow `SampledHeader`); regular flow records are unaffected. When the mode is set and the inner packet does not match the configured tunnel, the record is dropped -- there is no "fall back to outer view". | none | no |


</details>



#### via File

The configuration file name for this integration is `netflow.yaml`.


You can edit the configuration file using the [`edit-config`](https://github.com/netdata/netdata/blob/master/docs/netdata-agent/configuration/README.md#edit-configuration-files) script from the
Netdata [config directory](https://github.com/netdata/netdata/blob/master/docs/netdata-agent/configuration/README.md#locate-your-config-directory).

```bash
cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata
sudo ./edit-config netflow.yaml
```

##### Examples

###### VXLAN-based VTEP fleet (decode the inner tenant traffic)

Hypervisors emit sFlow with header sampling on the underlay. Every flow
between two VTEP loopbacks decodes to the inner VM-to-VM 5-tuple instead
of the underlay tunnel pair.


```yaml
protocols:
  decapsulation_mode: vxlan

```
###### SRv6 transit network (see the inner service traffic)

Provider-edge routers export IPFIX with IE 315 (`dataLinkFrameSection`)
via Juniper inline-monitoring. The plugin walks the IPv6 extension chain,
strips the SRH, and surfaces the inner IPv4 or IPv6 5-tuple.


<details open><summary>Config</summary>

```yaml
protocols:
  decapsulation_mode: srv6

```
</details>

###### Default (no decapsulation)

Outer-header view only. Tunnel endpoints appear as the source and
destination of every flow.


<details open><summary>Config</summary>

```yaml
protocols:
  decapsulation_mode: none

```
</details>



### Decap mode set but tunnels still show outer endpoints

The exporter is not shipping the L2 frame section. Plain NetFlow / IPFIX
flow records (no IE 104 / IE 315) take the regular path and are unaffected
by `decapsulation_mode`. Inspect the template -- look for field type 104
on NetFlow v9 or IE 315 on IPFIX. For sFlow, confirm the agent is sending
`SampledHeader` records rather than only `SampledIPv4` / `SampledIPv6`.


### Records disappear after enabling decap

When `decapsulation_mode` is set and a record arrives via the L2-section
path with a payload that does not match the configured tunnel, the record
is **dropped**. There is no fall back to the outer view. For sFlow with decap on, only `SampledHeader` records are processed;
`SampledIPv4`, `SampledIPv6`, `SampledEthernet`, `ExtendedSwitch`,
`ExtendedRouter`, `ExtendedGateway` records are skipped. If the same
exporter mixes tunnel and non-tunnel traffic on the L2-section path, you
will lose the non-tunnel records.


### VXLAN on a non-default UDP port goes undetected

The VXLAN parser matches only UDP destination port 4789. VXLAN-GPE on 4790 and any
vendor-custom port are not recognised and the record is dropped under
`decapsulation_mode: vxlan`.


### Frame section truncated, inner parsing fails

The exporter's clip / section size is shorter than the outer headers plus
the inner L3/L4 needed to populate the 5-tuple. Increase the section size
-- 128 bytes for VXLAN over IPv4, 256 bytes or more for SRv6 with extension
headers. On Juniper inline-monitoring, the knob is `maximum-clip-length`.


### VNI-based segmentation invisible

Bytes 4-6 of the VXLAN header (the VNI) are not exposed as journal
fields. If the inner Ethernet carries a VLAN tag, that VLAN reaches
`SRC_VLAN` / `DST_VLAN` and works for segmentation -- pure VNI does not.
No workaround inside the plugin; either VLAN-tag the inner traffic or
filter at query time using the tunnel-endpoint pair before decap.


### One mode at a time

The plugin cannot decode VXLAN and SRv6 in the same instance. If exporter A
ships VXLAN tenant traffic and exporter B ships SRv6 transit traffic, you
must choose the mode that matches the traffic this Netdata Agent receives.
