30
overview:
31
data_collection:
32
metrics_description: |
33
- Collects NetFlow v5, v7, and v9 records from one or more exporters (routers, switches, firewalls)
34
- and stores them in tiered journal files. Each record exposes source and destination IP, ports,
35
- protocol, bytes, packets, ToS, TCP flags, and ingress/egress interface indices.
33
+ Collect network flow records from NetFlow v5, v7, and v9 exporters such as
34
+ routers, switches, and firewalls. Each record exposes source and destination IP,
35
+ ports, protocol, bytes, packets, ToS, TCP flags, and ingress/egress interface indices.
36
Enrichment adds GeoIP country/city/ASN, static metadata, and classifier tags.
37
38
For full documentation including vendor configuration examples, sampling caveats, template
39
- handling and verification steps, see [NetFlow](https://learn.netdata.cloud/docs/network-flows/sources/netflow)
40
- and the [Network Flows Overview](https://learn.netdata.cloud/docs/network-flows/).
39
+ handling and verification steps, see the [Network Flows Overview](https://learn.netdata.cloud/docs/network-flows/).
40
method_description: |
41
The plugin listens on a configurable UDP socket for NetFlow datagrams.
42
NetFlow v5 and v7 records are decoded directly. NetFlow v9 records are decoded using
53
auto_detection:
54
description: "The plugin starts when enabled in netflow.yaml and listens on the configured UDP port."
55
limits:
57
- description: ""
56
+ description: "Operational limits are driven by sustained flows/s, cardinality, retention, storage speed, and enrichment. Plan around 25k sustained flows/s per well-provisioned agent for the full raw + rollup pipeline; use distributed agents for larger deployments."
57
performance_impact:
59
- description: ""
58
+ description: "Disabled until exporters send traffic. Once active, CPU and disk I/O scale with flow rate and cardinality; size retention and storage from observed flows/s."
59
setup:
60
prerequisites:
61
list:
93
description: Directory for journal files (relative to NETDATA_CACHE_DIR).
94
default_value: flows
95
required: false
97
- - name: journal.size_of_journal_files
98
- description: Maximum total size of all journal files.
96
+ - name: journal.tiers.<tier>.size_of_journal_files
97
+ description: Per-tier hard size cap. Replace `<tier>` with `raw`, `minute_1`, `minute_5`, or `hour_1`. Set to `null` for time-only retention.
98
default_value: "10GB"
99
required: false
101
- - name: journal.duration_of_journal_files
102
- description: Maximum age of journal files.
100
+ - name: journal.tiers.<tier>.duration_of_journal_files
101
+ description: Per-tier maximum age. Replace `<tier>` with `raw`, `minute_1`, `minute_5`, or `hour_1`. Set to `null` for size-only retention.
102
default_value: "7d"
103
required: false
104
examples:
109
- name: Basic NetFlow v5/v9 collection
110
folding:
111
enabled: false
113
- description: Listen on the standard NetFlow port for v5 and v9 records.
112
+ description: Listen on Netdata's default flow listener port for v5 and v9 records.
113
config: |
114
enabled: true
115
listener:
120
- name: NetFlow v9 only with extended retention
121
folding:
122
enabled: true
124
- description: Accept only v9 records and keep 30 days of journal data.
123
+ description: Accept only v9 records, keep one day of raw data, and keep longer rollups.
124
config: |
125
enabled: true
126
listener:
131
v9: true
132
journal:
133
journal_dir: flows
135
- size_of_journal_files: 50GB
136
- duration_of_journal_files: 30d
134
+ tiers:
135
+ raw: { size_of_journal_files: 50GB, duration_of_journal_files: 24h }
136
+ minute_1: { size_of_journal_files: 10GB, duration_of_journal_files: 14d }
137
+ minute_5: { size_of_journal_files: 10GB, duration_of_journal_files: 30d }
138
+ hour_1: { size_of_journal_files: 10GB, duration_of_journal_files: 365d }
139
troubleshooting:
140
problems:
141
list:
153
enabled: false
154
description: |
155
Network flow data is stored as journal records, not as traditional metrics.
154
- Use the "Network Flows" tab in the Netdata dashboard to query and visualize flow data.
156
+ Use the Network Flows view in the Netdata dashboard to query and visualize flow data.
157
For the full list of fields and the per-protocol availability matrix, see the
158
[Field Reference](https://learn.netdata.cloud/docs/network-flows/field-reference).
159
For visualisation guidance see [Sankey and Table](https://learn.netdata.cloud/docs/network-flows/visualization/summary-sankey),
190
overview:
191
data_collection:
192
metrics_description: |
191
- Collects IPFIX (NetFlow v10) records from one or more exporters and stores them in tiered
192
- journal files. IPFIX extends NetFlow v9 with variable-length fields, vendor-specific
193
- information elements, and template withdrawal. Each record exposes the same core fields
194
- as NetFlow plus any additional IEs the exporter provides.
193
+ Collect network flow records from IPFIX (NetFlow v10) exporters. IPFIX extends
194
+ NetFlow v9 with variable-length fields, vendor-specific information elements,
195
+ and template withdrawal. Each record exposes the same core fields as NetFlow plus
196
+ any additional IEs the exporter provides.
197
198
For full documentation including vendor configuration examples (Cisco, Juniper, Arista,
197
- ASA NSEL), biflow handling, sampling caveats, and verification steps, see
198
- [IPFIX](https://learn.netdata.cloud/docs/network-flows/sources/ipfix) and the
199
+ ASA NSEL), biflow handling, sampling caveats, and verification steps, see the
200
[Network Flows Overview](https://learn.netdata.cloud/docs/network-flows/).
201
method_description: |
202
The plugin listens on the same UDP socket as NetFlow. IPFIX messages are identified by
213
auto_detection:
214
description: "The plugin starts when enabled in netflow.yaml and listens on the configured UDP port."
215
limits:
215
- description: ""
216
+ description: "Operational limits are driven by sustained flows/s, template churn, cardinality, retention, storage speed, and enrichment. Plan around 25k sustained flows/s per well-provisioned agent for the full raw + rollup pipeline; use distributed agents for larger deployments."
217
performance_impact:
217
- description: ""
218
+ description: "Disabled until exporters send traffic. Once active, CPU and disk I/O scale with flow rate, template volume, and cardinality; size retention and storage from observed flows/s."
219
setup:
220
prerequisites:
221
list:
246
description: Directory for journal files (relative to NETDATA_CACHE_DIR).
247
default_value: flows
248
required: false
248
- - name: journal.size_of_journal_files
249
- description: Maximum total size of all journal files.
249
+ - name: journal.tiers.<tier>.size_of_journal_files
250
+ description: Per-tier hard size cap. Replace `<tier>` with `raw`, `minute_1`, `minute_5`, or `hour_1`. Set to `null` for time-only retention.
251
default_value: "10GB"
252
required: false
252
- - name: journal.duration_of_journal_files
253
- description: Maximum age of journal files.
253
+ - name: journal.tiers.<tier>.duration_of_journal_files
254
+ description: Per-tier maximum age. Replace `<tier>` with `raw`, `minute_1`, `minute_5`, or `hour_1`. Set to `null` for size-only retention.
255
default_value: "7d"
256
required: false
257
examples:
262
- name: IPFIX collection
263
folding:
264
enabled: false
264
- description: Listen for IPFIX records on the standard port.
265
+ description: Listen for IPFIX records on Netdata's default flow listener port.
266
config: |
267
enabled: true
268
listener:
290
enabled: false
291
description: |
292
Network flow data is stored as journal records, not as traditional metrics.
292
- Use the "Network Flows" tab in the Netdata dashboard to query and visualize flow data.
293
+ Use the Network Flows view in the Netdata dashboard to query and visualize flow data.
294
For the full list of fields and the per-protocol availability matrix, see the
295
[Field Reference](https://learn.netdata.cloud/docs/network-flows/field-reference).
296
IPFIX biflow records are emitted as two separate flow records (forward + reverse).
326
overview:
327
data_collection:
328
metrics_description: |
328
- Collects sFlow v5 datagrams from one or more agents and stores them in tiered journal files.
329
- sFlow provides statistically sampled packet headers, interface counters, or extended
330
- gateway data. Each flow record exposes source and destination IP, ports, protocol, bytes,
331
- packets, and sampling rate information.
329
+ Collect sampled network flow records from sFlow v5 agents. sFlow provides
330
+ statistically sampled packet headers, interface counters, or extended gateway data.
331
+ Each flow record exposes source and destination IP, ports, protocol, bytes, packets,
332
+ and sampling rate information.
333
334
For full documentation including how sFlow differs fundamentally from NetFlow (packet
335
sampling vs aggregated flows), vendor configuration examples (Arista, Juniper, Aruba CX,
335
- Ruckus, hsflowd), and the limits of sampled data, see
336
- [sFlow](https://learn.netdata.cloud/docs/network-flows/sources/sflow) and the
336
+ Ruckus, hsflowd), and the limits of sampled data, see the
337
[Network Flows Overview](https://learn.netdata.cloud/docs/network-flows/).
338
method_description: |
339
The plugin listens on the same UDP socket as NetFlow. sFlow datagrams are identified by
350
auto_detection:
351
description: "The plugin starts when enabled in netflow.yaml and listens on the configured UDP port."
352
limits:
353
- description: ""
353
+ description: "Operational limits are driven by sustained samples/s, sampling rate, cardinality, retention, storage speed, and enrichment. Plan capacity from the received sample rate and the expanded byte/packet estimates."
354
performance_impact:
355
- description: ""
355
+ description: "Disabled until sFlow agents send traffic. Once active, CPU and disk I/O scale with received samples/s and cardinality; size retention and storage from observed flow records/s."
356
setup:
357
prerequisites:
358
list:
383
description: Directory for journal files (relative to NETDATA_CACHE_DIR).
384
default_value: flows
385
required: false
386
- - name: journal.size_of_journal_files
387
- description: Maximum total size of all journal files.
386
+ - name: journal.tiers.<tier>.size_of_journal_files
387
+ description: Per-tier hard size cap. Replace `<tier>` with `raw`, `minute_1`, `minute_5`, or `hour_1`. Set to `null` for time-only retention.
388
default_value: "10GB"
389
required: false
390
- - name: journal.duration_of_journal_files
391
- description: Maximum age of journal files.
390
+ - name: journal.tiers.<tier>.duration_of_journal_files
391
+ description: Per-tier maximum age. Replace `<tier>` with `raw`, `minute_1`, `minute_5`, or `hour_1`. Set to `null` for size-only retention.
392
default_value: "7d"
393
required: false
394
examples:
399
- name: sFlow collection
400
folding:
401
enabled: false
402
- description: Listen for sFlow v5 datagrams on the standard port.
402
+ description: Listen for sFlow v5 datagrams on Netdata's default flow listener port.
403
config: |
404
enabled: true
405
listener:
429
enabled: false
430
description: |
431
Network flow data is stored as journal records, not as traditional metrics.
432
- Use the "Network Flows" tab in the Netdata dashboard to query and visualize flow data.
432
+ Use the Network Flows view in the Netdata dashboard to query and visualize flow data.
433
For the full list of fields and the per-protocol availability matrix, see the
434
[Field Reference](https://learn.netdata.cloud/docs/network-flows/field-reference).
435
sFlow byte counts are statistical estimates (sampled packets multiplied by sampling rate);
448
name: DB-IP IP Intelligence
449
link: https://db-ip.com/
450
categories:
451
- - flows.ip-intelligence
451
+ - flows.enrichment-methods
452
icon_filename: network-wired.svg
453
keywords:
454
- geoip
472
overview:
473
data_collection:
474
metrics_description: |
475
- DB-IP is the **default** IP intelligence source for the Netdata netflow plugin. Its
476
- MMDB-format databases are bundled with native packages (DEB, RPM) under
477
- `/usr/share/netdata/topology-ip-intel/`. Refreshing pulls newer data from
478
- `download.db-ip.com` via the bundled `topology-ip-intel-downloader`.
479
-
480
- Populates `SRC_COUNTRY`, `DST_COUNTRY`, `SRC_GEO_STATE`, `DST_GEO_STATE`,
481
- `SRC_GEO_CITY`, `DST_GEO_CITY`, `SRC_GEO_LATITUDE`, `DST_GEO_LATITUDE`,
482
- `SRC_GEO_LONGITUDE`, `DST_GEO_LONGITUDE`, plus the AS-number and AS-name fields
483
- when included in the resolution chain.
484
-
485
- For the full IP-intelligence concept (MMDB format, lookup priority, internal-IP
486
- handling, hot reload semantics), see
487
- [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment/ip-intelligence).
475
+ Enrich network flows with ASN and geographic context from DB-IP Lite MMDB
476
+ databases. DB-IP IP Intelligence is the default IP intelligence source for the
477
+ Netdata netflow plugin: when neither `enrichment.geoip.asn_database` nor
478
+ `enrichment.geoip.geo_database` is configured, the plugin auto-detects the
479
+ DB-IP-built MMDB files at startup and uses them. Two MMDB files are involved:
480
+ an ASN database (`topology-ip-asn.mmdb`) and a geographic database
481
+ (`topology-ip-geo.mmdb`). Native packages (DEB, RPM) ship a stock copy under
482
+ `/usr/share/netdata/topology-ip-intel/`; the bundled refresh tool fetches updates
483
+ into `/var/cache/netdata/topology-ip-intel/`.
484
+
485
+ DB-IP publishes the Lite databases monthly under a Creative Commons Attribution 4.0
486
+ International licence (https://db-ip.com/db/lite.php). The MMDB format is the MaxMind
487
+ binary database; lookups are in-process with no per-flow network call.
488
+
489
+ Populates these flow record fields when a lookup succeeds:
490
+
491
+ - From the **geo MMDB**: `SRC_COUNTRY`, `DST_COUNTRY`, `SRC_GEO_STATE`, `DST_GEO_STATE`,
492
+ `SRC_GEO_CITY`, `DST_GEO_CITY`, `SRC_GEO_LATITUDE`, `DST_GEO_LATITUDE`,
493
+ `SRC_GEO_LONGITUDE`, `DST_GEO_LONGITUDE`. Country and state survive into all four
494
+ journal tiers; city, latitude, and longitude are kept only in the raw tier so the
495
+ rollups stay cardinality-bounded.
496
+ - From the **ASN MMDB**: `SRC_AS_NAME`, `DST_AS_NAME`. The DB-IP-built ASN database also
497
+ tags address ranges as private/reserved (RFC 1918, link-local, RFC 6598, etc.); when
498
+ the resolved AS number is `0` and that flag is set, the plugin renders the AS name as
499
+ `AS0 Private IP Address Space` instead of `AS0 Unknown ASN`. The AS *number* itself
500
+ comes from the wider asn_providers chain, not directly from the MMDB.
501
+
502
+ For the cross-provider mechanics (lookup pass ordering, the 30-second hot-reload poll,
503
+ the auto-detect path order, multi-database composition, IPv4/IPv6 handling, the failure
504
+ modes shared by every MMDB provider), see
505
+ [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment).
506
method_description: |
489
- Files are read on plugin start and reloaded automatically every 30 seconds when
490
- their mtime or size changes. Lookups happen in-process; there is no per-flow network
491
- call. Auto-detection scans `${NETDATA_CACHE_DIR}/topology-ip-intel/` first, falling
492
- back to the stock copy under `${NETDATA_STOCK_DATA_DIR}/topology-ip-intel/`.
507
+ Files are read on plugin start and reloaded automatically when their mtime or size
508
+ changes. Auto-detection scans `${NETDATA_CACHE_DIR}/topology-ip-intel/` first
509
+ (typically `/var/cache/netdata/topology-ip-intel/`), falling back to the stock copy
510
+ under `${NETDATA_STOCK_DATA_DIR}/topology-ip-intel/` (typically
511
+ `/usr/share/netdata/topology-ip-intel/`). When databases are auto-detected they are
512
+ treated as optional, so a missing or unreadable file does not abort plugin startup.
513
supported_platforms:
514
include:
515
- Linux
521
auto_detection:
522
description: "Native packages ship the stock DB-IP MMDB files; the plugin auto-detects them at startup. No configuration required for the default install."
523
limits:
504
- description: ""
524
+ description: "Lookup coverage and freshness depend on the DB-IP Lite files installed on disk. Native packages provide a stock copy; schedule the downloader if you need monthly refreshes."
525
performance_impact:
506
- description: ""
526
+ description: "Lookups are local MMDB reads with no per-flow network call. Memory use is mostly the mapped database files and the kernel page cache needed to keep active pages hot."
527
setup:
528
prerequisites:
529
list:
530
- title: DB-IP MMDB files
531
description: |
512
- Ships with native packages. For source builds, run the bundled downloader once
513
- to populate `/var/cache/netdata/topology-ip-intel/`:
532
+ Native DEB / RPM packages ship the stock DB-IP MMDB files under
533
+ `/usr/share/netdata/topology-ip-intel/`. For source builds, or to get a fresher copy
534
+ than the one bundled with the package, run `topology-ip-intel-downloader` once when
535
+ the binary is available (packaged 32-bit installs do not include it) to populate
536
+ `/var/cache/netdata/topology-ip-intel/`:
537
538
```bash
539
sudo /usr/sbin/topology-ip-intel-downloader
540
```
541
519
- Subsequent refreshes (e.g., monthly cron) re-fetch from db-ip.com.
542
+ See the [Enrichment Intel Downloader](https://learn.netdata.cloud/docs/network-flows/intel-downloader)
543
+ page for downloader options and how to schedule periodic refreshes. DB-IP Lite
544
+ data is published monthly, so a monthly cron of the downloader is the right
545
+ cadence -- more frequent runs will not produce newer data.
546
+ - title: Licence acknowledgement
547
+ description: |
548
+ DB-IP Lite databases are distributed under the Creative Commons Attribution 4.0
549
+ International licence (https://db-ip.com/db/lite.php). Attribution is required
550
+ when redistributing the data or derivative dashboards.
551
configuration:
552
file:
553
name: netflow.yaml
601
troubleshooting:
602
problems:
603
list:
573
- - name: Internal IPs appearing in random countries
604
+ - name: Private IPs have empty GeoIP fields
605
description: |
575
- GeoIP databases have no entry for RFC 1918 / private space. The stock DB-IP
576
- build tags private ranges so `*_AS_NAME` renders as "AS0 Private IP Address Space"
577
- with empty country. With third-party MMDBs, results may vary. Declare your
578
- internal CIDRs under `enrichment.networks` to override -- see
579
- [Static metadata](https://learn.netdata.cloud/docs/network-flows/enrichment/static-metadata).
606
+ GeoIP databases normally have no country, city, or coordinate entry for RFC 1918 /
607
+ private space. The DB-IP-built ASN database tags private ranges so `*_AS_NAME`
608
+ renders as `AS0 Private IP Address Space`, while geographic fields stay empty and
609
+ private addresses do not appear on maps. Declare your internal CIDRs under
610
+ `enrichment.networks` when you want internal labels -- see
611
+ [Static metadata](https://learn.netdata.cloud/docs/network-flows/enrichment).
612
- name: Stale databases
613
description: |
582
- The plugin does not alert on staleness. Check file mtime: `ls -la /var/cache/netdata/topology-ip-intel/`.
583
- Schedule a weekly cron of `topology-ip-intel-downloader` to keep data fresh.
614
+ The plugin does not alert on staleness. Check file mtime:
615
+ `ls -la /var/cache/netdata/topology-ip-intel/`. DB-IP Lite is published monthly,
616
+ so a monthly cron of `/usr/sbin/topology-ip-intel-downloader` keeps you on the
617
+ upstream cadence when the downloader is installed; running it more often will not
618
+ produce fresher data.
619
+ - name: Map renders empty over a long time window
620
+ description: |
621
+ `SRC_GEO_CITY`, `DST_GEO_CITY`, `SRC_GEO_LATITUDE`, `DST_GEO_LATITUDE`,
622
+ `SRC_GEO_LONGITUDE`, and `DST_GEO_LONGITUDE` are stored only in the raw journal
623
+ tier; the 1-minute, 5-minute, and 1-hour rollups drop them to keep cardinality
624
+ bounded. A query that auto-falls back to a rollup tier therefore renders an empty
625
+ city map. Narrow the time range so the query fits the raw tier, or use the
626
+ country / state map (those survive into rollups).
627
alerts: []
628
metrics:
629
folding:
632
description: |
633
IP intelligence enriches existing flow records; it does not produce metrics of its own.
634
Verify enrichment is working by querying `SRC_COUNTRY` / `DST_COUNTRY` on the
592
- Network Flows tab and confirming non-empty values for public IPs.
635
+ Network Flows view and confirming non-empty values for public IPs.
636
availability: []
637
scopes: []
595
-
638
- meta:
639
plugin_name: netflow-plugin
640
module_name: maxmind
642
name: MaxMind GeoIP / GeoLite2
643
link: https://www.maxmind.com/
644
categories:
603
- - flows.ip-intelligence
645
+ - flows.enrichment-methods
646
icon_filename: network-wired.svg
647
keywords:
648
- maxmind
652
- asn
653
- mmdb
654
- ip intelligence
655
+ - flow enrichment
656
related_resources:
657
integrations:
658
list:
667
overview:
668
data_collection:
669
metrics_description: |
627
- MaxMind GeoIP2 (commercial) and GeoLite2 (free tier with license key) MMDB databases
628
- are read directly by the netflow plugin. The plugin uses any MMDB-format file that
629
- exposes the standard schema -- it is not tied to MaxMind specifically, but MaxMind
630
- is the canonical source and the format originator.
670
+ Enrich network flows with ASN and geographic context from MaxMind GeoIP /
671
+ GeoLite2 MMDB databases. MaxMind is the originator of the MMDB binary format and
672
+ the canonical commercial source for geo and ASN data. The netflow plugin reads
673
+ MaxMind MMDB files directly; they are interchangeable with other MMDB providers
674
+ (DB-IP, custom builds).
675
632
- Populates the same `SRC_COUNTRY`, `*_GEO_*`, and AS-name fields as DB-IP. Use this
633
- integration when you have a MaxMind license and prefer their data over the bundled
634
- DB-IP defaults.
676
+ Two product lines are supported:
677
636
- For the full IP-intelligence concept, see
637
- [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment/ip-intelligence).
678
+ - **GeoLite2** (free): requires a free MaxMind account and a license key; users
679
+ must accept the GeoLite2 EULA, which includes an attribution requirement. See
680
+ <https://dev.maxmind.com/geoip/geolite2-free-geolocation-data>.
681
+ - **GeoIP2** (commercial): paid subscription with the same license-key download
682
+ mechanism but higher accuracy and more frequent updates. See
683
+ <https://www.maxmind.com/en/geoip2-databases>.
684
+
685
+ Each lookup populates the same flow-record fields as DB-IP: `SRC_COUNTRY`,
686
+ `DST_COUNTRY`, `SRC_GEO_STATE`, `DST_GEO_STATE`, `SRC_GEO_CITY`, `DST_GEO_CITY`,
687
+ `SRC_GEO_LATITUDE`, `DST_GEO_LATITUDE`, `SRC_GEO_LONGITUDE`, `DST_GEO_LONGITUDE`,
688
+ `SRC_AS_NAME`, and `DST_AS_NAME`. Country and state survive into all rollup tiers;
689
+ city and lat/lon are **raw-tier-only**. Rollup tiers keep only the
690
+ bounded-cardinality geography columns.
691
+
692
+ For the cross-cutting concept (resolver poll loop, multi-database composition,
693
+ ASN provider chain, failure-modes table), see
694
+ [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment).
695
method_description: |
639
- You download the MaxMind MMDB files yourself (via `geoipupdate` or manual download),
640
- then point the plugin at their paths in `netflow.yaml`. The plugin reloads on file
641
- change every 30 seconds.
696
+ You download the MaxMind MMDB files yourself using `geoipupdate` (MaxMind's
697
+ official downloader, configured with your account ID + license key) or via direct
698
+ HTTPS download with the same credentials. MaxMind requires authentication for all
699
+ downloads -- there is no anonymous access. The bundled
700
+ `topology-ip-intel-downloader` shipped by Netdata does **not** know how to fetch
701
+ MaxMind databases (it supports DB-IP and IPtoASN only); use `geoipupdate` and
702
+ schedule it via cron or systemd-timer.
703
+
704
+ Once the files are on disk, point `asn_database` and `geo_database` at their
705
+ paths in `netflow.yaml`. The plugin reloads on file change automatically -- a
706
+ successful `geoipupdate` run causes the plugin to swap readers within ~30s, no
707
+ restart needed.
708
supported_platforms:
709
include:
710
- Linux
714
description: ""
715
default_behavior:
716
auto_detection:
651
- description: "Not auto-detected. You must configure the database paths explicitly."
717
+ description: "Not auto-detected. The plugin auto-detects the bundled DB-IP files; to use MaxMind you must configure the database paths explicitly. Set `enrichment.geoip.asn_database` and `enrichment.geoip.geo_database` to the MaxMind file paths."
718
limits:
653
- description: ""
719
+ description: "Lookup coverage, fields, license terms, and refresh cadence depend on the MaxMind database edition you configure. Netdata does not fetch MaxMind databases automatically."
720
performance_impact:
655
- description: ""
721
+ description: "Lookups are local MMDB reads with no per-flow network call. Memory use is mostly the mapped database files and the kernel page cache needed to keep active pages hot."
722
setup:
723
prerequisites:
724
list:
659
- - title: MaxMind license + downloaded MMDBs
725
+ - title: MaxMind account and license key
726
+ description: |
727
+ MaxMind does not allow anonymous downloads. Required for both GeoLite2 (free)
728
+ and GeoIP2 (paid):
729
+
730
+ 1. Sign up at <https://www.maxmind.com/en/geolite2/signup> (GeoLite2) or
731
+ purchase a GeoIP2 subscription.
732
+ 2. Generate a license key under "Account > Manage License Keys".
733
+ 3. Note your account ID (visible on the same account page).
734
+ - title: Install and configure geoipupdate
735
+ description: |
736
+ `geoipupdate` is MaxMind's official downloader. Install it from your distro
737
+ (`apt install geoipupdate`, `dnf install geoipupdate`) or download from
738
+ <https://github.com/maxmind/geoipupdate/releases>.
739
+
740
+ Edit `/etc/GeoIP.conf`:
741
+
742
+ ```ini
743
+ AccountID YOUR_ACCOUNT_ID
744
+ LicenseKey YOUR_LICENSE_KEY
745
+ # GeoLite2 (free):
746
+ EditionIDs GeoLite2-City GeoLite2-ASN
747
+ # ...or for GeoIP2 (paid):
748
+ # EditionIDs GeoIP2-City GeoIP2-ISP
749
+ DatabaseDirectory /usr/share/GeoIP
750
+ ```
751
+
752
+ Run `sudo geoipupdate` to fetch initial files, then schedule it via cron or
753
+ the bundled `geoipupdate.timer` systemd unit. Recommended cadences match the
754
+ upstream publish frequency:
755
+
756
+ - **GeoLite2 City / Country**: published twice weekly (Tuesday and Friday).
757
+ - **GeoLite2 ASN**: published every weekday (Mon-Fri).
758
+ - **GeoIP2 commercial editions**: published "every weekday, Monday through
759
+ Friday" per <https://www.maxmind.com/en/geoip2-databases>.
760
+
761
+ Source: <https://support.maxmind.com/hc/en-us/articles/4408216129947>.
762
+ - title: Single MMDB per database type (dual-stack)
763
description: |
661
- For GeoLite2 (free): create a MaxMind account, generate a license key, install
662
- `geoipupdate`, and configure it to fetch `GeoLite2-City.mmdb` and
663
- `GeoLite2-ASN.mmdb`. For GeoIP2 (paid): obtain a subscription and use the same
664
- `geoipupdate` mechanism with your paid license key.
764
+ A single MaxMind MMDB file covers both IPv4 and IPv6 in one binary tree --
765
+ you do **not** need separate IPv4 and IPv6 files. Point `asn_database` at one
766
+ file and `geo_database` at one file. (The CSV exports MaxMind also publishes
767
+ are split per family, but the netflow plugin only reads the binary MMDB
768
+ format.)
769
configuration:
770
file:
771
name: netflow.yaml
772
options:
773
description: |
670
- Override the default DB-IP auto-detection by pointing `asn_database` and `geo_database`
671
- at your MaxMind MMDB files.
774
+ Override the default DB-IP auto-detection by pointing `asn_database` and
775
+ `geo_database` at your MaxMind MMDB files. Both keys take a list -- you can
776
+ chain MaxMind alongside other MMDB sources; see the
777
+ [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment)
778
+ page for the per-field "last non-empty wins" composition rule.
779
folding:
780
title: Config options
781
enabled: true
782
list:
783
- name: enrichment.geoip.asn_database
677
- description: Paths to MaxMind ASN MMDB files (typically GeoLite2-ASN.mmdb or GeoIP2-ISP.mmdb).
784
+ description: Paths to MaxMind ASN MMDB files (typically `GeoLite2-ASN.mmdb` for the free tier or `GeoIP2-ISP.mmdb` for the paid tier; the dual-stack file covers IPv4 and IPv6).
785
default_value: "[]"
786
required: true
787
- name: enrichment.geoip.geo_database
681
- description: Paths to MaxMind geographic MMDB files (typically GeoLite2-City.mmdb or GeoIP2-City.mmdb).
788
+ description: Paths to MaxMind geographic MMDB files (typically `GeoLite2-City.mmdb` for the free tier or `GeoIP2-City.mmdb` for the paid tier; the dual-stack file covers IPv4 and IPv6).
789
default_value: "[]"
790
required: true
791
- name: enrichment.geoip.optional
685
- description: When true, missing or unreadable MMDBs are warnings, not fatal at startup.
792
+ description: When true, missing or unreadable MMDBs are warnings, not fatal at startup. Useful while `geoipupdate` is being set up for the first time.
793
default_value: "false"
794
required: false
795
examples:
800
- name: GeoLite2 (free tier)
801
folding:
802
enabled: false
696
- description: Standard `geoipupdate` install path. Free tier requires a license key.
803
+ description: Standard `geoipupdate` install path. Free tier requires a MaxMind account and license key; usage is subject to the GeoLite2 EULA (attribution required).
804
config: |
805
enrichment:
806
geoip:
812
- name: GeoIP2 (paid)
813
folding:
814
enabled: true
708
- description: Commercial subscription. Higher accuracy, more frequent updates.
815
+ description: Commercial subscription. Higher accuracy than GeoLite2 and a weekday update cadence on most editions.
816
config: |
817
enrichment:
818
geoip:
821
geo_database:
822
- /usr/share/GeoIP/GeoIP2-City.mmdb
823
optional: false
824
+ - name: MaxMind ASN + DB-IP geo (mixed)
825
+ folding:
826
+ enabled: true
827
+ description: Use MaxMind for ASN richness and keep the bundled DB-IP geo file. Both lookups run; the multi-DB composition rule is documented on the [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment) page.
828
+ config: |
829
+ enrichment:
830
+ geoip:
831
+ asn_database:
832
+ - /usr/share/GeoIP/GeoLite2-ASN.mmdb
833
+ geo_database:
834
+ - /var/cache/netdata/topology-ip-intel/topology-ip-geo.mmdb
835
+ optional: false
836
troubleshooting:
837
problems:
838
list:
839
- name: License key missing or expired
840
description: |
722
- `geoipupdate` fails silently and the MMDB files become stale. Set up a working
723
- `geoipupdate` cron and monitor its exit code.
841
+ `geoipupdate` fails (often silently from the plugin's perspective) and the
842
+ MMDB files become stale. Check the `geoipupdate` exit status and its log;
843
+ regenerate the key under "Account > Manage License Keys" if needed and
844
+ update `/etc/GeoIP.conf`.
845
+ - name: GeoLite2 attribution requirement
846
+ description: |
847
+ The GeoLite2 EULA requires attribution to MaxMind. If you redistribute
848
+ dashboards or screenshots that include GeoLite2-derived data, follow the
849
+ upstream guidance at <https://dev.maxmind.com/geoip/geolite2-free-geolocation-data>.
850
+ GeoIP2 (commercial) does not have the same attribution requirement.
851
- name: Schema differences between GeoLite2 and GeoIP2
852
description: |
726
- Both share the standard MMDB structure but the `Anonymous IP`, `ISP`, and
727
- `Connection Type` databases have GeoIP2-only fields the plugin does not read.
728
- Use `City` for geographic enrichment and `ASN` (GeoLite2) or `ISP` (GeoIP2)
729
- for AS data.
853
+ Both share the standard MMDB structure for the fields the plugin reads
854
+ (country, subdivisions, city, location, autonomous_system_number,
855
+ autonomous_system_organization). MaxMind's specialty databases (Anonymous IP,
856
+ Connection Type, Domain) carry GeoIP2-only fields the plugin does not consume.
857
+ Use `City` for geographic enrichment and `ASN` (GeoLite2) or `ISP` (GeoIP2) for
858
+ AS data.
859
+ - name: Mixing MaxMind with the bundled DB-IP files
860
+ description: |
861
+ The plugin loads every configured MMDB. If you list both, the per-field
862
+ "last non-empty wins" rule applies (see the
863
+ [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment)
864
+ concept page). Order matters: list the source whose values you want to win
865
+ **last**.
866
alerts: []
867
metrics:
868
folding:
869
title: Metrics
870
enabled: false
871
description: |
736
- Enriches flow records; produces no metrics of its own. Verify on the Network Flows
737
- tab via `SRC_COUNTRY`, `DST_COUNTRY`, and `*_AS_NAME` columns.
872
+ IP intelligence enriches existing flow records; it produces no metrics of its own.
873
+ Verify enrichment is working by querying `SRC_COUNTRY` / `DST_COUNTRY` and
874
+ `SRC_AS_NAME` / `DST_AS_NAME` on the Network Flows view and confirming non-empty
875
+ values for public IPs.
876
availability: []
877
scopes: []
740
-
878
- meta:
879
plugin_name: netflow-plugin
880
module_name: iptoasn
882
name: IPtoASN
883
link: https://iptoasn.com/
884
categories:
748
- - flows.ip-intelligence
885
+ - flows.enrichment-methods
886
icon_filename: network-wired.svg
887
keywords:
888
- iptoasn
889
- asn
890
- bgp
891
- public asn
892
+ - public domain
893
+ - pddl
894
- ip intelligence
895
related_resources:
896
integrations:
906
overview:
907
data_collection:
908
metrics_description: |
770
- [IPtoASN](https://iptoasn.com/) is a free public IP-to-ASN database derived from
771
- BGP RIB snapshots. Daily updates, no license required. Use it as a free, open
772
- alternative to MaxMind ASN data when license cost or terms matter.
909
+ Enrich network flows with public ASN and country context from IPtoASN
910
+ BGP-derived datasets. [IPtoASN](https://iptoasn.com/) is a free, public-domain
911
+ feed of IP-to-ASN mappings. The upstream publishes its dataset
912
+ under the [Public Domain Dedication and License (PDDL)](https://opendatacommons.org/licenses/pddl/)
913
+ (see [iptoasn.com](https://iptoasn.com/) -- "Frequently updated, public domain")
914
+ and rebuilds it hourly, making it the highest-cadence and lowest-friction public
915
+ ASN source available. Use it as a free, open alternative to MaxMind ASN data when
916
+ license cost or terms matter.
917
774
- IPtoASN provides ASN data only -- no geographic data. Pair with DB-IP, MaxMind,
775
- or another geo source for country/city enrichment.
918
+ IPtoASN's `ip2asn-combined` artifact contains five tab-separated columns:
919
+ `range_start`, `range_end`, `AS_number`, `country_code`, and `AS_description`
920
+ (see [iptoasn.com](https://iptoasn.com/) for the format reference). So
921
+ although IPtoASN is often described as "ASN-only", the feed also carries an
922
+ ISO 3166 country code per range and the Netdata downloader exposes both as
923
+ ASN + geo MMDBs. Pair with DB-IP or MaxMind when you also need state, city,
924
+ or coordinates.
925
777
- For the full IP-intelligence concept, see
778
- [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment/ip-intelligence).
926
+ For the IP-intelligence mechanism (lookup order, MMDB composition, refresh,
927
+ provider chains), see
928
+ [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment).
929
method_description: |
780
- The bundled `topology-ip-intel-downloader` supports IPtoASN as an ASN provider,
781
- fetching the latest TSV and converting it to MMDB format the plugin can read.
782
- Configure the downloader to use IPtoASN with `--asn iptoasn:combined`.
930
+ The Netdata plugin reads MMDB only. IPtoASN ships gzipped TSV
931
+ (`https://iptoasn.com/data/ip2asn-combined.tsv.gz`), so the TSV must be
932
+ converted to MMDB before the plugin can use it.
933
+
934
+ When available, Netdata provides a converter for this exact purpose: the
935
+ `topology-ip-intel-downloader` Go tool fetches the upstream TSV, parses it,
936
+ and emits MMDB files the plugin auto-detects. This is
937
+ a separate operator step (cron); the plugin itself does no fetching or
938
+ conversion. Packaged 32-bit installs ship the stock MMDB payload but do not include
939
+ the downloader binary. If you prefer not to use the bundled tool, any third-party
940
+ IPtoASN-to-MMDB converter that produces a standard
941
+ [MaxMind DB](https://maxmind.github.io/MaxMind-DB/) with `iso_code`,
942
+ `autonomous_system_number`, and `autonomous_system_organization` fields
943
+ will also work with the Custom MMDB integration.
944
supported_platforms:
945
include:
946
- Linux
950
description: ""
951
default_behavior:
952
auto_detection:
792
- description: "Not auto-detected as the default ASN source -- the plugin auto-detects DB-IP. To use IPtoASN as ASN, run the downloader explicitly."
953
+ description: |
954
+ Not auto-detected as the default ASN source -- the plugin auto-detects
955
+ DB-IP MMDBs in the cache directory at startup
956
+ (see [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment)).
957
+ To use IPtoASN, run `topology-ip-intel-downloader` when available to produce IPtoASN-derived
958
+ MMDBs (the downloader writes to the same cache paths the plugin scans,
959
+ so once present they are picked up automatically on the 30-second
960
+ file-signature check).
961
limits:
794
- description: ""
962
+ description: "IPtoASN provides AS number and country-level data only. It does not provide city, coordinates, or rich organization names unless you layer another MMDB source."
963
performance_impact:
796
- description: ""
964
+ description: "Lookups are local MMDB reads after the downloader converts the TSV feed. Memory use is mostly the mapped database files and the kernel page cache needed to keep active pages hot."
965
setup:
966
prerequisites:
967
list:
968
- title: Run the downloader with IPtoASN as ASN source
969
description: |
802
- IPtoASN is a TSV file. The bundled downloader knows how to fetch and convert
803
- it to MMDB:
970
+ When available, the downloader knows how to fetch the upstream TSV and convert
971
+ it to MMDB. Packaged 32-bit installs do not include this binary:
972
+
973
+ ```bash
974
+ sudo /usr/sbin/topology-ip-intel-downloader \
975
+ --asn iptoasn:combined \
976
+ --geo iptoasn:combined
977
+ ```
978
+
979
+ `iptoasn:combined` is valid for both `--asn` and `--geo` because the
980
+ upstream TSV carries both AS data and country. If you
981
+ want richer geographic data (state, city, coordinates), pair IPtoASN
982
+ ASN with DB-IP or MaxMind geo:
983
984
```bash
985
sudo /usr/sbin/topology-ip-intel-downloader \
987
--geo dbip:city-lite
988
```
989
811
- This produces ASN data from IPtoASN and geographic data from DB-IP. Schedule
812
- this in cron (daily for ASN; weekly is enough for geo).
990
+ IPtoASN rebuilds hourly upstream, but a daily cron is sufficient for
991
+ flow enrichment (ASN ownership rarely changes within a single day).
992
+ Do not exceed hourly -- you only get a fresh dataset once an hour
993
+ regardless.
994
configuration:
995
file:
996
name: netflow.yaml
997
options:
998
description: |
818
- Once the downloader has produced MMDB files in the cache directory, the plugin
819
- auto-detects them. To pin the path explicitly, set `enrichment.geoip.asn_database`.
999
+ Once the downloader has produced IPtoASN-derived MMDB files in the cache
1000
+ directory, the plugin auto-detects them. To pin the path explicitly, set
1001
+ `enrichment.geoip.asn_database` (and `geo_database` when you also want
1002
+ the country data IPtoASN provides).
1003
folding:
1004
title: Config options
1005
enabled: true
1006
list:
1007
- name: enrichment.geoip.asn_database
825
- description: Path to the IPtoASN-derived MMDB. Empty = auto-detect from cache directory.
1008
+ description: Path to the IPtoASN-derived ASN MMDB. Empty = auto-detect from cache directory.
1009
+ default_value: "[]"
1010
+ required: false
1011
+ - name: enrichment.geoip.geo_database
1012
+ description: Path to the IPtoASN-derived geo MMDB (country only). Empty = auto-detect; or point at a richer DB-IP / MaxMind geo MMDB for state/city/coordinates.
1013
default_value: "[]"
1014
required: false
1015
+ - name: enrichment.geoip.optional
1016
+ description: When true, missing or unreadable MMDBs are warnings, not fatal at startup.
1017
+ default_value: "false (true when auto-detected)"
1018
+ required: false
1019
examples:
1020
folding:
1021
title: Config
1024
- name: After running the downloader with IPtoASN
1025
folding:
1026
enabled: false
836
- description: Auto-detection picks up the cache copy.
1027
+ description: Auto-detection picks up the cache copy. Both ASN and country come from IPtoASN.
1028
+ config: |
1029
+ enrichment:
1030
+ geoip:
1031
+ asn_database: []
1032
+ geo_database: []
1033
+ optional: true
1034
+ - name: Explicit IPtoASN paths (ASN + country only)
1035
+ folding:
1036
+ enabled: true
1037
+ description: |
1038
+ Pin the IPtoASN-derived MMDBs explicitly. Country only -- no
1039
+ state/city. Use the DB-IP or MaxMind integration cards for richer
1040
+ geographic enrichment.
1041
+ config: |
1042
+ enrichment:
1043
+ geoip:
1044
+ asn_database:
1045
+ - /var/cache/netdata/topology-ip-intel/topology-ip-asn.mmdb
1046
+ geo_database:
1047
+ - /var/cache/netdata/topology-ip-intel/topology-ip-geo.mmdb
1048
+ optional: false
1049
+ - name: IPtoASN ASN + DB-IP city-lite geo
1050
+ folding:
1051
+ enabled: true
1052
+ description: |
1053
+ Free, fully public-domain ASN combined with DB-IP city-lite for
1054
+ state/city/coordinates. Run the downloader as
1055
+ `topology-ip-intel-downloader --asn iptoasn:combined --geo dbip:city-lite`
1056
+ and let auto-detection handle the rest.
1057
config: |
1058
enrichment:
1059
geoip:
1065
list:
1066
- name: ASN names not appearing
1067
description: |
848
- IPtoASN's data does not always carry a human-readable ASN organization name.
849
- The plugin renders `AS{n}` (without a name) for those records. This is data-source-
850
- level, not a plugin issue. Use MaxMind GeoLite2-ASN if you need richer name data.
1068
+ IPtoASN's `AS_description` column is sometimes empty for less-common
1069
+ ASNs (the upstream derives names from RIRs and the chain occasionally
1070
+ has gaps). When that happens the plugin renders the AS as `AS{n}` with
1071
+ no organisation. This is data-source-level, not a plugin issue. If richer AS-name
1072
+ coverage matters, layer a MaxMind GeoLite2-ASN MMDB after IPtoASN in
1073
+ `asn_database` -- per-field "last database with a non-empty value
1074
+ wins" composition (see
1075
+ [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment))
1076
+ means MaxMind names override IPtoASN's empty entries.
1077
+ - name: Country empty although IPtoASN was selected
1078
+ description: |
1079
+ IPtoASN's combined TSV publishes country only when it is known. Public
1080
+ IPs that the upstream cannot attribute will have an empty
1081
+ `*_COUNTRY`. If you need broader country coverage, point
1082
+ `geo_database` at a DB-IP or MaxMind country MMDB instead -- the
1083
+ plugin reads any combination.
1084
- name: Outdated ASN attribution
1085
description: |
853
- IPtoASN is rebuilt daily from BGP. Cron the downloader at least daily to keep
854
- ASN attribution current with real-world routing changes.
1086
+ IPtoASN rebuilds hourly upstream. A daily cron of the downloader is
1087
+ the recommended cadence for flow enrichment; weekly is too slow
1088
+ because BGP-driven prefix re-assignments will land in the dataset
1089
+ within hours but not in your cache until the next download. The
1090
+ plugin reloads MMDB files in place every 30 seconds when the file
1091
+ signature changes, so a fresh file lands without restart.
1092
alerts: []
1093
metrics:
1094
folding:
1095
title: Metrics
1096
enabled: false
1097
description: |
861
- Enriches flow records with AS numbers; provides no metrics of its own.
1098
+ Enriches flow records with AS numbers, AS names, and country codes; produces
1099
+ no metrics of its own. Verify on the Network Flows view via `*_AS_NAME` and
1100
+ `*_COUNTRY` columns.
1101
availability: []
1102
scopes: []
864
-
1103
- meta:
1104
plugin_name: netflow-plugin
1105
module_name: custom-mmdb
1107
name: Custom MMDB Database
1108
link: https://maxmind.github.io/MaxMind-DB/
1109
categories:
872
- - flows.ip-intelligence
1110
+ - flows.enrichment-methods
1111
icon_filename: network-wired.svg
1112
keywords:
1113
- mmdb
1114
- custom database
1115
- bring your own
878
- - ipinfo
1116
+ - mmdbwriter
1117
+ - internal asn
1118
+ - internal ipam
1119
- ip intelligence
1120
related_resources:
1121
integrations:
1131
overview:
1132
data_collection:
1133
metrics_description: |
894
- The plugin reads any MMDB file that conforms to the standard schema -- this catch-all
895
- integration covers IPInfo, custom-built internal MMDBs, vendor-specific feeds, or
896
- any provider that publishes MMDB data.
1134
+ Enrich network flows with ASN, geographic, or internal network context from
1135
+ operator-built MMDB databases. Use Custom MMDB Database when you want the netflow
1136
+ plugin to read a MaxMind-format binary database (`.mmdb`) that your
1137
+ own tooling produces -- typical use cases are joining the upstream DB-IP /
1138
+ GeoLite2 data with internal AS labels, or producing a CIDR-tagged custom file
1139
+ directly from an internal IPAM. The plugin only requires the file to conform to
1140
+ the [MaxMind DB binary format](https://maxmind.github.io/MaxMind-DB/); whatever
1141
+ fields it exposes are picked up by the same decoder path used for DB-IP and
1142
+ MaxMind.
1143
+
1144
+ The decoder reads `autonomous_system_number`, `autonomous_system_organization`,
1145
+ and (optionally) a string `asn` field from the ASN database, and `country.iso_code`,
1146
+ `subdivisions[].iso_code`, `city.names.en`, `location.latitude`,
1147
+ `location.longitude`, plus the Netdata-specific `netdata.ip_class` flag from the
1148
+ geo database. Any other vendor-specific keys are ignored.
1149
898
- The plugin reads `country.iso_code`, `city.names.en`, `subdivisions[].iso_code`,
899
- `location.latitude`, `location.longitude`, `autonomous_system_number`, and
900
- `autonomous_system_organization`. Vendor-specific extra fields are ignored.
1150
+ Note that `*_GEO_CITY`, `*_GEO_LATITUDE`, and `*_GEO_LONGITUDE` are written to
1151
+ the raw journal tier only -- the rollup tiers drop these high-cardinality fields.
1152
+ State and country survive into all four tiers.
1153
902
- For the full IP-intelligence concept, see
903
- [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment/ip-intelligence).
1154
+ For the full IP-intelligence concept (composition rule, ASN provider chain,
1155
+ auto-detect path order, dual-stack handling, hot reload semantics), see
1156
+ [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment).
1157
method_description: |
905
- You produce or download an MMDB file. Place it on the agent host. Point the
906
- plugin at it via `netflow.yaml`. The plugin reloads on file change every 30
907
- seconds.
1158
+ You build (or download) the MMDB file with your own tooling, place it on the
1159
+ agent host, and point `enrichment.geoip.asn_database` and / or
1160
+ `enrichment.geoip.geo_database` at it in `netflow.yaml`. The plugin reloads on
1161
+ file change automatically (mechanism documented on the IP Intelligence page).
1162
supported_platforms:
1163
include:
1164
- Linux
1170
auto_detection:
1171
description: "Not auto-detected. You must configure paths explicitly."
1172
limits:
919
- description: ""
1173
+ description: "Coverage, schema quality, and freshness are entirely controlled by the custom MMDB build you provide. Invalid or missing files fail startup unless marked optional."
1174
performance_impact:
921
- description: ""
1175
+ description: "Lookups are local MMDB reads with no per-flow network call. Memory use depends on the size and number of custom databases you configure."
1176
setup:
1177
prerequisites:
1178
list:
925
- - title: A standards-compliant MMDB file
1179
+ - title: Build or obtain a standards-compliant MMDB file
1180
description: |
927
- The MMDB file must use the [standard MMDB schema](https://maxmind.github.io/MaxMind-DB/).
928
- Validate with `mmdblookup` from the `libmaxminddb-tools` package before deploying.
1181
+ The file must conform to the
1182
+ [MaxMind DB binary format spec](https://maxmind.github.io/MaxMind-DB/) --
1183
+ a binary search tree over IP prefixes plus a data section of
1184
+ type-length-value records. Validate with `mmdblookup` from the
1185
+ `libmaxminddb-tools` package before deploying:
1186
930
- Common sources: IPInfo (`ipinfo.io`), custom internal builds via the `mmdbwriter`
931
- Go tool, or vendor-specific feeds.
1187
+ ```bash
1188
+ mmdblookup --file your-custom.mmdb --ip 8.8.8.8
1189
+ ```
1190
+
1191
+ Common ways to produce a file:
1192
+
1193
+ - **Go**: [`github.com/maxmind/mmdbwriter`](https://github.com/maxmind/mmdbwriter)
1194
+ -- MaxMind's official Go writer. Lets you start from an upstream MMDB
1195
+ (DB-IP, GeoLite2) and overlay extra records, then write a new file.
1196
+ Pairs well with the read-side library
1197
+ [`github.com/oschwald/maxminddb-golang`](https://github.com/oschwald/maxminddb-golang).
1198
+ - **Perl**: [`MaxMind::DB::Writer`](https://metacpan.org/pod/MaxMind::DB::Writer)
1199
+ -- the original reference writer.
1200
+ - **Python**: community ports such as `mmdb_writer` (PyPI) wrap the same
1201
+ format.
1202
+
1203
+ Whatever fields you encode are read by the plugin only if they match the
1204
+ standard schema names listed in the metrics description above.
1205
configuration:
1206
file:
1207
name: netflow.yaml
1208
options:
1209
description: |
937
- Point `enrichment.geoip.asn_database` and/or `enrichment.geoip.geo_database` at
938
- your MMDB file paths.
1210
+ Point `enrichment.geoip.asn_database` and / or `enrichment.geoip.geo_database`
1211
+ at your custom MMDB file paths. Set `optional: true` while you iterate so a
1212
+ missing or malformed file does not block plugin startup.
1213
folding:
1214
title: Config options
1215
enabled: true
1216
list:
1217
- name: enrichment.geoip.asn_database
944
- description: List of MMDB paths providing AS data. Multiple files allowed; later entries override on overlap.
1218
+ description: List of MMDB paths providing AS data. Multiple files compose -- per field, the last database returning a non-empty value wins.
1219
default_value: "[]"
1220
required: false
1221
- name: enrichment.geoip.geo_database
948
- description: List of MMDB paths providing geographic data.
1222
+ description: List of MMDB paths providing geographic data. Same composition rule as the ASN list.
1223
default_value: "[]"
1224
required: false
1225
- name: enrichment.geoip.optional
952
- description: When true, missing files become startup warnings instead of fatal errors.
1226
+ description: When true, missing or unreadable files at startup are tolerated (the resolver starts with no databases). Recommended while testing a custom file.
1227
default_value: "false"
1228
required: false
1229
examples:
1231
title: Config
1232
enabled: true
1233
list:
960
- - name: IPInfo MMDB
1234
+ - name: Internal MMDB built with mmdbwriter
1235
folding:
1236
enabled: false
963
- description: Using IPInfo's MMDB feed (subscription required).
1237
+ description: A custom build that combines public BGP data with internal CIDR labels, written atomically into the plugin's lookup directory by the operator's own pipeline.
1238
config: |
1239
enrichment:
1240
geoip:
1241
asn_database:
968
- - /opt/mmdb/ipinfo-asn.mmdb
1242
+ - /etc/netdata/internal-asn.mmdb
1243
geo_database:
970
- - /opt/mmdb/ipinfo-city.mmdb
1244
+ - /etc/netdata/internal-geo.mmdb
1245
optional: false
972
- - name: Internal custom MMDB
1246
+ - name: Overlay a custom ASN file on top of the bundled DB-IP geo
1247
folding:
1248
enabled: true
975
- description: Built in-house with `mmdbwriter`. Combines public BGP data with internal CIDR labels.
1249
+ description: Keep DB-IP for geographic data and use a custom MMDB only for AS labels (your IPAM-derived prefixes win because they appear last in the list -- the resolver merges per field, last non-empty wins).
1250
config: |
1251
enrichment:
1252
geoip:
1253
asn_database:
1254
+ - /var/cache/netdata/topology-ip-intel/topology-ip-asn.mmdb
1255
- /etc/netdata/internal-asn.mmdb
1256
geo_database:
982
- - /etc/netdata/internal-geo.mmdb
983
- optional: false
1257
+ - /var/cache/netdata/topology-ip-intel/topology-ip-geo.mmdb
1258
+ optional: true
1259
+ - name: Iterating on a new custom MMDB
1260
+ folding:
1261
+ enabled: true
1262
+ description: While you tune the build pipeline, mark the database optional so an absent or malformed file becomes a startup warning instead of a fatal error.
1263
+ config: |
1264
+ enrichment:
1265
+ geoip:
1266
+ asn_database:
1267
+ - /etc/netdata/wip-asn.mmdb
1268
+ geo_database: []
1269
+ optional: true
1270
troubleshooting:
1271
problems:
1272
list:
1273
- name: Lookups silently return empty
1274
description: |
989
- The MMDB schema is non-standard or the IP types don't match (some custom builds
990
- use `string` instead of `array` for ASN). Validate with `mmdblookup -f file.mmdb -i 8.8.8.8`
991
- and confirm the standard fields are present.
1275
+ The custom file's schema is non-standard (for example, the ASN is encoded
1276
+ as a string instead of `autonomous_system_number: uint32`, or the country
1277
+ is at a non-standard path). The plugin only reads the standard MaxMind
1278
+ field names listed in the data-collection description. Validate with
1279
+ `mmdblookup --file your-custom.mmdb --ip <known-public-ip>` and confirm the
1280
+ standard fields are present at the expected paths.
1281
- name: Plugin fails to start with optional=false
1282
description: |
994
- File missing or unreadable at the configured path. Check permissions; the netdata
995
- user must be able to read the file.
1283
+ File missing, unreadable, or not a valid MMDB at the configured path.
1284
+ Check permissions (the netdata user must be able to read the file) and
1285
+ re-validate with `mmdblookup`. Set `optional: true` while iterating.
1286
+ - name: Custom file refresh did not take effect
1287
+ description: |
1288
+ The plugin reloads custom databases the same way it reloads stock ones
1289
+ (signature-driven, in place). If the file was rewritten in place the
1290
+ plugin will pick it up; if it was edited byte-by-byte (rare with MMDB
1291
+ builders) verify size or mtime actually changed. The reload mechanism
1292
+ and its 30-second cadence are documented in
1293
+ [IP Intelligence](https://learn.netdata.cloud/docs/network-flows/enrichment).
1294
+ Operational practice: have your build pipeline write the new MMDB to a
1295
+ temp file in the same directory and `rename(2)` it over the live path so
1296
+ the swap is atomic.
1297
alerts: []
1298
metrics:
1299
folding:
1303
Enriches flow records; produces no metrics of its own.
1304
availability: []
1305
scopes: []
1005
-
1006
- # =====================================================================
1007
- # BGP Routing: live route feeds (BMP, BioRIS) used to enrich flow records
1008
- # =====================================================================
1009
-
1306
- meta:
1307
plugin_name: netflow-plugin
1308
module_name: bmp
1310
name: BMP (BGP Monitoring Protocol)
1311
link: https://www.rfc-editor.org/rfc/rfc7854
1312
categories:
1017
- - flows.bgp-routing
1313
+ - flows.enrichment-methods
1314
icon_filename: network-wired.svg
1315
keywords:
1316
- bmp
1319
- route monitoring
1320
- cisco
1321
- juniper
1322
+ - arista
1323
- frr
1324
+ - nokia
1325
related_resources:
1326
integrations:
1327
list:
1332
overview:
1333
data_collection:
1334
metrics_description: |
1037
- BMP (BGP Monitoring Protocol, RFC 7854) lets a router push its BGP route updates
1038
- to a passive collector. With this integration enabled, Netdata acts as that
1039
- collector -- it listens for BMP TCP connections from your routers, parses the BGP
1040
- UPDATE messages, and builds an in-memory routing table that flow enrichment then
1041
- reads from.
1042
-
1043
- The result: every flow gets accurate AS numbers, AS paths, communities, and
1044
- next-hop information from your real-time BGP table -- not from a stale GeoIP
1045
- database or from whatever the exporter happened to send in the flow record.
1046
-
1047
- For the full BGP-routing concept (shared trie with BioRIS, withdrawal handling,
1048
- per-vendor caveats, integration test gap), see
1049
- [BGP Routing](https://learn.netdata.cloud/docs/network-flows/enrichment/bgp-routing).
1335
+ Enrich network flows with BGP next-hop, AS path, communities, and routing
1336
+ context received directly from routers. BMP (BGP Monitoring Protocol, RFC 7854)
1337
+ lets a router push its BGP route updates to a passive collector. With this
1338
+ integration enabled, Netdata is that collector -- it listens for BMP TCP
1339
+ connections from your routers, parses BGP UPDATE messages carried inside
1340
+ RouteMonitoring frames, and builds an in-memory routing trie that flow enrichment
1341
+ then reads from.
1342
+
1343
+ Every flow whose source or destination IP matches a learned prefix gains:
1344
+ `SRC_AS` / `DST_AS` (when the `routing` provider in `asn_providers` reaches BGP
1345
+ data), `SRC_MASK` / `DST_MASK` (when `routing` reaches BGP data in `net_providers`),
1346
+ plus -- for the destination side only -- `NEXT_HOP`, `DST_AS_PATH`,
1347
+ `DST_COMMUNITIES`, and `DST_LARGE_COMMUNITIES` (RFC 8092). Source-side AS path and
1348
+ communities are not surfaced; BGP path attributes are most meaningful for the
1349
+ destination of the traffic. AS *names* (`*_AS_NAME`) come from the GeoIP/ASN MMDB,
1350
+ not from BMP -- BMP gives you accurate AS *numbers* and path/communities.
1351
+
1352
+ AS path, communities, and large communities are written to the **raw** flow journal
1353
+ only -- the rollup tiers do not carry them. `NEXT_HOP` is carried in both raw and
1354
+ rollup.
1355
+
1356
+ For the cross-cutting Enrichment concept (provider chains, shared trie with
1357
+ BioRIS, withdrawal handling, restart convergence), see
1358
+ [Enrichment](https://learn.netdata.cloud/docs/network-flows/enrichment).
1359
method_description: |
1051
- The plugin runs a TCP listener on `0.0.0.0:10179` (Akvorado convention -- not the
1052
- IANA-registered port 7854). Routers initiate BMP sessions to it. The plugin
1053
- processes Initiation, Termination, RouteMonitoring (BGP UPDATE messages), and
1054
- PeerDownNotification messages. NLRI types: IPv4/IPv6 unicast, MPLS-labelled, VPNv4,
1055
- VPNv6, EVPN IP-prefix.
1056
-
1057
- BMP and BioRIS share a single in-memory routing trie. Memory grows with the size
1058
- of the BGP table; a full IPv4+IPv6 feed is roughly 1.2M prefixes per peer.
1360
+ The plugin runs a TCP listener on `0.0.0.0:10179`. This port is the Akvorado
1361
+ convention -- RFC 7854 does not register a port, and IANA does not assign one
1362
+ for BMP. Each connecting router must first send an Initiation message; the plugin
1363
+ then processes RouteMonitoring (carrying BGP UPDATE), PeerDownNotification, and
1364
+ Termination frames. PeerUp, StatisticsReport, and RouteMirroring frames are
1365
+ accepted but not acted on. Only BMP **version 3** is processed; v1 and v2 frames
1366
+ are silently dropped.
1367
+
1368
+ NLRI families parsed: IPv4/IPv6 unicast, IPv4/IPv6 MPLS-labelled, VPNv4, VPNv6,
1369
+ and EVPN IP-prefix routes.
1370
+
1371
+ BMP and BioRIS share a single in-memory routing trie. A full IPv4+IPv6 BGP table
1372
+ is roughly 1.2M prefixes per peer; each entry stores `Vec<u32>` AS-path,
1373
+ `Vec<u32>` communities, `Vec<(u32,u32,u32)>` large communities, plus a route_key
1374
+ string per path. Expect several hundred MB of resident memory per peer with a full
1375
+ feed. The trie has no time-based eviction -- routes leave only via explicit BGP
1376
+ withdrawal (`MP_UNREACH` or `withdraw_routes`), PeerDown, or session disconnect
1377
+ followed by the `keep` interval expiring (default 5 minutes).
1378
supported_platforms:
1379
include:
1380
- Linux
1384
description: ""
1385
default_behavior:
1386
auto_detection:
1068
- description: "Disabled by default. Set enrichment.routing_dynamic.bmp.enabled to true and configure your routers."
1387
+ description: "Disabled by default. Set enrichment.routing_dynamic.bmp.enabled to true and configure your routers to dial in."
1388
limits:
1070
- description: ""
1389
+ description: "Memory and CPU scale with the number of BMP sessions, routing tables, prefixes, AS paths, and communities. Full-table router feeds can consume hundreds of MB per peer."
1390
performance_impact:
1072
- description: ""
1391
+ description: "Disabled until BMP is configured. Once active, BMP updates maintain an in-memory routing trie used for enrichment, so resource use scales with routing-table size and update rate."
1392
setup:
1393
prerequisites:
1394
list:
1395
- title: BMP-capable routers
1396
description: |
1078
- Modern Cisco IOS-XR, Juniper JunOS, Arista EOS, and FRR all support BMP v3.
1079
- The plugin parses RFC 7854 BMP v3 specifically. Older versions (v1, v2) are
1080
- not supported and will fail to parse.
1397
+ Common vendor configuration patterns:
1398
+
1399
+ - **Cisco IOS-XR** -- `bmp server N` global block plus `bmp-activate server N`
1400
+ under `router bgp ... neighbor`.
1401
+ - **Cisco IOS-XE 3.12 / 15.4 or later** -- `bmp server N` nested inside
1402
+ `router bgp` with `activate`.
1403
+ - **Juniper JunOS** (BMP support since 13.3, RFC 8671 Adj-RIB-In since 18.3R1)
1404
+ -- `routing-options bmp ...` with one or more named stations.
1405
+ - **Arista EOS** -- `router bgp ... bgp monitoring` with one or more
1406
+ `monitoring station` blocks (active connection).
1407
+ - **Nokia SR OS** (MD-CLI) -- `/configure bmp` plus per-router `bgp monitor`.
1408
+ - **FRR (bgpd)** -- `bmp targets` block under `router bgp`. Note the loadable
1409
+ module: `bgpd` must be started with `-M bmp` or every BMP command silently
1410
+ fails.
1411
+
1412
+ The plugin parses RFC 7854 BMP **version 3** only. Older draft versions (v1,
1413
+ v2) are silently dropped.
1414
- title: TCP reachability between routers and the agent
1415
description: |
1416
Routers initiate the connection -- the plugin is a passive listener. Allow
1417
inbound TCP on the configured port (default 10179) from each BMP-speaking
1085
- router to the agent.
1418
+ router to the agent. The plugin does not retry; it waits for the router to
1419
+ reconnect.
1420
- title: No TLS, no authentication
1421
description: |
1088
- The listener accepts plain TCP only. Restrict access at the firewall and on a
1089
- dedicated management network -- do not expose 10179 to the public internet.
1422
+ The listener accepts plain TCP only. Restrict access at the firewall and use
1423
+ a dedicated management network -- never expose 10179 to the public internet.
1424
+ BMP carries your full routing table; treat it as sensitive.
1425
configuration:
1426
file:
1427
name: netflow.yaml
1441
default_value: "0.0.0.0:10179"
1442
required: false
1443
- name: keep
1109
- description: Grace window after a BMP disconnect before purging that session's routes.
1444
+ description: Grace window after a BMP disconnect before purging that session's routes from the trie.
1445
default_value: "5m"
1446
required: false
1447
- name: max_consecutive_decode_errors
1453
default_value: "0"
1454
required: false
1455
- name: collect_asns
1121
- description: When false, AS numbers from BMP are forced to 0.
1456
+ description: When false, AS numbers from BMP are forced to 0 before storage.
1457
default_value: "true"
1458
required: false
1459
- name: collect_as_paths
1461
default_value: "true"
1462
required: false
1463
- name: collect_communities
1129
- description: When false, communities and large communities are dropped.
1464
+ description: When false, communities and large communities are dropped before storage.
1465
default_value: "true"
1466
required: false
1467
- name: rds
1468
description: |
1134
- Whitelist of accepted Route Distinguishers. Empty = accept all.
1135
- Formats: "0", "ASN:idx", "IPv4:idx", or full text.
1469
+ Whitelist of accepted Route Distinguishers for L3VPN peers. Empty list
1470
+ accepts everything. Formats: numeric `0`, `"ASN:idx"`, `"IPv4:idx"`, or
1471
+ full text RD.
1472
default_value: "[]"
1473
required: false
1474
examples:
1490
- name: Cisco IOS-XR router config
1491
folding:
1492
enabled: true
1157
- description: Vendor-side config to send BMP to Netdata. The bmp server block is global, not under router bgp.
1493
+ description: |
1494
+ Vendor-side config to send BMP to Netdata. The `bmp server` block is
1495
+ global, not under `router bgp`. Each neighbor that should be exported
1496
+ needs `bmp-activate server N`. IOS-XR's default route monitoring is
1497
+ pre-policy (Adj-RIB-In before inbound policy). Set
1498
+ `route-monitoring policy post inbound` if you prefer post-policy.
1499
config: |
1500
bmp server 1
1501
host 10.0.0.10 port 10179
1502
description "Netdata BMP collector"
1503
+ update-source Loopback0
1504
initial-delay 5
1505
stats-reporting-period 60
1506
initial-refresh delay 30 spread 2
1508
router bgp 65000
1509
neighbor 192.0.2.1
1510
bmp-activate server 1
1511
+ - name: Cisco IOS-XE router config
1512
+ folding:
1513
+ enabled: true
1514
+ description: |
1515
+ IOS-XE 3.12 / 15.4 or later. The `bmp server N` block lives inside
1516
+ `router bgp`, unlike IOS-XR.
1517
+ config: |
1518
+ router bgp 65000
1519
+ bmp server 1
1520
+ address 10.0.0.10 port-number 10179
1521
+ description "Netdata BMP collector"
1522
+ initial-delay 10
1523
+ stats-reporting-period 60
1524
+ update-source GigabitEthernet1
1525
+ activate
1526
+ exit-bmp-server-mode
1527
+ !
1528
+ neighbor 192.0.2.1 bmp-activate all
1529
- name: Juniper JunOS router config
1530
folding:
1531
enabled: true
1172
- description: Recommended local-address and statistics-timeout for production.
1532
+ description: |
1533
+ Named station form. JunOS supports both pre-policy (RFC 7854) and
1534
+ post-policy / Adj-RIB-In (RFC 8671, JunOS 18.3R1+).
1535
config: |
1536
set routing-options bmp station netdata station-address 10.0.0.10
1537
set routing-options bmp station netdata station-port 10179
1539
set routing-options bmp station netdata local-address 10.0.0.1
1540
set routing-options bmp station netdata statistics-timeout 60
1541
set routing-options bmp station netdata route-monitoring pre-policy
1542
+ set routing-options bmp station netdata monitor enable
1543
+ - name: Arista EOS router config
1544
+ folding:
1545
+ enabled: true
1546
+ description: |
1547
+ EOS uses `bgp monitoring` plus one or more `monitoring station` blocks
1548
+ inside `router bgp`. Active connection mode is the equivalent of all
1549
+ other vendors (router dials Netdata).
1550
+ config: |
1551
+ router bgp 65000
1552
+ bgp monitoring
1553
+ monitoring station netdata
1554
+ update-source Management1
1555
+ connection address 10.0.0.10
1556
+ connection mode active port 10179
1557
+ export-policy received routes post-policy
1558
+ export-policy bgp rib bestpaths
1559
- name: FRR (bgpd) router config
1560
folding:
1561
enabled: true
1562
description: |
1184
- Critical -- BMP is a runtime module in FRR. Without "-M bmp" in
1185
- /etc/frr/daemons (bgpd_options), every BMP command silently fails.
1563
+ Critical -- BMP is a runtime module in FRR. Without `-M bmp` in
1564
+ `/etc/frr/daemons` (`bgpd_options`), every BMP command silently fails.
1565
config: |
1566
# /etc/frr/daemons:
1567
# bgpd_options=" -A 127.0.0.1 -M bmp"
1572
bmp monitor ipv4 unicast pre-policy
1573
bmp monitor ipv6 unicast pre-policy
1574
exit
1575
+ - name: Nokia SR OS (MD-CLI) router config
1576
+ folding:
1577
+ enabled: true
1578
+ description: Active connection from one or more BGP routing instances to a named station.
1579
+ config: |
1580
+ /configure bmp admin-state enable
1581
+ /configure bmp station "netdata" admin-state enable
1582
+ /configure bmp station "netdata" connection local-address 10.0.0.1
1583
+ /configure bmp station "netdata" connection station-address ip-address 10.0.0.10
1584
+ /configure bmp station "netdata" connection station-address port 10179
1585
+ /configure bmp station "netdata" family ipv4 true
1586
+ /configure bmp station "netdata" family ipv6 true
1587
+ /configure router "Base" bgp monitor admin-state enable
1588
+ /configure router "Base" bgp monitor route-monitoring post-policy true
1589
+ /configure router "Base" bgp monitor station "netdata" { }
1590
+ - name: Drop AS path and communities
1591
+ folding:
1592
+ enabled: true
1593
+ description: |
1594
+ Useful if you only care about the AS number for traffic attribution and
1595
+ want to keep the journal small.
1596
+ config: |
1597
+ enrichment:
1598
+ routing_dynamic:
1599
+ bmp:
1600
+ enabled: true
1601
+ collect_asns: true
1602
+ collect_as_paths: false
1603
+ collect_communities: false
1604
+ - name: Restrict to specific Route Distinguishers
1605
+ folding:
1606
+ enabled: true
1607
+ description: |
1608
+ For L3VPN peers, only accept routes whose RD matches the whitelist.
1609
+ Other peer types are unaffected.
1610
+ config: |
1611
+ enrichment:
1612
+ routing_dynamic:
1613
+ bmp:
1614
+ enabled: true
1615
+ rds:
1616
+ - "65000:100"
1617
+ - "65000:200"
1618
troubleshooting:
1619
problems:
1620
list:
1621
- name: Listener not receiving BMP sessions
1622
description: |
1201
- Check `show bmp` (Cisco) / `show bmp connections` (Juniper) / `show bmp targets` (FRR)
1202
- to confirm the router has dialed in. The plugin does not initiate -- it listens.
1203
- Firewall: allow inbound TCP on 10179.
1204
- - name: Memory growth
1623
+ The plugin is a passive listener -- it never dials. Check the router side:
1624
+ `show bmp` (Cisco), `show bmp connections` / `show bgp monitoring station`
1625
+ (Juniper, Arista), `show bmp targets` (FRR). Confirm the firewall allows
1626
+ inbound TCP on port 10179. For FRR specifically, verify `bgpd` was started
1627
+ with `-M bmp` -- without it, every BMP command is silently accepted but
1628
+ no connection is ever opened.
1629
+ - name: Convergence takes minutes after restart
1630
+ description: |
1631
+ The trie is not persisted. After a plugin restart, routers re-send
1632
+ Initiation followed by their Adj-RIB-In as RouteMonitoring updates. FRR
1633
+ re-emits everything in seconds. Cisco IOS-XR's `initial-refresh` is
1634
+ configurably spread (defaults to a per-peer delay) so a full re-feed can
1635
+ take minutes. Juniper varies between seconds and minutes depending on
1636
+ station options. Schedule restarts off-peak when BGP attribution matters.
1637
+ - name: Memory growth without bound
1638
description: |
1206
- A full BGP feed adds ~1.2M prefixes per peer permanently. There is no time-based
1207
- eviction. Plan capacity accordingly. After a router disconnect, the routes
1208
- for that session are kept for `keep` (default 5 min) before purging.
1209
- - name: Integration-test gap
1639
+ A full BGP feed adds ~1.2M prefixes per peer permanently -- there is no
1640
+ time-based eviction in the trie. Routes are removed only by explicit BGP
1641
+ withdrawal, PeerDown, or session disconnect followed by the `keep`
1642
+ interval. Plan capacity before connecting full-table peers.
1643
+ - name: AS path inconsistent with the exporter's view
1644
description: |
1211
- BMP message parsing has unit tests. The TCP listener path, framed decode loop,
1212
- trie apply, and per-router cleanup are NOT integration-tested. Validate against
1213
- your specific router firmware before depending on this for capacity / security
1214
- decisions.
1645
+ The exporter and the BMP-feeding router are usually different boxes with
1646
+ different routing tables. Different vantage points see different AS paths;
1647
+ this is normal. The `routing` provider in the `asn_providers` chain decides
1648
+ which source wins (default order is `flow, routing, geoip` -- exporter first).
1649
+ - name: Empty BGP enrichment after enabling
1650
+ description: |
1651
+ Confirm the router actually established the BMP session (vendor-side `show`
1652
+ command above). Confirm `enrichment.asn_providers` includes `routing` (or
1653
+ the `bmp` alias) -- if `routing` is removed from both `asn_providers` and
1654
+ `net_providers`, the trie is built but never read.
1655
+ - name: Validate BGP enrichment after enabling
1656
+ description: |
1657
+ BGP-derived enrichment depends on router export policy, peer state, and
1658
+ route visibility. Validate against your specific router firmware before
1659
+ depending on this for capacity or security decisions.
1660
alerts: []
1661
metrics:
1662
folding:
1663
title: Metrics
1664
enabled: false
1665
description: |
1221
- Enriches flow records with `SRC_AS`, `DST_AS`, `SRC_MASK`, `DST_MASK`, `NEXT_HOP`,
1222
- `DST_AS_PATH`, `DST_COMMUNITIES`, `DST_LARGE_COMMUNITIES`. Source-side AS path and
1223
- communities are not surfaced. AS names come from the GeoIP/ASN MMDB, not from BMP.
1224
- Verify by querying the AS-path columns on the Network Flows tab.
1666
+ Enriches flow records with `SRC_AS` / `DST_AS` (when the `routing` provider in
1667
+ `asn_providers` reaches BGP), `SRC_MASK` / `DST_MASK` (via `net_providers`),
1668
+ `NEXT_HOP`, `DST_AS_PATH`, `DST_COMMUNITIES`, `DST_LARGE_COMMUNITIES`. Source-side
1669
+ AS path and communities are not surfaced. AS *names* come from the GeoIP/ASN MMDB,
1670
+ not from BMP. AS path, communities, and large communities are RAW-tier-only --
1671
+ rollups carry only `NEXT_HOP`. Verify in the Network Flows view by querying the
1672
+ AS-path and communities columns.
1673
availability: []
1674
scopes: []
1227
-
1675
- meta:
1676
plugin_name: netflow-plugin
1677
module_name: bioris
1679
name: bio-rd / RIPE RIS
1680
link: https://github.com/bio-routing/bio-rd
1681
categories:
1235
- - flows.bgp-routing
1682
+ - flows.enrichment-methods
1683
icon_filename: network-wired.svg
1684
keywords:
1685
- bioris
1688
- bgp
1689
- grpc
1690
- route information service
1691
+ - as path
1692
+ - bgp communities
1693
related_resources:
1694
integrations:
1695
list:
1700
overview:
1701
data_collection:
1702
metrics_description: |
1254
- BioRIS lets Netdata consume BGP routing data from a [bio-rd](https://github.com/bio-routing/bio-rd)
1255
- `cmd/ris/` daemon over gRPC. bio-rd is a Go-based BGP daemon that can peer with
1256
- [RIPE RIS](https://www.ripe.net/analyse/internet-measurements/routing-information-service-ris)
1257
- Route Collectors -- or any BGP / BMP source you have access to -- and expose the
1258
- resulting RIB through a gRPC interface. Netdata is a client of that interface.
1259
-
1260
- Use this when you want a third-party view of the BGP routing table (e.g., RIPE
1261
- RIS's view) without running a BGP session yourself or deploying BMP across your
1262
- network.
1263
-
1264
- For the full BGP-routing concept and how BMP and BioRIS share the same trie, see
1265
- [BGP Routing](https://learn.netdata.cloud/docs/network-flows/enrichment/bgp-routing).
1703
+ Enrich network flows with BGP routing context received from bio-rd / RIPE RIS
1704
+ over gRPC. [bio-rd](https://github.com/bio-routing/bio-rd)
1705
+ is a Go-based BGP/BMP daemon that you run yourself. You point it at one or more
1706
+ BGP / BMP sources -- your own routers, a [RIPE RIS](https://www.ripe.net/analyse/internet-measurements/routing-information-service-ris)
1707
+ Route Collector you peer with, or any other reachable BGP source -- and it
1708
+ exposes the resulting RIB through a gRPC interface (`RoutingInformationService`).
1709
+ Netdata is a **client** of that interface, not of RIPE NCC directly.
1710
+
1711
+ Pick this when you want a third-party / external BGP view (e.g. RIPE RIS's view of the
1712
+ public DFZ) without exposing a BMP listener on your agent or running BMP across your
1713
+ network. If your routers can speak BMP straight to Netdata, the `bmp` integration is
1714
+ simpler -- BioRIS makes sense when bio-rd is already part of your routing toolbox or
1715
+ when you want to peer with an external party (RIPE RIS, looking-glass) and re-export
1716
+ to Netdata.
1717
+
1718
+ BioRIS populates the same flow-record fields as BMP -- both feed a single shared
1719
+ in-memory routing trie. See the BMP integration card for the side-by-side comparison
1720
+ and combined-deployment notes.
1721
method_description: |
1267
- The plugin connects to one or more bio-rd `ris` gRPC endpoints. It runs three RPCs:
1268
- `GetRouters` to discover what's available, `DumpRIB` to do baseline reconciliation,
1269
- and `ObserveRIB` for incremental updates. Multiple instances are additive (not
1270
- failover); they all merge into the shared in-memory trie.
1722
+ The plugin connects as a gRPC client to one or more user-provided bio-rd `ris`
1723
+ endpoints (`grpc_addr`) and runs three RPCs against each one:
1724
+
1725
+ 1. `GetRouters` -- discover which routers/VRFs the bio-rd instance is exposing.
1726
+ 2. `DumpRIB` -- pull a baseline RIB for each (router, AFI/SAFI) tuple. This is the
1727
+ expensive call -- full IPv4+IPv6 feeds run to millions of prefixes.
1728
+ 3. `ObserveRIB` -- subscribe to incremental updates so the trie tracks live changes.
1729
+
1730
+ Per refresh cycle (default 30 minutes), the plugin re-runs `GetRouters` +
1731
+ `DumpRIB`, then keeps `ObserveRIB` streams open between cycles. Routers that
1732
+ disappear between refreshes have their routes purged.
1733
+
1734
+ Multiple `ris_instances` are **additive**, not failover -- routes from every
1735
+ configured endpoint merge into the same trie. The trie is also shared with the
1736
+ `bmp` integration, so if both are enabled their routes coexist and lookups pick
1737
+ the best match across both sources.
1738
+
1739
+ Connection is plain gRPC over HTTP/2 by default; set `grpc_secure: true` to use
1740
+ TLS with the system CA bundle. There is no client-cert / mTLS and no application
1741
+ auth -- restrict access at the network layer.
1742
+
1743
+ **Fields populated** (same set as BMP):
1744
+
1745
+ | Field | Side | Source |
1746
+ |---|---|---|
1747
+ | `SRC_AS` / `DST_AS` | both | When the `routing` provider in the `asn_providers` chain matches |
1748
+ | `SRC_MASK` / `DST_MASK` | both | Prefix length of the longest-match BGP route |
1749
+ | `NEXT_HOP` | dest only | BGP next-hop attribute from the destination route |
1750
+ | `DST_AS_PATH` | dest only | Full AS path, CSV of ASNs |
1751
+ | `DST_COMMUNITIES` | dest only | Standard BGP communities (CSV of u32) |
1752
+ | `DST_LARGE_COMMUNITIES` | dest only | RFC 8092 large communities |
1753
+
1754
+ Source-side AS path and communities are **not** surfaced; BGP path attributes are
1755
+ most meaningful for the destination of the traffic. AS *names* (`SRC_AS_NAME`,
1756
+ `DST_AS_NAME`) come from the GeoIP/ASN MMDB, not from BGP -- BioRIS gives you
1757
+ accurate AS *numbers* and path/community attributes; the names come from the ASN
1758
+ database integration.
1759
+
1760
+ **Storage tier:** `DST_AS_PATH`, `DST_COMMUNITIES`, and `DST_LARGE_COMMUNITIES`
1761
+ are written only into the raw journal tier. The 1-minute / 5-minute / 1-hour
1762
+ rollup tiers do not carry them. Queries that need AS path or community data
1763
+ must run against a window that the raw retention still covers.
1764
supported_platforms:
1765
include:
1766
- Linux
1772
auto_detection:
1773
description: "Disabled by default. Set enrichment.routing_dynamic.bioris.enabled to true and provide at least one ris_instances entry."
1774
limits:
1282
- description: ""
1775
+ description: "Memory scales with the number of RIS instances, peers, routing tables, prefixes, AS paths, and communities. Full-table feeds can consume hundreds of MB per peer."
1776
performance_impact:
1284
- description: ""
1777
+ description: |
1778
+ Disabled until BioRIS is configured. Once active, Netdata maintains an
1779
+ in-memory routing trie for the received RIB and updates. Plan capacity from
1780
+ the number of peers and tables you import, and watch the agent's RSS.
1781
setup:
1782
prerequisites:
1783
list:
1784
- title: A running bio-rd 'ris' daemon
1785
description: |
1786
bio-rd is a separate project. The plugin only consumes its gRPC interface; it
1291
- does not bundle bio-rd. You install it yourself:
1787
+ does not bundle bio-rd. You install and operate it yourself:
1788
1789
```bash
1790
# Install Go (>=1.20), then:
1793
go build -o /usr/local/bin/ris .
1794
```
1795
1300
- Configure `ris` to peer with one or more BGP / BMP sources (RIPE RIS Route
1301
- Collectors, your own peers, etc.). Refer to the bio-rd documentation for the
1302
- peering setup -- this is bio-rd's configuration, not Netdata's.
1796
+ Configure `ris` to peer with one or more BGP / BMP sources (your own routers,
1797
+ RIPE RIS Route Collectors, looking-glass servers, etc.). Refer to the bio-rd
1798
+ documentation for the peering setup -- this is bio-rd's configuration, not
1799
+ Netdata's.
1800
1801
Run the daemon with a gRPC port:
1802
`/usr/local/bin/ris --grpc_port 50051 --config.file /etc/bio-rd.yml`
1803
- title: Network reachability + no auth
1804
description: |
1308
- The gRPC connection is plain HTTP/2 by default (or TLS with system-CA when
1309
- `grpc_secure: true`). There is no authentication. Restrict access at the
1310
- firewall, or run bio-rd on the same host as the agent and bind it to localhost.
1805
+ The gRPC connection is plain HTTP/2 by default, or TLS with the system CA
1806
+ bundle when `grpc_secure: true`. There is no client-cert / mTLS and no application
1807
+ authentication -- restrict access at the firewall, or run bio-rd on the same
1808
+ host as the agent and bind it to localhost.
1809
configuration:
1810
file:
1811
name: netflow.yaml
1812
options:
1813
description: |
1316
- BioRIS options live under `enrichment.routing_dynamic.bioris`.
1814
+ BioRIS options live under `enrichment.routing_dynamic.bioris` in
1815
+ `netflow.yaml`.
1816
folding:
1817
title: Config options
1818
enabled: true
1822
default_value: "false"
1823
required: false
1824
- name: timeout
1326
- description: Connect + per-RPC timeout. Default is aggressive for public RIS over the internet -- raise if you see "deadline exceeded".
1825
+ description: Connect + per-RPC timeout for `GetRouters` and `ObserveRIB` setup. Default is aggressive; raise to 2-5s when reaching a remote bio-rd over the public internet.
1826
default_value: "200ms"
1827
required: false
1828
- name: refresh
1330
- description: How often to re-dump every router's RIB from scratch.
1829
+ description: Cadence at which the plugin re-runs `GetRouters` + `DumpRIB` for every router. Floored to 10s.
1830
default_value: "30m"
1831
required: false
1832
- name: refresh_timeout
1334
- description: Per-DumpRIB request timeout and per-message stream timeout.
1833
+ description: Per-DumpRIB request timeout and per-message stream timeout for the baseline RIB pull.
1834
default_value: "10s"
1835
required: false
1836
- name: ris_instances
1837
description: |
1339
- List of bio-rd endpoints. Each: grpc_addr, grpc_secure, vrf, vrf_id.
1340
- Multiple instances are additive (not failover) -- routes from all merge.
1838
+ List of bio-rd endpoints. Each entry: `grpc_addr` (`host:port` or full
1839
+ `http(s)://` URI), `grpc_secure` (TLS with system CAs when true), `vrf`
1840
+ (string VRF name to filter on), `vrf_id` (numeric VRF ID, alternative to
1841
+ `vrf`). Multiple instances are additive (not failover) -- routes from every
1842
+ instance merge into the same trie.
1843
default_value: "[]"
1844
required: true
1845
examples:
1876
- grpc_addr: "ris.example.internal:50051"
1877
grpc_secure: true
1878
vrf: "global"
1879
+ - name: Prefer BGP over the exporter's AS view
1880
+ folding:
1881
+ enabled: true
1882
+ description: |
1883
+ With the default provider chain, an exporter-supplied AS number wins over
1884
+ BGP. If your bio-rd feed is more accurate than what the exporter is
1885
+ stamping into flow records, reorder the chains so `routing` is consulted
1886
+ first.
1887
+ config: |
1888
+ enrichment:
1889
+ asn_providers: [routing, flow, geoip]
1890
+ net_providers: [routing, flow]
1891
+ routing_dynamic:
1892
+ bioris:
1893
+ enabled: true
1894
+ ris_instances:
1895
+ - grpc_addr: "127.0.0.1:50051"
1896
+ - name: Combined with BMP into a single trie
1897
+ folding:
1898
+ enabled: true
1899
+ description: |
1900
+ Run BMP from internal routers and BioRIS for an external (RIPE RIS) view.
1901
+ Both populate the same shared trie -- lookups pick the best-matching route
1902
+ across both sources at query time.
1903
+ config: |
1904
+ enrichment:
1905
+ routing_dynamic:
1906
+ bmp:
1907
+ enabled: true
1908
+ listen: "0.0.0.0:10179"
1909
+ bioris:
1910
+ enabled: true
1911
+ ris_instances:
1912
+ - grpc_addr: "127.0.0.1:50051"
1913
troubleshooting:
1914
problems:
1915
list:
1916
- name: Default 200ms timeout too aggressive
1917
description: |
1382
- Over the public internet to RIPE RIS, you may need 2-5 seconds. If you see
1383
- "deadline exceeded" errors in the journal, raise `timeout`.
1918
+ `timeout` covers the gRPC connect plus the `GetRouters` and `ObserveRIB`
1919
+ setup RPCs. Over the public internet to a remote bio-rd, 200ms is often not
1920
+ enough. If you see "deadline exceeded" errors in the journal, raise to 2-5s.
1921
+ `refresh_timeout` is separate and bounds the long-running `DumpRIB` and per-
1922
+ message stream reads (default 10s).
1923
- name: Initial dump takes minutes for full feeds
1924
description: |
1386
- A full IPv4+IPv6 RIB from a route collector is millions of prefixes. The first
1387
- refresh takes time; subsequent observe streams are incremental.
1388
- - name: Integration-test gap
1925
+ A full IPv4+IPv6 RIB from a route collector is millions of prefixes. The
1926
+ first `DumpRIB` after enabling (or after a plugin restart) takes time -- BGP
1927
+ attribution is incomplete until it finishes. Subsequent `ObserveRIB` streams
1928
+ are incremental.
1929
+ - name: Plugin restart wipes the trie
1930
+ description: |
1931
+ The trie is in-memory only -- restarting the netflow plugin loses every
1932
+ learned BGP route. Convergence over BioRIS depends on the upstream feed; a
1933
+ full DumpRIB from a RIPE RIS Route Collector can take minutes. Schedule
1934
+ restarts off-peak if BGP attribution matters for your workflow.
1935
+ - name: Memory growth without bound
1936
+ description: |
1937
+ The trie has no time-based eviction. Routes are removed only when the
1938
+ upstream BGP source withdraws them, when a router disappears from
1939
+ `GetRouters` between refreshes, or on plugin shutdown. A full feed is
1940
+ several hundred MB of RSS per peer, permanently.
1941
+ - name: AS path / communities missing on older queries
1942
+ description: |
1943
+ `DST_AS_PATH`, `DST_COMMUNITIES`, and `DST_LARGE_COMMUNITIES` only exist in
1944
+ the raw journal tier. The 1m / 5m / 1h rollup tiers do not carry them. Queries that span beyond the raw
1945
+ retention horizon will not return BGP path data.
1946
+ - name: AS path inconsistent with the exporter's view
1947
description: |
1390
- proto and route conversion are unit-tested. The gRPC client path
1391
- (connecting, consuming streams, retry/backoff) is NOT integration-tested.
1392
- Validate against your specific bio-rd setup before relying on this for
1393
- capacity / security decisions.
1948
+ Different vantage points see different BGP paths. If your flow exporter and
1949
+ the BGP source bio-rd is peering with are different boxes with different
1950
+ routing tables, expect divergence. This is normal in BGP, not a bug.
1951
+ - name: Validate BioRIS enrichment after enabling
1952
+ description: |
1953
+ BioRIS-derived enrichment depends on the bio-rd version, upstream BGP source,
1954
+ route visibility, and refresh cadence. Validate against your bio-rd setup
1955
+ before relying on this for capacity or security decisions.
1956
alerts: []
1957
metrics:
1958
folding:
1959
title: Metrics
1960
enabled: false
1961
description: |
1400
- Enriches flow records with the same fields as BMP (`SRC_AS`, `DST_AS`, masks,
1401
- `NEXT_HOP`, `DST_AS_PATH`, `DST_COMMUNITIES`, `DST_LARGE_COMMUNITIES`). Both
1402
- sources contribute to the same shared trie -- if both are enabled, lookups
1403
- prefer the best-matching route across both.
1962
+ Enriches flow records with the same fields as BMP: `SRC_AS`, `DST_AS`, `SRC_MASK`,
1963
+ `DST_MASK`, `NEXT_HOP`, `DST_AS_PATH`, `DST_COMMUNITIES`, `DST_LARGE_COMMUNITIES`.
1964
+ Source-side AS path and communities are not surfaced. AS names come from the
1965
+ GeoIP/ASN MMDB, not from BGP. AS path and communities are written only to the raw
1966
+ journal tier; rollup tiers do not carry them. When BMP and BioRIS are both
1967
+ enabled, they contribute to a single shared in-memory trie and lookups pick the
1968
+ best-matching route across both sources.
1969
availability: []
1970
scopes: []
1406
-
1407
- # =====================================================================
1408
- # Network Identity: external feeds that label your network prefixes
1409
- # =====================================================================
1410
-
1971
- meta:
1972
plugin_name: netflow-plugin
1973
module_name: aws-ip-ranges
1975
name: AWS IP Ranges
1976
link: https://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html
1977
categories:
1418
- - flows.network-identity
1978
+ - flows.enrichment-methods
1979
icon_filename: network-wired.svg
1980
keywords:
1981
- aws
1985
- vpc
1986
- ec2
1987
- prefix list
1988
+ - service tags
1989
related_resources:
1990
integrations:
1991
list:
2002
overview:
2003
data_collection:
2004
metrics_description: |
1444
- AWS publishes a continuously updated JSON file listing every public IP prefix used
1445
- by AWS services -- per region, per service. This integration fetches that file
1446
- periodically, transforms it via a jq expression, and uses the result to label flow
1447
- records destined to / from AWS with `*_NET_TENANT="amazon"` plus a per-region tag.
2005
+ Annotate network flows with AWS service and region labels from AWS public IP
2006
+ ranges. AWS publishes its current public IP allocations as a single JSON document at
2007
+ [`https://ip-ranges.amazonaws.com/ip-ranges.json`](https://ip-ranges.amazonaws.com/ip-ranges.json).
2008
+ The file lists every prefix AWS uses for a published service, tagged with the AWS
2009
+ region and the AWS service that owns the prefix (`AMAZON`, `EC2`, `S3`,
2010
+ `CLOUDFRONT`, `API_GATEWAY`, ...). This integration fetches the file periodically,
2011
+ transforms it via a jq expression, and labels matching flow records with provider,
2012
+ region, and service tags.
2013
+
2014
+ Once configured, traffic to / from AWS shows up in dashboards as `tenant=amazon`
2015
+ with per-region (`region=us-east-1`, `region=eu-central-1`, ...) and per-service
2016
+ (`role=s3`, `role=cloudfront`, ...) breakdown. This is **complementary to GeoIP
2017
+ and ASN enrichment**: instead of a flow being labeled simply `AS16509 Amazon`,
2018
+ it becomes labeled with the specific AWS service and region carrying the
2019
+ traffic -- without parsing AS-name strings.
2020
+
2021
+ The file is public; no AWS credentials are needed.
2022
1449
- The result: traffic to/from AWS shows up clearly in dashboards as "amazon", with
1450
- per-region and per-service breakdown if you customize the jq transform.
2023
+ Schema of `ip-ranges.json`:
2024
1452
- For the full network-identity concept (merge order, jq transform, TLS verification),
1453
- see [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment/network-identity).
2025
+ - top-level: `syncToken`, `createDate`, `prefixes`, `ipv6_prefixes`
2026
+ - each entry in `prefixes[]`: `ip_prefix`, `region`, `service`, `network_border_group`
2027
+ - each entry in `ipv6_prefixes[]`: `ipv6_prefix`, `region`, `service`, `network_border_group`
2028
+
2029
+ For the cross-cutting concepts (how multiple network sources merge, the lookup
2030
+ priority vs static `networks` config, TLS verification rules, the jq engine and
2031
+ its expected output schema, fetch loop and retry/backoff), see
2032
+ [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment).
2033
method_description: |
2034
The plugin issues a periodic GET to `https://ip-ranges.amazonaws.com/ip-ranges.json`,
1456
- parses the JSON body, runs the configured jq transform via the [jaq](https://github.com/01mf02/jaq)
1457
- library, and merges the resulting prefix-labeled rows into the network-attributes trie.
2035
+ parses the JSON body, runs the configured jq transform via the
2036
+ [jaq](https://github.com/01mf02/jaq) library, and merges the resulting
2037
+ prefix-labeled rows into the network-attributes trie shared by all enrichment
2038
+ sources.
2039
+
2040
+ AWS does not publish a fixed refresh cadence; the file is updated whenever the
2041
+ AWS IP space changes (typically several times per day) and the `syncToken` /
2042
+ `createDate` fields advance on every change. AWS recommends polling no faster
2043
+ than the file actually changes; daily is enough for most flow-attribution use
2044
+ cases. The plugin floors the configured `interval` at 60s.
2045
supported_platforms:
2046
include:
2047
- Linux
2051
description: ""
2052
default_behavior:
2053
auto_detection:
1467
- description: "Disabled by default. Add an entry under enrichment.network_sources to enable."
2054
+ description: "Disabled by default. Add an entry under `enrichment.network_sources` to enable."
2055
limits:
1469
- description: ""
2056
+ description: "One full AWS prefix document is fetched per refresh. Resource use scales with the number of AWS prefixes selected by your transform and the refresh interval."
2057
performance_impact:
1471
- description: ""
2058
+ description: "One HTTPS request per refresh interval plus a jq transform over the AWS prefix document. Runtime enrichment does prefix matching for source and destination IPs, and cost scales with the number of loaded network-source records."
2059
setup:
2060
prerequisites:
2061
list:
2062
- title: Outbound HTTPS to AWS
2063
description: |
2064
The agent host must be able to reach `https://ip-ranges.amazonaws.com/ip-ranges.json`.
1478
- No AWS credentials needed -- the file is public.
2065
+ No AWS credentials are needed -- the file is public.
2066
configuration:
2067
file:
2068
name: netflow.yaml
2069
options:
2070
description: |
1484
- Add a named entry under `enrichment.network_sources`. The `name` you choose appears
1485
- in flow records via the `*_NET_TENANT` field (when your jq transform sets it).
2071
+ Add a named entry under `enrichment.network_sources`. The map key (e.g. `aws`)
2072
+ is the source name; it is used in plugin logs but is **not** automatically
2073
+ attached to flow records -- the record labels come entirely from your `transform`
2074
+ output (`tenant`, `region`, `role`, `name`, `site`, `city`, `country`, `state`,
2075
+ `asn`, `asn_name`).
2076
+
2077
+ The expected `transform` output is a stream of objects, each carrying a `prefix`
2078
+ (CIDR string) plus any subset of the optional attribute fields. See the
2079
+ cross-cutting [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment)
2080
+ page for the full output schema.
2081
folding:
2082
title: Config options
2083
enabled: true
2084
list:
2085
- name: url
1491
- description: AWS publishes the master file at this URL.
2086
+ description: AWS publishes the master file at this URL. Use it as-is unless you mirror it locally for air-gapped environments.
2087
default_value: "https://ip-ranges.amazonaws.com/ip-ranges.json"
2088
required: true
2089
- name: interval
1495
- description: How often to fetch. AWS updates the file roughly every 15 minutes; daily is enough for most uses.
1496
- default_value: "60s (loop floor)"
2090
+ description: |
2091
+ How often to fetch the file. AWS updates the document whenever its IP space
2092
+ changes (often several times per day, sometimes more); daily is enough for
2093
+ most uses. The configured value is floored at 60s.
2094
+ default_value: "60s"
2095
required: false
2096
- name: timeout
1499
- description: Per-request timeout.
2097
+ description: Per-request timeout for the HTTPS GET.
2098
default_value: "60s"
2099
required: false
2100
+ - name: method
2101
+ description: HTTP method. AWS serves the file via GET; leave at the default.
2102
+ default_value: "GET"
2103
+ required: false
2104
+ - name: headers
2105
+ description: |
2106
+ Extra HTTP headers added to the request. Not required for the public AWS
2107
+ URL; only needed if you front the file behind your own authenticated mirror.
2108
+ default_value: "{}"
2109
+ required: false
2110
- name: transform
1503
- description: jq expression that converts the AWS response into objects with `prefix` and label fields.
2111
+ description: |
2112
+ jq expression (compiled by jaq) that converts the AWS JSON into a stream
2113
+ of `{prefix, ...}` objects. The default `.` does **not** match the AWS
2114
+ schema -- you must supply a real transform (see examples below) or fetches fail
2115
+ because output rows cannot be mapped to the required `{prefix, ...}` schema.
2116
default_value: "."
2117
required: true
2118
examples:
2120
title: Config
2121
enabled: true
2122
list:
1511
- - name: Tag all AWS prefixes by region and service
2123
+ - name: Tag all AWS prefixes by region and service (IPv4 + IPv6)
2124
folding:
2125
enabled: false
1514
- description: "Sets tenant=amazon, region=`aws-region`, role=`service-name`."
2126
+ description: |
2127
+ Recommended starting point. Sets `tenant=amazon`, `region=<aws-region>`,
2128
+ `role=<service-name-lowercased>`. Covers both `prefixes[]` and
2129
+ `ipv6_prefixes[]` in one stream so v4 and v6 traffic are tagged
2130
+ consistently.
2131
config: |
2132
enrichment:
2133
network_sources:
2145
- name: AWS S3 only
2146
folding:
2147
enabled: true
1532
- description: Filter to a single AWS service for narrower tagging.
2148
+ description: |
2149
+ Filter to a single AWS service for narrower tagging. Useful when you only
2150
+ care about identifying S3 traffic (e.g. egress-cost attribution).
2151
config: |
2152
enrichment:
2153
network_sources:
2163
role: "s3",
2164
region: .region
2165
}
2166
+ - name: Use network_border_group as the site label
2167
+ folding:
2168
+ enabled: true
2169
+ description: |
2170
+ AWS exposes a `network_border_group` field that distinguishes Local Zones
2171
+ / Wavelength Zones from the parent Region. Map it to the `site` attribute
2172
+ if you want that distinction visible in flow dashboards.
2173
+ config: |
2174
+ enrichment:
2175
+ network_sources:
2176
+ aws:
2177
+ url: "https://ip-ranges.amazonaws.com/ip-ranges.json"
2178
+ interval: 24h
2179
+ transform: |
2180
+ (.prefixes + .ipv6_prefixes)[] | {
2181
+ prefix: (.ip_prefix // .ipv6_prefix),
2182
+ tenant: "amazon",
2183
+ region: .region,
2184
+ site: .network_border_group,
2185
+ role: (.service | ascii_downcase)
2186
+ }
2187
troubleshooting:
2188
problems:
2189
list:
2190
+ - name: 'Default `transform: "."` fails because output rows are missing `prefix`'
2191
+ description: |
2192
+ The default `.` returns the raw JSON object, not the per-prefix stream the
2193
+ plugin expects. You **must** supply a transform that yields one object per
2194
+ prefix (with at least a `prefix` field). Use the first example above as your
2195
+ starting template.
2196
+ - name: AWS service name precedence inside one prefix
2197
+ description: |
2198
+ AWS sometimes lists the same `ip_prefix` under multiple `service` entries
2199
+ (e.g. once under `AMAZON` and again under `EC2`). The plugin merges all
2200
+ records into a single prefix trie, and the **last write wins** for a given
2201
+ prefix length. If you want a specific service to take precedence, filter the
2202
+ transform with `select(.service != "AMAZON")` so the broader catch-all
2203
+ entries are dropped.
2204
+ - name: Static `networks:` config silently overrides AWS labels
2205
+ description: |
2206
+ When a prefix is defined in both this source and `enrichment.networks`, the
2207
+ static config wins on every non-empty field. This is by design (operator
2208
+ intent overrides imported data) but can surprise operators who expect the
2209
+ remote feed to be authoritative. See the cross-cutting Network Identity page
2210
+ for the full lookup-priority rules.
2211
- name: Empty result from the transform is treated as failure
2212
description: |
1553
- If the jq filter happens to produce nothing (e.g., AWS responds with no prefixes),
1554
- the source backs off as if it errored. Check the journal for `network-sources` warnings.
2213
+ If the jq filter happens to produce nothing (bad selector, wrong field name,
2214
+ upstream JSON shape change), the source backs off as if it errored. Check
2215
+ the journal for `network-sources` warnings:
2216
+ `journalctl --namespace netdata | grep network-sources`.
2217
- name: TLS verification cannot be disabled
2218
description: |
2219
`tls.skip_verify: true` is rejected by validation. Use `tls.ca_file` for
1558
- custom-CA paths if needed.
2220
+ custom-CA paths if you front AWS behind an internal TLS-terminating proxy
2221
+ with a private CA.
2222
alerts: []
2223
metrics:
2224
folding:
2225
title: Metrics
2226
enabled: false
2227
description: |
1565
- Tags flow records with `SRC_NET_TENANT`, `*_NET_REGION`, `*_NET_ROLE`, etc. when
1566
- the source or destination IP matches an AWS prefix. Verify on the Network Flows
1567
- tab via the `*_NET_*` columns.
2228
+ This integration does not produce metrics. It enriches flow records with the
2229
+ following journal fields when a flow's source or destination IP matches an AWS
2230
+ prefix:
2231
+
2232
+ - `SRC_NET_NAME` / `DST_NET_NAME`
2233
+ - `SRC_NET_ROLE` / `DST_NET_ROLE`
2234
+ - `SRC_NET_SITE` / `DST_NET_SITE`
2235
+ - `SRC_NET_REGION` / `DST_NET_REGION`
2236
+ - `SRC_NET_TENANT` / `DST_NET_TENANT`
2237
+
2238
+ Plus, when the transform sets them, the country / state / city / ASN overrides
2239
+ documented on the Network Identity page. Verify on the Network Flows view via the
2240
+ `*_NET_*` columns or by filtering on `tenant=amazon`.
2241
availability: []
2242
scopes: []
1570
-
2243
- meta:
2244
plugin_name: netflow-plugin
2245
module_name: gcp-ip-ranges
2247
name: GCP IP Ranges
2248
link: https://cloud.google.com/compute/docs/faq#find_ip_range
2249
categories:
1578
- - flows.network-identity
2250
+ - flows.enrichment-methods
2251
icon_filename: network-wired.svg
2252
keywords:
2253
- gcp
2254
- google cloud
2255
+ - google
2256
- cloud
2257
- ip ranges
2258
+ - cloud.json
2259
+ - goog.json
2260
- prefix list
2261
+ - network identity
2262
related_resources:
2263
integrations:
2264
list:
2275
overview:
2276
data_collection:
2277
metrics_description: |
1602
- Google Cloud publishes its public IP prefixes at `https://www.gstatic.com/ipranges/cloud.json`,
1603
- updated periodically. This integration fetches the file and labels flow records
1604
- to/from Google Cloud with `*_NET_TENANT="gcp"` plus per-scope and per-service tags.
2278
+ Annotate network flows with Google ownership, service, and scope labels from
2279
+ Google public IP ranges. Google publishes its public IP ranges as two static JSON
2280
+ files served from `gstatic.com`. Wire one of them as a
2281
+ `network_source` and the netflow plugin fetches it periodically, transforms each
2282
+ prefix entry through your jq filter, and merges the resulting CIDR-keyed records
2283
+ into the network-attributes trie. Flows whose source or destination IP falls
2284
+ inside a Google-owned prefix are then labeled with `*_NET_TENANT`,
2285
+ `*_NET_REGION`, `*_NET_ROLE`, etc. according to the labels your transform emits.
2286
1606
- For the full network-identity concept, see
1607
- [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment/network-identity).
2287
+ Two upstream files exist and they are NOT interchangeable:
2288
+
2289
+ - **`https://www.gstatic.com/ipranges/cloud.json`** -- the prefixes used by
2290
+ Google Cloud (Compute Engine, GKE, Cloud Run, Cloud Functions, Cloud SQL,
2291
+ and the rest of Google Cloud Platform). This is what you almost always want
2292
+ for cloud-traffic attribution.
2293
+ - **`https://www.gstatic.com/ipranges/goog.json`** -- the broader Google IP
2294
+ space, including consumer-facing properties (Search, Gmail, YouTube, Google
2295
+ Workspace, Maps, Ads, etc.). It is a strict superset of `cloud.json` but
2296
+ **carries no service or region metadata** -- only the bare CIDRs.
2297
+
2298
+ For the cross-cutting network-identity behavior (merge order with GeoIP and
2299
+ static config, jq output contract, TLS rules, single-page fetch, failure /
2300
+ backoff handling), see
2301
+ [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment).
2302
method_description: |
1609
- Periodic HTTPS GET, jq transform, merge into network-attributes trie. Same mechanism
1610
- as AWS IP Ranges, different URL and JSON shape.
2303
+ Periodic HTTPS GET against the chosen `gstatic.com` URL. The body is parsed
2304
+ as JSON and the configured `transform` (a [jaq](https://github.com/01mf02/jaq)
2305
+ jq-equivalent expression) runs over the parsed value. Each output object is
2306
+ merged into the network-attributes trie keyed on its `prefix` field; remaining
2307
+ fields (`name`, `role`, `site`, `region`, `country`, `state`, `city`, `tenant`,
2308
+ `asn`, `asn_name`) populate the corresponding `*_NET_*` flow-record columns
2309
+ when a flow's IP matches the prefix.
2310
+
2311
+ The upstream files are static JSON snapshots, not pageable APIs -- one fetch
2312
+ per cycle is the whole dataset. Each contains a `syncToken` and a
2313
+ `creationTime` you can inspect to see when Google last regenerated them.
2314
+ The plugin fetches the full document on each refresh cycle.
2315
supported_platforms:
2316
include:
2317
- Linux
2323
auto_detection:
2324
description: "Disabled by default. Add an entry under enrichment.network_sources to enable."
2325
limits:
1622
- description: ""
2326
+ description: "One full GCP prefix document is fetched per refresh. Resource use scales with the number of GCP prefixes selected by your transform and the refresh interval."
2327
performance_impact:
1624
- description: ""
2328
+ description: |
2329
+ One short HTTPS GET per `interval`, plus a jq pass over the response.
2330
+ `cloud.json` is on the order of ~1000 prefix entries and the trie merge
2331
+ is bounded by that count; runtime cost is negligible against typical flow
2332
+ ingest. `goog.json` is similar in size.
2333
setup:
2334
prerequisites:
2335
list:
1628
- - title: Outbound HTTPS to Google
2336
+ - title: Outbound HTTPS to gstatic.com
2337
description: |
1630
- The agent host must be able to reach `https://www.gstatic.com/ipranges/cloud.json`.
1631
- No GCP credentials needed -- the file is public.
2338
+ The agent host must be able to reach `https://www.gstatic.com/ipranges/cloud.json`
2339
+ (or `goog.json`). The files are public CDN-served static JSON; no Google
2340
+ Cloud project, no service account, no API key, and no IAM permission is
2341
+ required.
2342
+ - title: Pick the right file for your use case
2343
+ description: |
2344
+ - Use `cloud.json` to attribute traffic to/from **Google Cloud Platform**
2345
+ services (Compute Engine VMs, GKE, Cloud Run, Cloud Functions, Cloud
2346
+ SQL, BigQuery API, Pub/Sub, GCS endpoints, etc.). Carries `service` and
2347
+ `scope` (region) per prefix.
2348
+ - Use `goog.json` to also catch **non-cloud Google traffic** (Gmail,
2349
+ YouTube, Google Workspace, Search, Ads, Maps, etc.). It carries no
2350
+ `service` or `scope` -- you only get "this is Google" attribution.
2351
+ - Configure both as separate sources if you want both attributions and
2352
+ a deterministic merge order between them. Within network-identity, more-
2353
+ specific prefixes win at lookup time, so a `cloud.json` match for a
2354
+ Compute Engine prefix will out-rank the broader `goog.json` umbrella.
2355
configuration:
2356
file:
2357
name: netflow.yaml
2358
options:
2359
description: |
1637
- Add a named entry under `enrichment.network_sources`.
2360
+ Add a named entry under `enrichment.network_sources`. The entry name is
2361
+ cosmetic (used in logs and metrics); the labels that end up in flow records
2362
+ come from the fields your `transform` emits.
2363
folding:
2364
title: Config options
2365
enabled: true
2366
list:
2367
- name: url
1643
- description: GCP publishes the master file here.
2368
+ description: |
2369
+ The Google IP-ranges JSON URL. Use `cloud.json` for GCP services or
2370
+ `goog.json` for the broader Google IP space.
2371
default_value: "https://www.gstatic.com/ipranges/cloud.json"
2372
required: true
2373
+ - name: interval
2374
+ description: |
2375
+ How often to refetch. Google does not publish a fixed cadence; their
2376
+ documentation states the lists are "published and updated frequently".
2377
+ Daily is plenty for most deployments and avoids hammering the CDN.
2378
+ default_value: "60s (loop floor)"
2379
+ required: false
2380
+ - name: timeout
2381
+ description: Per-request timeout.
2382
+ default_value: "60s"
2383
+ required: false
2384
- name: transform
1647
- description: jq expression mapping `prefixes[]` to `prefix` + label objects.
2385
+ description: |
2386
+ jq expression that converts each entry in `prefixes[]` into an object
2387
+ with a `prefix` field (CIDR string) plus any of the optional label
2388
+ fields (`name`, `role`, `site`, `region`, `country`, `state`, `city`,
2389
+ `tenant`, `asn`, `asn_name`). Required.
2390
default_value: "."
2391
required: true
2392
examples:
2394
title: Config
2395
enabled: true
2396
list:
1655
- - name: Tag all GCP prefixes by service and scope
2397
+ - name: GCP cloud.json -- tag Google Cloud prefixes by region
2398
folding:
2399
enabled: false
1658
- description: "Sets tenant=gcp, role=`service`, region=`scope`."
2400
+ description: |
2401
+ Tags every flow whose IP matches a Google Cloud prefix with
2402
+ `*_NET_TENANT="gcp"`, `*_NET_ROLE="google-cloud"`, and
2403
+ `*_NET_REGION` set to the GCP scope (`us-central1`, `europe-west1`,
2404
+ `global`, etc.). Both `ipv4Prefix` and `ipv6Prefix` entries are
2405
+ covered by the `// (slash-or)` fallback.
2406
config: |
2407
enrichment:
2408
network_sources:
2409
gcp:
2410
url: "https://www.gstatic.com/ipranges/cloud.json"
2411
interval: 24h
2412
+ timeout: 60s
2413
transform: |
2414
.prefixes[] | {
2415
prefix: (.ipv4Prefix // .ipv6Prefix),
2416
tenant: "gcp",
1669
- role: .service,
2417
+ role: "google-cloud",
2418
region: .scope
2419
}
1672
- troubleshooting:
1673
- problems:
1674
- list:
1675
- - name: Customer-only ranges
1676
- description: |
1677
- GCP also publishes a `goog.json` file (broader: includes Google services beyond
1678
- cloud). Use `cloud.json` for compute IP attribution; `goog.json` if you also
1679
- want to tag Google's other services.
1680
- alerts: []
1681
- metrics:
1682
- folding:
1683
- title: Metrics
1684
- enabled: false
1685
- description: |
1686
- Tags flow records with `*_NET_TENANT`, `*_NET_REGION`, `*_NET_ROLE`. Verify on the
1687
- Network Flows tab via the `*_NET_*` columns.
1688
- availability: []
1689
- scopes: []
1690
-
1691
- - meta:
1692
- plugin_name: netflow-plugin
2420
+ - name: GCP cloud.json -- IPv4 only
2421
+ folding:
2422
+ enabled: true
2423
+ description: |
2424
+ Same as above but skips the IPv6 prefixes (some operators only need
2425
+ IPv4 attribution and prefer to keep the trie smaller).
2426
+ config: |
2427
+ enrichment:
2428
+ network_sources:
2429
+ gcp-v4:
2430
+ url: "https://www.gstatic.com/ipranges/cloud.json"
2431
+ interval: 24h
2432
+ transform: |
2433
+ .prefixes[]
2434
+ | select(.ipv4Prefix)
2435
+ | {
2436
+ prefix: .ipv4Prefix,
2437
+ tenant: "gcp",
2438
+ role: "google-cloud",
2439
+ region: .scope
2440
+ }
2441
+ - name: Tag a single GCP region
2442
+ folding:
2443
+ enabled: true
2444
+ description: |
2445
+ Narrow the source to one region (here `us-central1`) so you can build
2446
+ dashboards that distinguish that region from the rest of GCP.
2447
+ config: |
2448
+ enrichment:
2449
+ network_sources:
2450
+ gcp-us-central1:
2451
+ url: "https://www.gstatic.com/ipranges/cloud.json"
2452
+ interval: 24h
2453
+ transform: |
2454
+ .prefixes[]
2455
+ | select(.scope == "us-central1")
2456
+ | {
2457
+ prefix: (.ipv4Prefix // .ipv6Prefix),
2458
+ tenant: "gcp",
2459
+ role: "google-cloud",
2460
+ region: "us-central1",
2461
+ site: "us-central1"
2462
+ }
2463
+ - name: Broader Google IP space (goog.json)
2464
+ folding:
2465
+ enabled: true
2466
+ description: |
2467
+ Use `goog.json` to also attribute traffic to non-Cloud Google services
2468
+ (Gmail, YouTube, Workspace, Search, Ads, Maps). The file has no
2469
+ `service` or `scope` fields, so only `tenant` / `role` are set.
2470
+ Configure this **alongside** `cloud.json` if you want both -- the more
2471
+ specific GCP prefixes from `cloud.json` will still win at lookup time.
2472
+ config: |
2473
+ enrichment:
2474
+ network_sources:
2475
+ google-all:
2476
+ url: "https://www.gstatic.com/ipranges/goog.json"
2477
+ interval: 24h
2478
+ transform: |
2479
+ .prefixes[] | {
2480
+ prefix: (.ipv4Prefix // .ipv6Prefix),
2481
+ tenant: "google",
2482
+ role: "google"
2483
+ }
2484
+ troubleshooting:
2485
+ problems:
2486
+ list:
2487
+ - name: cloud.json vs goog.json -- pick the right one
2488
+ description: |
2489
+ `cloud.json` is the Google Cloud Platform list (Compute Engine, GKE,
2490
+ Cloud Run, Cloud SQL, BigQuery, GCS, etc.) and carries `service` plus
2491
+ `scope` (region) per entry. `goog.json` is the broader Google list
2492
+ (consumer products: Gmail, YouTube, Workspace, Search, Ads, Maps) and
2493
+ carries **only the bare CIDRs** -- no service, no scope, no region.
2494
+ Using `goog.json` as if it were `cloud.json` will give you "this is
2495
+ Google" attribution but no per-region or per-service breakdown. Most
2496
+ operators want `cloud.json`; some configure both as separate sources.
2497
+ - name: No per-service breakdown from cloud.json
2498
+ description: |
2499
+ Today every entry in `cloud.json` reports `service: "Google Cloud"` --
2500
+ the file does not split prefixes by individual GCP service (Compute
2501
+ Engine vs GKE vs Cloud Run, etc.). Region (`scope`) is the dimension
2502
+ you can actually pivot on. Per-service attribution requires a different
2503
+ data source.
2504
+ - name: Empty result from the transform is treated as failure
2505
+ description: |
2506
+ If the jq expression yields zero objects (for example, an over-narrow
2507
+ `select()` that no entry passes), the source backs off as if the fetch
2508
+ had errored. Check the journal for `network-sources` warnings and verify
2509
+ your filter against a saved copy of `cloud.json`.
2510
+ - name: TLS verification cannot be disabled
2511
+ description: |
2512
+ `tls.skip_verify: true` (and `tls.verify: false`) are rejected by
2513
+ validation. `gstatic.com` is publicly trusted so this is rarely an issue
2514
+ for GCP; if you front the URL through an internal proxy with a private
2515
+ CA, supply it via `tls.ca_file`.
2516
+ - name: Update cadence is not contractual
2517
+ description: |
2518
+ Google states the lists are "published and updated frequently" but does
2519
+ not guarantee a fixed cadence. The `syncToken` and `creationTime` keys
2520
+ at the top of each file let you check when Google last regenerated it.
2521
+ Daily polling is a safe default; sub-hourly is unnecessary.
2522
+ alerts: []
2523
+ metrics:
2524
+ folding:
2525
+ title: Metrics
2526
+ enabled: false
2527
+ description: |
2528
+ Tags flow records with `SRC_NET_TENANT` / `DST_NET_TENANT`,
2529
+ `SRC_NET_REGION` / `DST_NET_REGION`, `SRC_NET_ROLE` / `DST_NET_ROLE`,
2530
+ and any other `*_NET_*` fields your transform emits, when the source or
2531
+ destination IP matches a Google prefix. Verify in the Network Flows view via
2532
+ the `*_NET_*` columns. Coordinates (`*_GEO_LATITUDE` / `*_GEO_LONGITUDE`)
2533
+ cannot be set from network-identity sources -- use the static `networks`
2534
+ block for those.
2535
+ availability: []
2536
+ scopes: []
2537
+ - meta:
2538
+ plugin_name: netflow-plugin
2539
module_name: azure-ip-ranges
2540
monitored_instance:
2541
name: Azure IP Ranges
2542
link: https://www.microsoft.com/en-us/download/details.aspx?id=56519
2543
categories:
1698
- - flows.network-identity
2544
+ - flows.enrichment-methods
2545
icon_filename: network-wired.svg
2546
keywords:
2547
- azure
2565
overview:
2566
data_collection:
2567
metrics_description: |
1722
- Azure publishes "Service Tags" data describing IP ranges per region and per service.
1723
- The Azure publication mechanism is **less convenient** than AWS / GCP -- the
1724
- authoritative URL contains a date stamp that changes weekly, so you cannot use
1725
- a single stable URL.
1726
-
1727
- For automated fetching, you have two options:
1728
- 1. Mirror the file in your own infrastructure (a script that resolves the latest
1729
- URL via the Azure CLI, downloads, and serves at a stable internal URL).
1730
- 2. Skip Azure IP Ranges entirely and rely on GeoIP / ASN data for Azure
1731
- attribution (Azure ASN is 8075).
1732
-
1733
- For the full network-identity concept, see
1734
- [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment/network-identity).
2568
+ Annotate network flows with Azure service and region labels from Azure Service
2569
+ Tags. Microsoft publishes Azure's public IP prefixes as **Service Tags JSON
2570
+ files**. A service tag is Microsoft's name for a group of IP prefixes belonging
2571
+ to one Azure service (e.g., `Storage`, `Sql`, `AzureFrontDoor.Backend`); the
2572
+ JSON enumerates every tag together with the prefixes, the platform, and -- for
2573
+ tags that support regional scope -- the Azure region.
2574
+
2575
+ Microsoft publishes four separate JSON files, one per Azure cloud:
2576
+
2577
+ - **Azure Public** -- commercial Azure, the file most users want.
2578
+ - **Azure US Government** -- separate cloud for US public-sector workloads.
2579
+ - **Microsoft Azure operated by 21Vianet** -- the China cloud.
2580
+ - **Azure Germany** -- legacy German cloud.
2581
+
2582
+ This integration tags flow records to/from Azure-hosted services with
2583
+ `*_NET_TENANT="azure"` plus per-region and per-service labels. Use it to
2584
+ identify traffic to Azure SQL, Azure Storage, Azure Front Door, App Service,
2585
+ and the rest -- without maintaining the prefix list yourself.
2586
+
2587
+ For the full network-identity concept (merge order, jq output shape, TLS
2588
+ verification, failure modes), see
2589
+ [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment).
2590
method_description: |
1736
- Periodic HTTPS GET against your stable mirror URL, jq transform, merge into
1737
- network-attributes trie. The plugin does not handle Azure's date-stamped URL
1738
- rotation -- you provide a stable URL via your own mirror.
2591
+ Periodic HTTPS GET against the Service Tags JSON, jq transform via the
2592
+ [jaq](https://github.com/01mf02/jaq) library, merge into the network-attributes
2593
+ trie. Same mechanism as AWS / GCP IP Ranges -- different URL and JSON shape,
2594
+ plus one important operational caveat documented below.
2595
supported_platforms:
2596
include:
2597
- Linux
2601
description: ""
2602
default_behavior:
2603
auto_detection:
1748
- description: "Disabled by default. Set up your own URL mirror, then add an entry under enrichment.network_sources."
2604
+ description: "Disabled by default. Add an entry under enrichment.network_sources to enable."
2605
limits:
1750
- description: ""
2606
+ description: "One full Azure Service Tags document is fetched per refresh. Resource use scales with the number of Azure prefixes selected by your transform and the refresh interval."
2607
performance_impact:
1752
- description: ""
2608
+ description: "One HTTPS request per refresh interval plus a jq transform over the Azure Service Tags document. Runtime enrichment does prefix matching for source and destination IPs, and cost scales with the number of loaded network-source records."
2609
setup:
2610
prerequisites:
2611
list:
1756
- - title: A stable URL for the Azure Service Tags JSON
2612
+ - title: Azure publishes weekly, but the URL rotates
2613
+ description: |
2614
+ Microsoft updates the Service Tags JSON **weekly** (per
2615
+ <https://learn.microsoft.com/en-us/azure/virtual-network/service-tags-overview#discover-service-tags-by-using-downloadable-json-files>:
2616
+ "These lists are updated and published weekly"), and Microsoft asks you
2617
+ to delay rolling out new prefixes for at least one week after publication
2618
+ ("When new IP addresses are added to service tags, they aren't used in
2619
+ Azure for at least one week").
2620
+
2621
+ The catch: the actual download URL is **not stable**. The download portal
2622
+ at <https://www.microsoft.com/en-us/download/details.aspx?id=56519> serves
2623
+ a `ServiceTags_Public_<YYYYMMDD>.json` filename whose date stamp changes
2624
+ every week. A naive `interval`-based fetch against last week's URL will
2625
+ start 404'ing as soon as a new file is published.
2626
+
2627
+ You have three reasonable options, in increasing order of effort:
2628
+
2629
+ 1. **Skip Azure IP Ranges entirely** and rely on GeoIP / ASN data
2630
+ (Microsoft's main ASN is 8075). Coarse but zero-maintenance.
2631
+ 2. **Use a stable redirect** if your environment provides one (some
2632
+ enterprise mirrors do).
2633
+ 3. **Run a small mirror script** -- a cron job that fetches the latest
2634
+ JSON via the [Service Tag Discovery REST API](https://learn.microsoft.com/en-us/rest/api/virtualnetwork/servicetags/list)
2635
+ (or `Get-AzNetworkServiceTag` in PowerShell) and writes the result to
2636
+ a stable path on an internal HTTP server. Point the plugin at that
2637
+ stable URL.
2638
+
2639
+ Option 3 is what most operators end up with. The Service Tag Discovery
2640
+ API is authoritative and authenticated (Azure subscription with read
2641
+ role); the downloadable JSON is unauthenticated but URL-rotated. Pick
2642
+ whichever fits your operational model.
2643
+ - title: Outbound HTTPS to your mirror (or to Microsoft, if you script the URL discovery)
2644
description: |
1758
- Azure's authoritative URL embeds a date stamp that changes weekly. A simple
1759
- workaround: a cron job that calls
1760
- `az network list-service-tags --location global -o json` (Azure CLI) and
1761
- writes the result to a stable path on an internal HTTP server. The plugin then
1762
- fetches from that stable URL.
1763
- - title: Outbound HTTPS to your mirror
2645
+ The plugin only needs to reach the configured `url`. Azure credentials
2646
+ are needed only on the side that resolves "what's this week's URL?" --
2647
+ not by the plugin itself.
2648
+ - title: A jq transform that matches the Service Tags schema
2649
description: |
1765
- No Azure credentials needed by the plugin itself; credentials only matter on
1766
- the side that does the upstream Azure CLI call.
2650
+ The Service Tags JSON has a nested shape:
2651
+
2652
+ ```text
2653
+ {
2654
+ "changeNumber": 123,
2655
+ "cloud": "Public",
2656
+ "values": [
2657
+ {
2658
+ "name": "Storage.WestUS",
2659
+ "id": "Storage.WestUS",
2660
+ "properties": {
2661
+ "changeNumber": 456,
2662
+ "region": "westus",
2663
+ "regionId": 30,
2664
+ "platform": "Azure",
2665
+ "systemService": "AzureStorage",
2666
+ "addressPrefixes": ["13.105.16.4/30", "20.150.0.0/17", ...],
2667
+ "networkFeatures": ["API", "NSG"]
2668
+ }
2669
+ },
2670
+ ...
2671
+ ]
2672
+ }
2673
+ ```
2674
+
2675
+ The transform must unwrap `values[]` -> `properties.addressPrefixes[]`
2676
+ and emit one object per prefix. Schema reference: `values[].name`,
2677
+ `values[].id`,
2678
+ `values[].properties.region` (region tag, can be empty for
2679
+ cloud-wide tags like the bare `Storage`), `values[].properties.platform`,
2680
+ `values[].properties.systemService` (e.g. `AzureStorage`, `AzureSql`),
2681
+ `values[].properties.addressPrefixes[]` (CIDR strings, IPv4 and IPv6
2682
+ mixed). Top-level `changeNumber` increments on every publication.
2683
configuration:
2684
file:
2685
name: netflow.yaml
2686
options:
2687
description: |
1772
- Add a named entry under `enrichment.network_sources` pointing at your mirror URL.
2688
+ Add a named entry under `enrichment.network_sources` pointing at your
2689
+ stable mirror URL (or, with the limitations above, at this week's
2690
+ `ServiceTags_Public_<date>.json` URL).
2691
folding:
2692
title: Config options
2693
enabled: true
2694
list:
2695
- name: url
1778
- description: Stable URL to your locally-mirrored Azure Service Tags JSON.
2696
+ description: Stable URL to your locally-mirrored Azure Service Tags JSON, or this week's date-stamped Microsoft URL.
2697
default_value: ""
2698
required: true
2699
+ - name: interval
2700
+ description: How often to fetch. Microsoft publishes weekly; daily is plenty.
2701
+ default_value: "60s (loop floor)"
2702
+ required: false
2703
+ - name: timeout
2704
+ description: Per-request timeout. Service Tags JSON files are large (tens of MB) -- give it room.
2705
+ default_value: "60s"
2706
+ required: false
2707
- name: transform
1782
- description: jq expression mapping the values[] array to per-prefix objects.
2708
+ description: jq expression that maps `values[].properties.addressPrefixes[]` into per-prefix objects.
2709
default_value: "."
2710
required: true
2711
examples:
2713
title: Config
2714
enabled: true
2715
list:
1790
- - name: Internal mirror of Azure Service Tags
2716
+ - name: Azure Public via internal mirror -- tag by region and service
2717
folding:
2718
enabled: false
1793
- description: Tag every Azure prefix with tenant=azure plus region/service.
2719
+ description: |
2720
+ Internal mirror serving the latest Public-cloud Service Tags JSON.
2721
+ Tags every Azure prefix with `tenant=azure`, the region, and the
2722
+ lowercase systemService name as the role.
2723
config: |
2724
enrichment:
2725
network_sources:
2726
azure:
2727
+ url: "https://internal.example/azure-service-tags.json"
2728
+ interval: 24h
2729
+ timeout: 60s
2730
+ transform: |
2731
+ .values[]
2732
+ | .properties as $p
2733
+ | $p.addressPrefixes[]
2734
+ | {
2735
+ prefix: .,
2736
+ tenant: "azure",
2737
+ region: ($p.region // ""),
2738
+ role: (($p.systemService // "") | ascii_downcase)
2739
+ }
2740
+ - name: Azure Storage only
2741
+ folding:
2742
+ enabled: true
2743
+ description: Filter to a single Azure systemService for narrower tagging.
2744
+ config: |
2745
+ enrichment:
2746
+ network_sources:
2747
+ azure-storage:
2748
url: "https://internal.example/azure-service-tags.json"
2749
interval: 24h
2750
transform: |
2751
.values[]
1802
- | .id as $id
1803
- | .properties.region as $region
1804
- | (.properties.systemService // "") as $service
1805
- | .properties.addressPrefixes[]
2752
+ | select(.properties.systemService == "AzureStorage")
2753
+ | .properties as $p
2754
+ | $p.addressPrefixes[]
2755
| {
2756
prefix: .,
2757
tenant: "azure",
1809
- region: ($region // ""),
1810
- role: ($service | ascii_downcase)
2758
+ role: "storage",
2759
+ region: ($p.region // "")
2760
+ }
2761
+ - name: Azure US Government cloud
2762
+ folding:
2763
+ enabled: true
2764
+ description: |
2765
+ The US Government cloud is published as a separate JSON file with its
2766
+ own download ID (57063). Same schema as the Public cloud; tag tenant
2767
+ differently so you can tell them apart in dashboards.
2768
+ config: |
2769
+ enrichment:
2770
+ network_sources:
2771
+ azure-usgov:
2772
+ url: "https://internal.example/azure-service-tags-usgov.json"
2773
+ interval: 24h
2774
+ transform: |
2775
+ .values[]
2776
+ | .properties as $p
2777
+ | $p.addressPrefixes[]
2778
+ | {
2779
+ prefix: .,
2780
+ tenant: "azure-usgov",
2781
+ region: ($p.region // ""),
2782
+ role: (($p.systemService // "") | ascii_downcase)
2783
}
2784
troubleshooting:
2785
problems:
2786
list:
1815
- - name: Empty results
2787
+ - name: 404 a week after deploy
2788
+ description: |
2789
+ You configured `url` against `ServiceTags_Public_<date>.json` directly.
2790
+ Microsoft rotates the date stamp weekly, so the URL stops resolving
2791
+ within a week. Move to an internal mirror that resolves the latest URL
2792
+ each cycle, or to the Service Tag Discovery REST API
2793
+ (<https://learn.microsoft.com/en-us/rest/api/virtualnetwork/servicetags/list>)
2794
+ fed into a static file.
2795
+ - name: Empty results from the transform
2796
description: |
1817
- The Azure Service Tags JSON has nested structure (`values[].properties.addressPrefixes[]`).
1818
- If your jq doesn't unwrap correctly, every fetch yields zero rows and the source
1819
- backs off. Test the jq locally with `jq < azure-service-tags.json`.
2797
+ The Service Tags JSON is nested two levels deep
2798
+ (`values[].properties.addressPrefixes[]`). If the jq doesn't unwrap
2799
+ both levels, every fetch yields zero rows and the source backs off as if
2800
+ it errored. Test the jq locally with `jq < azure-service-tags.json` and
2801
+ confirm at least one `{prefix, tenant, ...}` object comes out.
2802
+ - name: Service Tag API data lags the JSON file
2803
+ description: |
2804
+ Per Microsoft's note on the Service Tags overview page, "It takes up to
2805
+ four weeks for new Service Tag data to propagate in the API results
2806
+ across all Azure regions". If you mirror via the REST API, expect newly
2807
+ added tags to appear in the JSON download a few weeks before the API,
2808
+ not the other way around. For prefix tagging this rarely matters; for
2809
+ firewall rules it can.
2810
+ - name: TLS verification cannot be disabled
2811
+ description: |
2812
+ `tls.skip_verify: true` is rejected by validation. Use `tls.ca_file`
2813
+ for custom-CA paths (e.g., on an internal mirror with a private CA).
2814
alerts: []
2815
metrics:
2816
folding:
2817
title: Metrics
2818
enabled: false
2819
description: |
1826
- Tags flow records to/from Azure with `*_NET_TENANT`, `*_NET_REGION`, `*_NET_ROLE`.
2820
+ Tags flow records with `*_NET_TENANT`, `*_NET_REGION`, `*_NET_ROLE` when the
2821
+ source or destination IP matches an Azure prefix. Verify on the Network Flows
2822
+ tab via the `*_NET_*` columns. Country / state / city overrides
2823
+ (`*_COUNTRY`, `*_GEO_STATE`, `*_GEO_CITY`) are also available if your
2824
+ transform sets them, but Service Tags don't carry country/state/city data --
2825
+ only `region` codes like `westus` or `northeurope`.
2826
availability: []
2827
scopes: []
1829
-
2828
- meta:
2829
plugin_name: netflow-plugin
2830
module_name: netbox
2831
monitored_instance:
2832
name: NetBox
1835
- link: https://netboxlabs.com/oss/netbox/
2833
+ link: https://github.com/netbox-community/netbox
2834
categories:
1837
- - flows.network-identity
2835
+ - flows.enrichment-methods
2836
icon_filename: network-wired.svg
2837
keywords:
2838
- netbox
2840
- dcim
2841
- source of truth
2842
- prefix list
2843
+ - network identity
2844
related_resources:
2845
integrations:
2846
list:
2857
overview:
2858
data_collection:
2859
metrics_description: |
1861
- [NetBox](https://netboxlabs.com/oss/netbox/) is the most widely deployed open-source
1862
- IPAM / DCIM. Many networks already curate prefix metadata there -- tenant, site,
1863
- role, VRF -- and want flow data to inherit those labels automatically rather than
1864
- duplicating them in `netflow.yaml`.
2860
+ Annotate network flows with tenant, site, role, VRF, and description metadata
2861
+ from NetBox. [NetBox](https://github.com/netbox-community/netbox) is the most
2862
+ widely deployed open-source IPAM / DCIM. It is Apache-2.0 licensed and maintained
2863
+ by the netbox-community organization (commercial variants -- NetBox Cloud and
2864
+ NetBox Enterprise -- are offered by NetBox Labs on top of the same upstream code).
2865
+ Operators already curate prefix metadata in NetBox and want flow records to
2866
+ inherit those labels automatically rather than maintaining a parallel list in
2867
+ `netflow.yaml`.
2868
1866
- This integration polls NetBox's Prefixes API at a configurable interval, transforms
1867
- the response with jq, and labels flow records with the prefix metadata.
2869
+ This integration polls NetBox's Prefixes REST API at a configurable interval,
2870
+ transforms the response with jq, and labels matching flow prefixes with whatever
2871
+ fields you map. NetBox is the authoritative source -- when the same prefix is
2872
+ tagged in NetBox and in the static `networks:` block, the static block wins
2873
+ (operator override is intentional, see the
2874
+ [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment)
2875
+ concept page).
2876
1869
- For the full network-identity concept, see
1870
- [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment/network-identity).
2877
+ Use cases: applying your organisation's data-centre rack labels, tenant names,
2878
+ environment tags (prod / staging / dev), and VRF / site identifiers to flows so
2879
+ dashboards and queries surface "this is the staging tier in fra1" instead of a
2880
+ raw CIDR.
2881
method_description: |
1872
- Periodic HTTPS GET to a NetBox API endpoint with a Bearer token in the
1873
- `Authorization` header. jq transform produces per-prefix objects with the labels
1874
- you want -- typically `tenant.name`, `site.name`, `role.name`, `description`.
2882
+ Periodic HTTPS GET to `/api/ipam/prefixes/` on your NetBox host. Authentication is
2883
+ a NetBox API token in the `Authorization` header. NetBox supports two token
2884
+ formats:
2885
1876
- NetBox paginates results -- there is **no automatic pagination** in this plugin.
1877
- For inventories larger than the default page size (50), wrap NetBox with a
2886
+ - **Legacy v1 tokens** (`Authorization: Token <token>`) -- accepted by all NetBox
2887
+ versions, simplest to wire up.
2888
+ - **v2 tokens** (NetBox 4.x, `Authorization: Bearer nbt_<key>.<token>`) -- the
2889
+ prefix `nbt_` and the random key are concatenated with the token via a dot.
2890
+
2891
+ The plugin transports either format -- the value is whatever NetBox issued for the
2892
+ service account.
2893
+
2894
+ The plugin runs the configured `transform` (jaq -- a jq-equivalent) over the
2895
+ parsed JSON body and produces per-prefix objects. NetBox's response is paginated;
2896
+ the plugin does **not** follow `next` links. Pass `?limit=0` (NetBox 4.x default
2897
+ `MAX_PAGE_SIZE` is 1000; setting `0` removes the cap when the server config
2898
+ allows) or an explicit `?limit=N` greater than your prefix count, or expose a
2899
server-side aggregator that returns the full list at one URL.
2900
supported_platforms:
2901
include:
2906
description: ""
2907
default_behavior:
2908
auto_detection:
1888
- description: "Disabled by default. Add an entry under enrichment.network_sources with your NetBox URL and API token."
2909
+ description: "Disabled by default. Add an entry under `enrichment.network_sources` with your NetBox URL and API token."
2910
limits:
1890
- description: ""
2911
+ description: "Resource use scales with the number of NetBox prefixes returned by the URL and transform. Use NetBox filtering when you only need a subset of VRFs, sites, tenants, or roles."
2912
performance_impact:
1892
- description: ""
2913
+ description: "One HTTP request per refresh interval plus a jq transform over the response. Runtime enrichment does prefix matching for source and destination IPs, and cost scales with the number of loaded network-source records."
2914
setup:
2915
prerequisites:
2916
list:
2917
- title: NetBox API token with read scope on Prefixes
2918
description: |
1898
- In NetBox, create or use a service account, generate an API token, scope it
1899
- read-only to the Prefixes endpoint. The token goes in the `Authorization` header.
1900
- - title: A bulk endpoint or aggregator
2919
+ In NetBox, create or reuse a service-account user, then generate an API token
2920
+ under "Admin > Users > Tokens". Restrict the token to read-only and (for
2921
+ v4.x) limit the scope to `ipam.view_prefix`. The token value goes in the
2922
+ `Authorization` header.
2923
+
2924
+ The plugin only reads -- never writes -- so a read-only token is sufficient
2925
+ and recommended. Token format depends on the NetBox version:
2926
+
2927
+ - NetBox 3.x or earlier: `Token <40-char-hex>` (legacy).
2928
+ - NetBox 4.x: either legacy `Token <hex>` or new `Bearer nbt_<key>.<token>`
2929
+ (v2 tokens, opt-in).
2930
+ - title: Bulk endpoint (`?limit=0` or aggregator)
2931
+ description: |
2932
+ The plugin fetches a single page. NetBox's default `PAGINATE_COUNT` is 50
2933
+ and `MAX_PAGE_SIZE` is 1000. For inventories above 1000 prefixes, either
2934
+ raise `MAX_PAGE_SIZE` server-side and pass `?limit=0`, or expose an internal
2935
+ aggregator endpoint that walks pagination and returns the full list at one URL.
2936
+ - title: NetBox version-aware field mapping
2937
description: |
1902
- The plugin does not paginate. If your NetBox has more prefixes than fit in the
1903
- default page (`?limit=50`), either raise `limit` (`?limit=10000`) or expose
1904
- an internal endpoint that aggregates all pages and serves them at one URL.
2938
+ NetBox **4.2** replaced the per-prefix `site` foreign key with a generic
2939
+ `scope` field (a prefix can now be scoped to a region, site group, site, or
2940
+ location -- not just a site). API responses on 4.2+ omit `site` and expose
2941
+ `scope` (read-only) plus `scope_type` / `scope_id`. Adjust your jq accordingly
2942
+ -- on 4.2+ use `(.scope.name // "")`, on 4.1 and earlier use
2943
+ `(.site.name // "")`.
2944
configuration:
2945
file:
2946
name: netflow.yaml
2947
options:
2948
description: |
2949
Add a named entry under `enrichment.network_sources` pointing at your NetBox.
2950
+ The network source configuration accepts `url`, `method`,
2951
+ `headers`, `proxy`, `tls`, `timeout`, `interval`, and `transform`. Authentication
2952
+ is configured via the generic `headers:` map -- there is no NetBox-specific
2953
+ auth helper.
2954
folding:
2955
title: Config options
2956
enabled: true
2957
list:
2958
- name: url
1916
- description: NetBox Prefixes API endpoint, with `?limit=` if needed.
2959
+ description: NetBox prefixes API endpoint, including `?limit=` (recommend `?limit=0` on 4.x for full inventory in one shot).
2960
default_value: ""
2961
required: true
2962
- name: headers.Authorization
1920
- description: NetBox API token, prefixed with "Token ".
2963
+ description: 'NetBox API token. Use `Token <hex>` for legacy v1 or `Bearer nbt_<key>.<token>` for v4.x v2 tokens.'
2964
default_value: ""
2965
required: true
2966
- name: interval
1924
- description: How often to refresh. NetBox is your source of truth -- 5-15 minutes is typical.
2967
+ description: How often to refresh. NetBox is your source of truth; 5 minutes is typical for IPAMs that change frequently, 1 hour is fine for static inventories.
2968
default_value: "60s"
2969
required: false
2970
+ - name: timeout
2971
+ description: HTTP request timeout. Bump to 30-60s if your NetBox returns thousands of prefixes in one shot.
2972
+ default_value: "10s"
2973
+ required: false
2974
- name: transform
1928
- description: jq expression mapping `.results[]` (NetBox's response shape) to per-prefix objects.
2975
+ description: jq expression mapping NetBox's `.results[]` to per-prefix objects with `prefix` and any of `name`, `role`, `site`, `region`, `country`, `state`, `city`, `tenant`, `asn`, `asn_name`.
2976
default_value: "."
2977
required: true
2978
+ - name: tls.ca_file
2979
+ description: Path to your internal CA bundle when NetBox runs behind internal PKI. Disabling verification is rejected by the validator -- use this instead.
2980
+ default_value: ""
2981
+ required: false
2982
examples:
2983
folding:
2984
title: Config
2985
enabled: true
2986
list:
1936
- - name: NetBox with API token and standard label set
2987
+ - name: NetBox 4.x with v2 token, scope-aware mapping
2988
folding:
2989
enabled: false
1939
- description: Tags prefixes with tenant, site, role, and the NetBox description.
2990
+ description: |
2991
+ Standard NetBox 4.2+ wiring. Maps tenant, role, the new `scope` field
2992
+ (covers site / region / site-group / location), and the human-readable
2993
+ description. `?limit=0` returns all prefixes in one call when
2994
+ `MAX_PAGE_SIZE` is unset on the NetBox server.
2995
config: |
2996
enrichment:
2997
network_sources:
2998
netbox:
1944
- url: "https://netbox.example.internal/api/ipam/prefixes/?limit=10000"
2999
+ url: "https://netbox.example.internal/api/ipam/prefixes/?limit=0"
3000
headers:
1946
- Authorization: "Token abcdef0123456789"
3001
+ Authorization: "Bearer nbt_AbCdEf0123456789.GhIjKl0123456789"
3002
interval: 5m
3003
timeout: 30s
3004
transform: |
3005
.results[] | {
3006
prefix: .prefix,
3007
tenant: (.tenant.name // ""),
1953
- site: (.site.name // ""),
1954
- role: (.role.name // ""),
1955
- name: .description
3008
+ role: (.role.name // ""),
3009
+ site: (.scope.name // ""),
3010
+ name: (.description // "")
3011
}
1957
- - name: NetBox with mTLS to internal CA
3012
+ - name: NetBox 3.x / 4.0 / 4.1 with legacy site field
3013
folding:
3014
enabled: true
1960
- description: When NetBox is behind your internal PKI; use tls.ca_file plus client cert.
3015
+ description: |
3016
+ Pre-4.2 NetBox still exposes `site` directly on the Prefix object. Use a
3017
+ legacy `Token` header and read `.site.name` instead of `.scope.name`.
3018
config: |
3019
enrichment:
3020
network_sources:
3021
netbox:
3022
url: "https://netbox.example.internal/api/ipam/prefixes/?limit=10000"
3023
headers:
1967
- Authorization: "Token abcdef0123456789"
3024
+ Authorization: "Token abcdef0123456789abcdef0123456789abcdef01"
3025
+ interval: 15m
3026
+ transform: |
3027
+ .results[] | {
3028
+ prefix: .prefix,
3029
+ tenant: (.tenant.name // ""),
3030
+ role: (.role.name // ""),
3031
+ site: (.site.name // ""),
3032
+ name: (.description // "")
3033
+ }
3034
+ - name: NetBox behind internal PKI (mTLS)
3035
+ folding:
3036
+ enabled: true
3037
+ description: |
3038
+ When NetBox is fronted by internal PKI. `tls.verify: false` is rejected at
3039
+ config-load -- supply your CA explicitly and (optionally) a client
3040
+ certificate.
3041
+ config: |
3042
+ enrichment:
3043
+ network_sources:
3044
+ netbox:
3045
+ url: "https://netbox.example.internal/api/ipam/prefixes/?limit=0"
3046
+ headers:
3047
+ Authorization: "Token abcdef0123456789abcdef0123456789abcdef01"
3048
interval: 5m
3049
tls:
3050
enable: true
3055
.results[] | {
3056
prefix: .prefix,
3057
tenant: (.tenant.name // ""),
1978
- site: (.site.name // ""),
1979
- role: (.role.name // ""),
1980
- name: .description
3058
+ role: (.role.name // ""),
3059
+ site: (.scope.name // ""),
3060
+ name: (.description // "")
3061
+ }
3062
+ - name: VRF-aware mapping (multi-tenant networks)
3063
+ folding:
3064
+ enabled: true
3065
+ description: |
3066
+ When the same RFC1918 prefix appears in multiple VRFs, fold the VRF name
3067
+ into the friendly `name` so dashboards disambiguate. Note: the plugin keys
3068
+ on `prefix` only -- if two rows share a CIDR, the last one wins. Filter the
3069
+ NetBox query (`?vrf_id=N`) to scope the export.
3070
+ config: |
3071
+ enrichment:
3072
+ network_sources:
3073
+ netbox-prod-vrf:
3074
+ url: "https://netbox.example.internal/api/ipam/prefixes/?limit=0&vrf_id=12"
3075
+ headers:
3076
+ Authorization: "Token abcdef0123456789abcdef0123456789abcdef01"
3077
+ interval: 5m
3078
+ transform: |
3079
+ .results[] | {
3080
+ prefix: .prefix,
3081
+ tenant: (.tenant.name // ""),
3082
+ role: (.role.name // ""),
3083
+ site: (.scope.name // ""),
3084
+ name: ((.vrf.name // "default") + ": " + (.description // ""))
3085
}
3086
troubleshooting:
3087
problems:
3088
list:
1985
- - name: Only first page of results loaded
3089
+ - name: Only first 50 prefixes loaded
3090
description: |
1987
- NetBox paginates by default at 50 results. The plugin does not follow `next`
1988
- links. Use `?limit=10000` (or the actual count) on the URL, or expose an
1989
- aggregating endpoint server-side.
1990
- - name: Token missing or wrong scope
3091
+ NetBox's default `PAGINATE_COUNT` is 50 and the plugin does not follow `next`
3092
+ links. Pass `?limit=0` (NetBox 4.x removes the cap when `MAX_PAGE_SIZE` is
3093
+ `0` server-side) or `?limit=N` larger than your inventory. For inventories
3094
+ above the server's `MAX_PAGE_SIZE` (default 1000), expose a server-side
3095
+ aggregator endpoint.
3096
+ - name: 401 / 403 from NetBox
3097
description: |
1992
- NetBox returns 403 silently consumed by the plugin's HTTP error path. Watch
1993
- the journal for `network-sources` warnings; verify with curl:
3098
+ Token missing, expired, or wrong format. Verify with:
3099
`curl -H "Authorization: Token <tok>" https://netbox/api/ipam/prefixes/`.
3100
+ On NetBox 4.x check whether the token is v1 (`Token <hex>`) or v2
3101
+ (`Bearer nbt_<key>.<token>`) and use the matching header. Watch the journal
3102
+ for `network-sources` warnings -- HTTP errors are logged there as
3103
+ refresh-failed warnings.
3104
+ - name: site is empty after upgrade to NetBox 4.2
3105
+ description: |
3106
+ NetBox 4.2 removed `site` from the Prefix model and replaced it with `scope`
3107
+ (a generic foreign key that can reference region / site group / site /
3108
+ location). Update the jq from `(.site.name // "")` to `(.scope.name // "")`.
3109
+ Alternatively, key on `(.scope.name // .site.name // "")` so the same config
3110
+ works across the upgrade boundary.
3111
+ - name: VRF collisions (same CIDR in multiple VRFs)
3112
+ description: |
3113
+ The plugin's network-attributes trie keys on `prefix` only -- there is no VRF
3114
+ dimension on the flow side. If NetBox lists `10.0.0.0/24` in three VRFs, only
3115
+ the last row wins. Filter the export with `?vrf_id=N` per data-plane and run
3116
+ one named source per VRF, or fold the VRF name into the friendly `name` so
3117
+ dashboards disambiguate.
3118
+ - name: Empty result triggers backoff
3119
+ description: |
3120
+ An empty `results` array (legitimate state for a freshly-installed NetBox)
3121
+ is treated as a fetch failure by the cross-cutting source loop and triggers
3122
+ exponential backoff. Add at least one synthetic prefix (e.g. a `RFC1918`
3123
+ container) so the response is never empty.
3124
alerts: []
3125
metrics:
3126
folding:
3127
title: Metrics
3128
enabled: false
3129
description: |
2001
- Tags flow records with the labels you mapped from NetBox -- typically `*_NET_TENANT`,
2002
- `*_NET_SITE`, `*_NET_ROLE`, `*_NET_NAME`. Verify on the Network Flows tab.
3130
+ Tags flow records with the labels you mapped from NetBox -- typically
3131
+ `*_NET_TENANT`, `*_NET_SITE`, `*_NET_ROLE`, `*_NET_NAME`. Verify on the Network
3132
+ Flows tab.
3133
availability: []
3134
scopes: []
2005
-
3135
- meta:
3136
plugin_name: netflow-plugin
3137
module_name: generic-ipam
3138
monitored_instance:
3139
name: Generic JSON-over-HTTP IPAM
2011
- link: https://learn.netdata.cloud/docs/network-flows/enrichment/network-identity
3140
+ link: https://learn.netdata.cloud/docs/network-flows/enrichment
3141
categories:
2013
- - flows.network-identity
3142
+ - flows.enrichment-methods
3143
icon_filename: network-wired.svg
3144
keywords:
3145
- ipam
3147
- infoblox
3148
- bluecat
3149
- phpipam
3150
+ - servicenow
3151
- custom
3152
- prefix list
3153
+ - network identity
3154
related_resources:
3155
integrations:
3156
list:
3167
overview:
3168
data_collection:
3169
metrics_description: |
2039
- The catch-all integration. Any IPAM, CMDB, or service that exposes prefix metadata
2040
- via an HTTP-fetchable JSON endpoint can plug into Netdata's flow enrichment via this
2041
- mechanism. Examples: Infoblox WAPI, BlueCat REST API, phpIPAM, internal-built CMDB
2042
- endpoints, ServiceNow CMDB queries, custom Lambda functions producing JSON.
3170
+ Annotate network flows with network-identity labels from any JSON-over-HTTP IPAM
3171
+ or CMDB endpoint. The plugin does not care WHO produces the JSON -- it cares
3172
+ about the JSON shape after your `transform` (a jq expression) runs over it.
3173
+ Examples: Infoblox WAPI, BlueCat REST API, phpIPAM, ServiceNow CMDB queries, an
3174
+ internal aggregator, a Lambda function, a static file served from S3, a
3175
+ hand-rolled CMDB.
3176
2044
- You define the URL, the HTTP method, headers (for auth), and a jq transform that
2045
- converts the response into objects with `prefix` + label fields.
3177
+ This card is also the **reference description** of how all the other Network
3178
+ Identity cards work under the hood. AWS IP Ranges, GCP IP Ranges, Azure IP Ranges
3179
+ and NetBox are all special-cased instances of this same mechanism: each is just
3180
+ a known URL plus a recommended jq `transform`. Read this card to understand the
3181
+ generic shape, then read the per-source cards for the URL and transform that fit
3182
+ that specific provider.
3183
2047
- For the full network-identity concept, see
2048
- [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment/network-identity).
3184
+ For the full network-identity concept (merge order vs GeoIP and static, what
3185
+ fields you can populate, why TLS verification cannot be disabled), see
3186
+ [Network Identity](https://learn.netdata.cloud/docs/network-flows/enrichment).
3187
method_description: |
2050
- Periodic HTTPS GET (or POST) to a configured URL with optional headers, optional
2051
- custom CA / mTLS, jq transform of the response, merge into network-attributes trie.
3188
+ The plugin issues a periodic HTTP request (GET by default, POST optionally) to
3189
+ your configured URL with the headers you specify, parses the response as JSON,
3190
+ runs your `transform` jq expression (compiled by the
3191
+ [jaq](https://github.com/01mf02/jaq) library) over the parsed body, and merges
3192
+ the resulting per-prefix rows into the network-attributes trie.
3193
+
3194
+ The same flow applies to every JSON-over-HTTP source; the integration-specific
3195
+ part is the URL and the `transform` expression.
3196
supported_platforms:
3197
include:
3198
- Linux
3202
description: ""
3203
default_behavior:
3204
auto_detection:
2061
- description: "Disabled by default. Add an entry per IPAM source under enrichment.network_sources."
3205
+ description: "Disabled by default. Add a named entry under `enrichment.network_sources` for each IPAM/CMDB/endpoint you want to import."
3206
limits:
2063
- description: ""
3207
+ description: "Resource use scales with response size, transform complexity, refresh interval, and the number of emitted prefixes. Empty transform output is treated as a fetch failure."
3208
performance_impact:
2065
- description: ""
3209
+ description: "One HTTP request per refresh interval plus a jq transform over the response. Runtime enrichment does prefix matching for source and destination IPs, and cost scales with the number of loaded network-source records."
3210
setup:
3211
prerequisites:
3212
list:
3213
- title: An HTTP/HTTPS endpoint returning JSON
3214
description: |
2071
- The endpoint must produce a parseable JSON document. The plugin only supports
2072
- GET and POST. There is no pagination, no cursor following, no OAuth flow --
2073
- if your IPAM needs those, wrap it in an internal aggregator.
3215
+ The endpoint must respond with a parseable JSON document (the plugin sets
3216
+ `Accept: application/json`). Only GET and POST are accepted as request
3217
+ methods. There is no pagination, no
3218
+ cursor following, no `Link: rel=next` handling -- the fetch is one-shot
3219
+ per cycle. If your IPAM paginates, expose a bulk endpoint or wrap it in a
3220
+ server-side aggregator that returns the full list at one URL.
3221
- title: Authentication via headers
3222
description: |
2076
- The plugin has no built-in auth helpers. Set whatever the API needs -- bearer
2077
- tokens, basic-auth header, custom API-key headers -- via `headers:`. Store
2078
- tokens carefully; they're written into the YAML.
3223
+ The plugin has no built-in OAuth flow, basic-auth helper, or token
3224
+ refresh. Whatever the API needs (bearer tokens, API keys, custom header
3225
+ names, basic-auth realms) goes into the `headers:` map. The header map is
3226
+ an arbitrary string-to-string mapping, so any single-shot scheme works.
3227
+ For short-lived tokens, refresh them outside Netdata and reload the
3228
+ plugin config.
3229
+ - title: A POST endpoint must accept an empty body
3230
+ description: |
3231
+ When `method: POST` is configured, the plugin sends the request with the
3232
+ configured headers but **no request body**. If your CMDB requires a JSON query body to return prefixes,
3233
+ wrap it server-side with an endpoint that accepts GET (or POST with no
3234
+ body) and returns the full prefix set.
3235
configuration:
3236
file:
3237
name: netflow.yaml
3238
options:
3239
description: |
2084
- Add a named entry under `enrichment.network_sources`. The keys below are the
2085
- full set of options.
3240
+ Add a named entry under `enrichment.network_sources`. Unknown keys cause a
3241
+ config error.
3242
folding:
3243
title: Config options
3244
enabled: true
3245
list:
3246
- name: url
2091
- description: HTTP/HTTPS endpoint.
3247
+ description: HTTP/HTTPS endpoint. Required (a non-empty URL is enforced by validation).
3248
default_value: ""
3249
required: true
3250
- name: method
2095
- description: GET or POST.
3251
+ description: HTTP method. Only `GET` and `POST` are accepted; anything else fails validation. Note that `POST` is sent with no request body.
3252
default_value: "GET"
3253
required: false
3254
+ - name: headers
3255
+ description: |
3256
+ Map of additional HTTP request headers. Use this for any authentication
3257
+ scheme (`Authorization: Bearer ...`, `token: ...`, custom API-key
3258
+ headers, basic-auth realms encoded explicitly, etc.). Values are
3259
+ passed through verbatim.
3260
+ default_value: "{}"
3261
+ required: false
3262
- name: interval
2099
- description: Refresh interval (loop floors at 60s).
3263
+ description: Refresh cadence. Values below 60 seconds are accepted, but refreshes still run no faster than once per minute. Pick the value that matches how often your IPAM actually changes (5-15 minutes for a curated CMDB; daily for slow-moving prefix lists).
3264
default_value: "60s"
3265
required: false
3266
- name: timeout
2103
- description: Per-request timeout.
3267
+ description: Per-request timeout. Must be greater than 0.
3268
default_value: "60s"
3269
required: false
2106
- - name: headers
2107
- description: Map of additional HTTP request headers (e.g., authentication).
2108
- default_value: "{}"
3270
+ - name: proxy
3271
+ description: Whether to honor the system HTTP/HTTPS proxy environment variables. Set to `false` to bypass the proxy for this source (useful when the IPAM is on the internal network and the proxy is for outbound traffic only).
3272
+ default_value: "true"
3273
required: false
2110
- - name: transform
2111
- description: jq expression converting response to {prefix, name?, role?, site?, region?, country?, state?, city?, tenant?, asn?, asn_name?} stream.
2112
- default_value: "."
2113
- required: true
3274
- name: tls.enable
2115
- description: Use custom TLS settings (custom CA, mTLS).
3275
+ description: Enables custom TLS settings (custom CA bundle, mTLS client certificate). Must be `true` whenever any of `tls.ca_file`, `tls.cert_file`, `tls.key_file` is set.
3276
+ default_value: "false"
3277
+ required: false
3278
+ - name: tls.verify
3279
+ description: Certificate verification toggle. **Setting this to `false` is rejected by validation** -- network-identity data flows directly into security-relevant enrichment, so MITM-able responses are not allowed. Use `tls.ca_file` to trust internal CAs instead.
3280
+ default_value: "true"
3281
+ required: false
3282
+ - name: tls.skip_verify
3283
+ description: |
3284
+ Legacy alias for the same intent as `tls.verify: false`. **Setting this
3285
+ to `true` is rejected by validation.** Use `tls.ca_file`.
3286
default_value: "false"
3287
required: false
3288
- name: tls.ca_file
2119
- description: PEM file with the CA bundle.
3289
+ description: PEM file with the CA bundle to trust for this endpoint (instead of, or in addition to, the system roots). The recommended way to talk to an internal IPAM behind your own PKI.
3290
default_value: ""
3291
required: false
3292
- name: tls.cert_file
2123
- description: PEM file with the client certificate (mTLS).
3293
+ description: PEM file with the client certificate, for mTLS-protected endpoints.
3294
default_value: ""
3295
required: false
3296
- name: tls.key_file
2127
- description: PEM file with the client private key.
3297
+ description: PEM file with the client private key. Required only when the key is in a separate file from the certificate; if omitted, the cert file is reused. `tls.cert_file` must also be set whenever `tls.key_file` is set.
3298
default_value: ""
3299
required: false
3300
+ - name: transform
3301
+ description: |
3302
+ jq expression compiled by [jaq](https://github.com/01mf02/jaq). Receives the entire parsed JSON body once and must produce a **stream of objects**, where each object has at minimum a `prefix` field (a CIDR string -- `IPv4/len` or `IPv6/len`) plus any of the optional attribute fields: `name`, `role`, `site`, `region`, `country`, `state`, `city`, `tenant`, `asn`, `asn_name`. Any field not produced is treated as empty. The transform compiles at startup -- a syntax error fails the config load. An empty stream at runtime is treated as a fetch failure and triggers backoff.
3303
+ default_value: "."
3304
+ required: true
3305
examples:
3306
folding:
3307
title: Config
3308
enabled: true
3309
list:
2135
- - name: phpIPAM with API token
3310
+ - name: Flat list with `{prefix, name, env}`
3311
folding:
3312
enabled: false
2138
- description: "phpIPAM exposes `/api/<APP>/subnets/`. Replace `<APP>` with your phpIPAM app name. Use the standard transform."
3313
+ description: |
3314
+ The simplest IPAM shape: a top-level array of subnets, each with a CIDR
3315
+ string and a few labels. Maps `env` -> tenant and the `name` -> NET_NAME.
3316
+ config: |
3317
+ enrichment:
3318
+ network_sources:
3319
+ custom_ipam:
3320
+ url: "https://ipam.corp.example/api/v1/prefixes"
3321
+ headers:
3322
+ Authorization: "Bearer abcdef0123456789"
3323
+ interval: 5m
3324
+ transform: |
3325
+ .[] | {
3326
+ prefix: .prefix,
3327
+ name: .name,
3328
+ tenant: .env
3329
+ }
3330
+ - name: phpIPAM with API token
3331
+ folding:
3332
+ enabled: true
3333
+ description: |
3334
+ phpIPAM exposes `/api/<APP>/subnets/`. Replace `<APP>` with your phpIPAM
3335
+ application name. phpIPAM splits the address into a base and a mask --
3336
+ the transform reassembles them into a CIDR string.
3337
config: |
3338
enrichment:
3339
network_sources:
3349
tenant: (.custom_tenant // ""),
3350
site: (.location.name // "")
3351
}
2154
- - name: Custom internal CMDB (POST with body)
3352
+ - name: Hierarchical CMDB export
3353
folding:
3354
enabled: true
2157
- description: When your CMDB requires POST with a query body. Define `method` and append the body via headers/url. The plugin's body support is limited -- prefer GET endpoints when possible.
3355
+ description: |
3356
+ A CMDB that returns nested objects -- top-level sites, each with a list
3357
+ of vlans, each with a list of prefixes. Flattens to one row per prefix,
3358
+ inheriting site and role labels from the parent.
3359
config: |
3360
enrichment:
3361
network_sources:
3362
cmdb:
2162
- url: "https://cmdb.example/query/networks"
2163
- method: POST
3363
+ url: "https://cmdb.example/export/networks.json"
3364
headers:
2165
- Authorization: "Bearer ..."
2166
- Content-Type: "application/json"
2167
- interval: 30m
3365
+ Authorization: "Bearer <CMDB_TOKEN>"
3366
+ interval: 15m
3367
transform: |
2169
- .results[] | {
2170
- prefix: .cidr,
2171
- tenant: .organization,
2172
- site: .datacenter,
2173
- role: .purpose
2174
- }
2175
- - name: Internal IPAM with mTLS
3368
+ .sites[] as $site
3369
+ | $site.vlans[] as $vlan
3370
+ | $vlan.prefixes[]
3371
+ | {
3372
+ prefix: .cidr,
3373
+ name: .label,
3374
+ site: $site.name,
3375
+ region: $site.region,
3376
+ role: $vlan.role,
3377
+ tenant: $vlan.tenant
3378
+ }
3379
+ - name: Internal IPAM behind mTLS
3380
folding:
3381
enabled: true
2178
- description: When the IPAM is behind your internal PKI.
3382
+ description: |
3383
+ When the IPAM is fronted by your internal PKI and requires a client
3384
+ certificate. `tls.enable: true` activates the custom TLS path; `tls.verify`
3385
+ must remain true (cannot be disabled).
3386
config: |
3387
enrichment:
3388
network_sources:
3400
name: .label,
3401
tenant: .tenant
3402
}
3403
+ - name: Source with the system proxy bypassed
3404
+ folding:
3405
+ enabled: true
3406
+ description: |
3407
+ When the agent host has an outbound HTTP proxy configured but the IPAM
3408
+ lives on the internal network and should be reached directly.
3409
+ config: |
3410
+ enrichment:
3411
+ network_sources:
3412
+ internal_ipam:
3413
+ url: "https://ipam.internal/api/networks"
3414
+ proxy: false
3415
+ headers:
3416
+ Authorization: "Bearer ..."
3417
+ interval: 5m
3418
+ transform: |
3419
+ .[] | { prefix: .cidr, name: .label }
3420
troubleshooting:
3421
problems:
3422
list:
3423
- name: Endpoint requires pagination
3424
description: |
2201
- The plugin does not paginate. Either raise the page size to cover your inventory,
2202
- or wrap the endpoint with an internal aggregator that returns all results at one URL.
3425
+ The plugin does not paginate. Either raise the page size in the URL to
3426
+ cover your full inventory, or wrap the endpoint with a server-side
3427
+ aggregator that returns all results at one URL. There is no built-in
3428
+ `Link: rel=next` follower.
3429
+ - name: POST endpoint requires a request body
3430
+ description: |
3431
+ The plugin's POST request is sent with no body. If your CMDB requires a
3432
+ JSON query body to return prefixes, wrap it server-side with an endpoint
3433
+ that accepts GET (or accepts POST with no body) and returns the full prefix
3434
+ set.
3435
- name: TLS verification cannot be disabled
3436
description: |
2205
- `tls.skip_verify` and `tls.verify: false` are rejected by validation. Use
2206
- `tls.ca_file` to trust internal CAs.
3437
+ `tls.verify: false` and `tls.skip_verify: true` are both rejected during
3438
+ configuration validation. Use `tls.ca_file` to trust internal CAs. This is
3439
+ deliberate -- network-identity rows feed enrichment used in security
3440
+ investigations and capacity decisions, where silently accepting MITM-able
3441
+ responses would corrupt every downstream analysis.
3442
- name: Empty result back-off
3443
description: |
2209
- An empty jq result is treated as a fetch failure. If your IPAM legitimately
2210
- returns no prefixes (quiet state), the source backs off as if it errored.
2211
- Workaround: have the upstream return at least one synthetic prefix.
3444
+ An empty stream from the jq transform is treated as a fetch failure.
3445
+ The source then backs
3446
+ off exponentially -- starting at `interval / 10` (floor 1s), doubling on
3447
+ each consecutive failure, and capped at the regular `interval`. On the
3448
+ next successful non-empty fetch the cadence resets to `interval`. If your
3449
+ IPAM legitimately has no prefixes (a quiet state), have the upstream
3450
+ return at least one synthetic prefix so the source does not back off.
3451
+ - name: Refresh appears slower than configured
3452
+ description: |
3453
+ The fetch loop floors the configured `interval` at 60 seconds. Configuring
3454
+ `interval: 5s` does not produce a 5-second loop -- it produces a 60-second
3455
+ loop. Pick a value at or above 60s that matches how often your IPAM
3456
+ actually changes (5-15 minutes is typical for a curated CMDB).
3457
+ - name: Unknown config keys cause errors
3458
+ description: |
3459
+ The config struct uses `deny_unknown_fields`. Typos like `headres:` or a
3460
+ non-existent option fail config load with a parse error rather than being
3461
+ silently ignored. Check the `enrichment.network_sources.<name>` schema
3462
+ listed under "Config options".
3463
+ - name: JSON parse errors are silent in the dashboard
3464
+ description: |
3465
+ Decode failures (HTTP error, JSON parse error, jq runtime error, schema
3466
+ mismatch on `prefix`) are logged but do not surface in the dashboard.
3467
+ Watch the Netdata journal for warnings:
3468
+ `journalctl --namespace netdata | grep network_sources`.
3469
+ - name: Prefer explicit authorization headers over URL credentials
3470
+ description: |
3471
+ URLs with embedded credentials (`https://user:pass@host`) are converted to
3472
+ HTTP Basic authentication by the HTTP client. Prefer `headers:` for clarity
3473
+ and to avoid storing credentials in URLs -- e.g.
3474
+ `headers: { Authorization: "Basic dXNlcjpwYXNz" }` for HTTP basic-auth.
3475
+ alerts: []
3476
+ metrics:
3477
+ folding:
3478
+ title: Metrics
3479
+ enabled: false
3480
+ description: |
3481
+ Tags flow records with whatever labels your jq transform emits -- typically
3482
+ `*_NET_NAME`, `*_NET_TENANT`, `*_NET_SITE`, `*_NET_ROLE`, `*_NET_REGION`. Verify
3483
+ on the Network Flows view via the `*_NET_*` columns.
3484
+ availability: []
3485
+ scopes: []
3486
+ - meta:
3487
+ plugin_name: netflow-plugin
3488
+ module_name: static-metadata
3489
+ monitored_instance:
3490
+ name: Static Metadata
3491
+ link: https://learn.netdata.cloud/docs/network-flows/enrichment
3492
+ categories:
3493
+ - flows.enrichment-methods
3494
+ icon_filename: network-wired.svg
3495
+ keywords:
3496
+ - static metadata
3497
+ - exporters
3498
+ - interfaces
3499
+ - networks
3500
+ - cidr
3501
+ - sampling rate override
3502
+ - asn override
3503
+ - country override
3504
+ - tenant
3505
+ - site
3506
+ - region
3507
+ - role
3508
+ related_resources:
3509
+ integrations:
3510
+ list:
3511
+ - plugin_name: netflow-plugin
3512
+ module_name: generic-ipam
3513
+ - plugin_name: netflow-plugin
3514
+ module_name: netbox
3515
+ - plugin_name: netflow-plugin
3516
+ module_name: dbip
3517
+ info_provided_to_referring_integrations:
3518
+ description: ""
3519
+ overview:
3520
+ data_collection:
3521
+ metrics_description: |
3522
+ Annotate network flows with operator-defined labels for exporters, interfaces,
3523
+ networks, and sampling rates. Static Metadata is a YAML-defined enrichment source
3524
+ that lives entirely in `netflow.yaml`. Use it when there is no IPAM, no CMDB, and
3525
+ no MMDB to query -- you simply know your own networks, your own routers, and what
3526
+ the interfaces on those routers do, and you want those labels visible on the
3527
+ Network Flows view.
3528
+
3529
+ Three independent surfaces are configured under this card, each populating a
3530
+ different set of flow-record fields:
3531
+
3532
+ - `enrichment.metadata_static.exporters.<ip-or-cidr>` -- per-exporter labels
3533
+ (matched against the source IP of the UDP datagram) and per-interface labels
3534
+ (matched against the ifIndex from the flow record).
3535
+ - `enrichment.networks.<cidr>` -- labels for arbitrary CIDR blocks (your own
3536
+ corp ranges, customer ranges, public blocks you operate). Matched against the
3537
+ flow's source and destination IPs.
3538
+ - `enrichment.override_sampling_rate.<cidr>` -- per-prefix sampling-rate
3539
+ substitution for exporters that do not communicate their rate (e.g. NetFlow
3540
+ v7, which has no sampling field, or a v9 exporter that never sends a Sampling
3541
+ Options Template).
3542
+
3543
+ Fields populated:
3544
+
3545
+ - From `metadata_static.exporters` (per-exporter):
3546
+ `EXPORTER_NAME`, `EXPORTER_GROUP`, `EXPORTER_ROLE`, `EXPORTER_SITE`,
3547
+ `EXPORTER_REGION`, `EXPORTER_TENANT`.
3548
+ - From `metadata_static.exporters.if_indexes` (per-interface):
3549
+ `IN_IF_NAME` / `OUT_IF_NAME`, `IN_IF_DESCRIPTION` / `OUT_IF_DESCRIPTION`,
3550
+ `IN_IF_SPEED` / `OUT_IF_SPEED` (in **bits per second**), `IN_IF_PROVIDER` /
3551
+ `OUT_IF_PROVIDER`, `IN_IF_CONNECTIVITY` / `OUT_IF_CONNECTIVITY`,
3552
+ `IN_IF_BOUNDARY` / `OUT_IF_BOUNDARY` (`1` = external, `2` = internal,
3553
+ `0`/omitted = removed from output).
3554
+ - From `enrichment.networks` (per-CIDR):
3555
+ `SRC_NET_NAME` / `DST_NET_NAME`, `SRC_NET_ROLE` / `DST_NET_ROLE`,
3556
+ `SRC_NET_SITE` / `DST_NET_SITE`, `SRC_NET_REGION` / `DST_NET_REGION`,
3557
+ `SRC_NET_TENANT` / `DST_NET_TENANT`, plus overrides for the GeoIP-derived
3558
+ `SRC_COUNTRY` / `DST_COUNTRY`, `SRC_GEO_STATE` / `DST_GEO_STATE`,
3559
+ `SRC_GEO_CITY` / `DST_GEO_CITY`, `SRC_GEO_LATITUDE` / `DST_GEO_LATITUDE`,
3560
+ `SRC_GEO_LONGITUDE` / `DST_GEO_LONGITUDE`. Setting `asn:` on a `networks`
3561
+ entry overrides the AS *number* via the same merge path; the AS *name*
3562
+ still comes from the ASN database (see "Composition with dynamic sources"
3563
+ below).
3564
+ - From `override_sampling_rate` (longest-prefix match against the exporter IP):
3565
+ `SAMPLING_RATE` is set unconditionally when an override prefix matches. This
3566
+ is different from `default_sampling_rate`, which only applies when the flow
3567
+ does not already carry a rate.
3568
+
3569
+ For the cross-cutting Enrichment concept (provider chains, merge order rules,
3570
+ how static composes with dynamic sources, the static-blocks-classifiers
3571
+ interaction, and shared failure modes), see
3572
+ [Enrichment](https://learn.netdata.cloud/docs/network-flows/enrichment).
3573
+ method_description: |
3574
+ Edit `netflow.yaml`, restart the plugin, and the YAML-defined data is loaded
3575
+ into the same in-memory tries the GeoIP, IPAM, and BGP enrichment paths read
3576
+ from. There is no network access, no file watching, and no hot reload --
3577
+ changes take effect on the next plugin startup.
3578
+ supported_platforms:
3579
+ include:
3580
+ - Linux
3581
+ exclude: []
3582
+ multi_instance: false
3583
+ additional_permissions:
3584
+ description: ""
3585
+ default_behavior:
3586
+ auto_detection:
3587
+ description: "Disabled by default. Add entries under `enrichment.metadata_static`, `enrichment.networks`, and / or `enrichment.override_sampling_rate` to populate it."
3588
+ limits:
3589
+ description: "Resource use scales with the number of exporter, interface, network, and sampling-override entries. Keep CIDR ranges and interface maps specific enough to match the routers you actually export."
3590
+ performance_impact:
3591
+ description: "Static lookups are local map/trie lookups during enrichment. Cost is usually small compared with flow decode and journal writes, but very large maps add memory and lookup work."
3592
+ setup:
3593
+ prerequisites:
3594
+ list:
3595
+ - title: An understanding of your own topology
3596
+ description: |
3597
+ You need to know which IP addresses your routers / switches / firewalls
3598
+ export from, the integer ifIndex values they use for each interface, and
3599
+ the CIDR ranges that belong to each of your sites / tenants / roles. None
3600
+ of this is auto-discovered -- this card is the "I will tell you" path.
3601
+ For sources that auto-discover the same data, see Generic IPAM, NetBox,
3602
+ and the cloud IP-range cards.
3603
+ - title: Persistent ifIndex values
3604
+ description: |
3605
+ `if_indexes` keys are the integer ifIndex the router puts in the flow
3606
+ record. Some platforms reassign ifIndex on line-card reseat or stack
3607
+ rebuild. After hardware changes, audit the labels -- a stale ifIndex
3608
+ entry silently no longer applies. The `default` interface block is used
3609
+ instead, or no labels are written when `skip_missing_interfaces: true` is set.
3610
+ configuration:
3611
+ file:
3612
+ name: netflow.yaml
3613
+ options:
3614
+ description: |
3615
+ All keys live under `enrichment:` in `netflow.yaml`. Unknown keys fail config
3616
+ load with a parse error.
3617
+ folding:
3618
+ title: Config options
3619
+ enabled: true
3620
+ list:
3621
+ - name: enrichment.metadata_static.exporters
3622
+ description: |
3623
+ Map keyed by exporter IP or CIDR. Longest-prefix match wins. A `/32`
3624
+ key and a bare IP are equivalent. Each entry holds exporter-level
3625
+ labels (`name`, `group`, `role`, `site`, `region`, `tenant`), an
3626
+ optional `default` interface block, an `if_indexes` map keyed by
3627
+ integer ifIndex, and `skip_missing_interfaces`.
3628
+ default_value: "{}"
3629
+ required: false
3630
+ - name: enrichment.metadata_static.exporters.<key>.if_indexes
3631
+ description: |
3632
+ Map keyed by integer ifIndex (the value the router puts in the flow
3633
+ record). Each entry holds `name`, `description`, `speed` (bits per
3634
+ second), `provider`, `connectivity`, and `boundary`.
3635
+ default_value: "{}"
3636
+ required: false
3637
+ - name: enrichment.metadata_static.exporters.<key>.default
3638
+ description: |
3639
+ Interface block applied to flow records whose ifIndex is not present
3640
+ in `if_indexes`. Same shape as an `if_indexes` entry. Ignored when
3641
+ `skip_missing_interfaces: true` is set.
3642
+ default_value: "{}"
3643
+ required: false
3644
+ - name: enrichment.metadata_static.exporters.<key>.skip_missing_interfaces
3645
+ description: |
3646
+ When `true`, flow records whose ifIndex is not in `if_indexes` get no
3647
+ interface labels at all (not even from `default`). Useful when you only
3648
+ care about a known set of WAN interfaces and want unknown ones to stay
3649
+ blank instead of inheriting a placeholder.
3650
+ default_value: "false"
3651
+ required: false
3652
+ - name: enrichment.metadata_static.exporters.<key>.if_indexes.<n>.boundary
3653
+ description: |
3654
+ Interface boundary marker. Accepts the integers `0` (undefined),
3655
+ `1` (external -- faces the outside world: Internet, peer, transit),
3656
+ `2` (internal -- faces your own infrastructure), or the case-insensitive
3657
+ strings `"undefined"`, `"external"`, `"internal"`. Any other value fails config load. Filtering for `IN_IF_BOUNDARY=1`
3658
+ cleanly gives you "traffic that arrived from outside".
3659
+ default_value: "0"
3660
+ required: false
3661
+ - name: enrichment.metadata_static.exporters.<key>.if_indexes.<n>.speed
3662
+ description: |
3663
+ Interface speed in **bits per second**. A 1 Gbps interface is
3664
+ `1000000000`, not `1000` and not `1000000`. Operators thinking in
3665
+ megabits get the value wrong by a factor of 1000 to 1000000.
3666
+ A `0` value means "not set" and removes the field from the output.
3667
+ default_value: "0"
3668
+ required: false
3669
+ - name: enrichment.networks
3670
+ description: |
3671
+ Map keyed by CIDR. Longest-prefix match contributes the most-specific
3672
+ fields; less-specific containing prefixes contribute their non-empty
3673
+ fields too. The same merge rule is used by `network_sources`. Each value is either a string
3674
+ (shorthand for `name:`) or a map with `name`, `role`, `site`, `region`,
3675
+ `country`, `state`, `city`, `latitude`, `longitude`, `tenant`, `asn`.
3676
+ default_value: "{}"
3677
+ required: false
3678
+ - name: enrichment.networks.<cidr>.asn
3679
+ description: |
3680
+ Forces the AS *number* for traffic in this prefix, overriding whatever
3681
+ the `asn_providers` chain computed. The AS *name* is still resolved
3682
+ from the ASN MMDB -- there is no `asn_name` config field. See the ASN
3683
+ section of [Enrichment](https://learn.netdata.cloud/docs/network-flows/enrichment).
3684
+ default_value: "0"
3685
+ required: false
3686
+ - name: enrichment.networks.<cidr>.latitude / longitude
3687
+ description: |
3688
+ Per-CIDR coordinate override. Out-of-range values (latitude not in
3689
+ [-90, 90] or longitude not in [-180, 180]) and non-finite values are
3690
+ silently coerced to empty strings -- the field is dropped, no error.
3691
+ Validate input out of band if your data matters.
3692
+ default_value: "null"
3693
+ required: false
3694
+ - name: enrichment.default_sampling_rate
3695
+ description: |
3696
+ Global fallback applied only when the flow record does not already
3697
+ carry a sampling rate. Either a single integer or a CIDR-keyed map
3698
+ (longest-prefix match against the exporter IP).
3699
+ default_value: "0"
3700
+ required: false
3701
+ - name: enrichment.override_sampling_rate
3702
+ description: |
3703
+ Per-exporter substitution that **always** wins when its prefix matches
3704
+ the exporter IP, regardless of what the flow record carried. Either a
3705
+ single integer or a CIDR-keyed map.
3706
+ default_value: "{}"
3707
+ required: false
3708
+ examples:
3709
+ folding:
3710
+ title: Config
3711
+ enabled: true
3712
+ list:
3713
+ - name: Naming exporters and their interfaces
3714
+ folding:
3715
+ enabled: false
3716
+ description: |
3717
+ One edge router and one spine. The `default` block applies to any
3718
+ ifIndex not listed under `if_indexes` -- handy when you only care about
3719
+ a few WAN ports and want everything else to inherit a placeholder.
3720
+ config: |
3721
+ enrichment:
3722
+ metadata_static:
3723
+ exporters:
3724
+ 192.0.2.10: # bare IP == /32
3725
+ name: edge-router-1
3726
+ site: par1
3727
+ region: eu-west
3728
+ role: edge
3729
+ tenant: tenant-a
3730
+ default:
3731
+ description: unclassified port
3732
+ if_indexes:
3733
+ 1:
3734
+ name: Gi0/0/1
3735
+ description: uplink to ISP-A
3736
+ speed: 10000000000 # 10 Gbps in bits per second
3737
+ provider: isp-a
3738
+ connectivity: transit
3739
+ boundary: external
3740
+ 2:
3741
+ name: Gi0/0/2
3742
+ description: LAN core
3743
+ speed: 1000000000
3744
+ connectivity: lan
3745
+ boundary: internal
3746
+ 198.51.100.0/24: # all routers in this subnet
3747
+ site: dc-fra1
3748
+ region: eu-central
3749
+ role: spine
3750
+ default:
3751
+ connectivity: lan
3752
+ boundary: internal
3753
+ - name: Tagging your own networks
3754
+ folding:
3755
+ enabled: true
3756
+ description: |
3757
+ The shorthand form (`203.0.113.0/24: transit-a`) sets only the `name`.
3758
+ The map form takes any subset of the schema fields. Less-specific
3759
+ supernets contribute non-empty fields to more-specific subnets via
3760
+ ascending-prefix-length merge -- declare RFC1918 once at `/8` and
3761
+ a `/24` inherits everything you did not override.
3762
+ config: |
3763
+ enrichment:
3764
+ networks:
3765
+ 10.0.0.0/8:
3766
+ name: corp-internal
3767
+ role: internal
3768
+ tenant: tenant-a
3769
+ 198.51.100.0/24: # a public block you operate
3770
+ name: customer-acme
3771
+ role: customer
3772
+ site: par1
3773
+ country: FR
3774
+ city: Paris
3775
+ latitude: 48.8566
3776
+ longitude: 2.3522
3777
+ asn: 64500
3778
+ 203.0.113.0/24: transit-a # shorthand: name only
3779
+ - name: Skipping interfaces you have not labelled
3780
+ folding:
3781
+ enabled: true
3782
+ description: |
3783
+ With `skip_missing_interfaces: true`, an ifIndex that is not in
3784
+ `if_indexes` produces no interface labels at all -- the `default`
3785
+ block is ignored. Useful when you want clearly-blank values for
3786
+ unmodelled interfaces instead of a placeholder description.
3787
+ config: |
3788
+ enrichment:
3789
+ metadata_static:
3790
+ exporters:
3791
+ 192.0.2.10:
3792
+ name: edge-router-1
3793
+ skip_missing_interfaces: true
3794
+ if_indexes:
3795
+ 1:
3796
+ name: Gi0/0/1
3797
+ description: uplink to ISP-A
3798
+ connectivity: transit
3799
+ boundary: external
3800
+ - name: Sampling rate override for old or silent exporters
3801
+ folding:
3802
+ enabled: true
3803
+ description: |
3804
+ NetFlow v7 has no sampling field; some v9 exporters never send a
3805
+ Sampling Options Template. Without an override, the bytes/packets
3806
+ stored in the journal are exporter-side **sampled** counters with
3807
+ no scaling factor. `override_sampling_rate` always wins;
3808
+ `default_sampling_rate` is the fallback used only when the flow
3809
+ did not carry a rate.
3810
+ config: |
3811
+ enrichment:
3812
+ default_sampling_rate: 1 # global fallback
3813
+ override_sampling_rate:
3814
+ 10.1.0.0/16: 1024 # an old NetFlow v7 stack
3815
+ 192.0.2.10/32: 4096 # one specific exporter
3816
+ troubleshooting:
3817
+ problems:
3818
+ list:
3819
+ - name: A more-specific entry inherits the wrong field from its supernet
3820
+ description: |
3821
+ `enrichment.networks` merges containing prefixes from least-specific to
3822
+ most-specific. Leaving a field blank on a `/24` does **not** clear the `/16`'s value
3823
+ for that field -- you must explicitly set the field on the more-specific
3824
+ entry to overwrite. The same merge rule applies to entries from
3825
+ `network_sources`, which interleave at the same prefix lengths.
3826
+ - name: GeoIP returns spurious data for an internal range
3827
+ description: |
3828
+ Until you declare your RFC1918 / RFC6598 / link-local ranges as
3829
+ `enrichment.networks` entries, the GeoIP-derived country / city / coord
3830
+ fields can pick up junk for those addresses. Adding a `networks` entry
3831
+ for the range overrides the GeoIP layer at the merge step.
3832
+ - name: ifIndex changed after a hardware swap
3833
+ description: |
3834
+ `if_indexes` keys are the numeric ifIndex sent in the flow record. A
3835
+ line-card reseat or stack rebuild can renumber the interfaces; the old
3836
+ ifIndex no longer matches and the per-interface block silently no longer
3837
+ applies. Audit after hardware changes.
3838
+ - name: speed shows up wrong by a factor of 1000
3839
+ description: |
3840
+ `speed:` is in **bits per second**. `speed: 1000` means 1 kbps, not
3841
+ 1 Mbps. A 1 Gbps interface is `1000000000`. `speed: 0` means "not set"
3842
+ and removes the field from the output.
3843
+ - name: An interface block silently no longer applies
3844
+ description: |
3845
+ When the configured ifIndex is not present in the flow record, the
3846
+ `default` block is used instead -- unless `skip_missing_interfaces: true`
3847
+ is set, in which case no interface labels are written at all. If you expected your block to apply but the labels are blank, the
3848
+ router is sending a different ifIndex.
3849
+ - name: Coordinates dropped silently
3850
+ description: |
3851
+ Out-of-range latitude / longitude (`latitude: 91.5`) and non-finite
3852
+ values become empty strings without an error. The map quietly stops drawing the marker. Validate input externally if
3853
+ the data matters.
3854
+ - name: Static labels block the classifiers
3855
+ description: |
3856
+ When static metadata sets **any** of `group`, `role`, `site`, `region`,
3857
+ `tenant` for an exporter, the `exporter_classifiers` rule chain does not
3858
+ run for that exporter at all. The same is true for an interface: any of `provider`, `connectivity`,
3859
+ `boundary` set by static metadata short-circuits
3860
+ `interface_classifiers`. If
3861
+ you want classifiers to run on top of static metadata, drop the static
3862
+ fields they are supposed to set.
3863
+ - name: A typo fails config load
3864
+ description: |
3865
+ The schema is `deny_unknown_fields` at every level. A typo such as
3866
+ `if_index` (the canonical key is `if_indexes`; aliases `ifindexes`,
3867
+ `if-indexes` are accepted) or a misspelt attribute (`teannt:`) fails plugin
3868
+ start with a YAML parse error rather than being silently ignored.
3869
+ - name: Sampling override looks ignored
3870
+ description: |
3871
+ `override_sampling_rate` always wins when its prefix matches; if the
3872
+ field still looks unset, check that the **exporter IP** -- not the
3873
+ flow's source / destination IP -- falls under the configured prefix.
3874
+ `default_sampling_rate` is only consulted when the flow did not already
3875
+ carry a rate.
3876
+ - name: Changes do not take effect
3877
+ description: |
3878
+ Static metadata is loaded at plugin startup and there is no file-change
3879
+ watcher. Restart the plugin (or the agent) after editing
3880
+ `netflow.yaml`.
3881
+ alerts: []
3882
+ metrics:
3883
+ folding:
3884
+ title: Metrics
3885
+ enabled: false
3886
+ description: |
3887
+ Tags flow records with operator-defined labels and (optionally) substitutes
3888
+ the sampling rate; produces no metrics of its own. Verify on the Network
3889
+ Flows tab via the `EXPORTER_*`, `IN_IF_*`, `OUT_IF_*`, `*_NET_*`,
3890
+ `*_COUNTRY`, `*_GEO_*`, and `SAMPLING_RATE` columns.
3891
+ availability: []
3892
+ scopes: []
3893
+ - meta:
3894
+ plugin_name: netflow-plugin
3895
+ module_name: classifiers
3896
+ monitored_instance:
3897
+ name: Classifiers
3898
+ link: https://learn.netdata.cloud/docs/network-flows/enrichment
3899
+ categories:
3900
+ - flows.enrichment-methods
3901
+ icon_filename: network-wired.svg
3902
+ keywords:
3903
+ - classifiers
3904
+ - rules
3905
+ - akvorado
3906
+ - expression
3907
+ - exporter
3908
+ - interface
3909
+ - boundary
3910
+ - connectivity
3911
+ - provider
3912
+ - tagging
3913
+ related_resources:
3914
+ integrations:
3915
+ list:
3916
+ - plugin_name: netflow-plugin
3917
+ module_name: static-metadata
3918
+ - plugin_name: netflow-plugin
3919
+ module_name: generic-ipam
3920
+ - plugin_name: netflow-plugin
3921
+ module_name: netbox
3922
+ info_provided_to_referring_integrations:
3923
+ description: ""
3924
+ overview:
3925
+ data_collection:
3926
+ metrics_description: |
3927
+ Annotate network flows with exporter and interface labels derived from reusable
3928
+ classification rules. Where [static metadata](https://learn.netdata.cloud/docs/network-flows/enrichment)
3929
+ forces you to enumerate every exporter and every ifIndex by hand, classifiers
3930
+ let you express the network design once -- "anything matching `^edge-` is the
3931
+ edge tier", "any interface with `BACKBONE-LUMEN` in its description is on
3932
+ Lumen", "any interface at 100Gbps is a core uplink" -- and apply that labelling
3933
+ across the whole flow stream.
3934
+
3935
+ The plugin ships two rule lists, evaluated in YAML order:
3936
+
3937
+ - `enrichment.exporter_classifiers` -- runs once per exporter (cached). Sees the
3938
+ exporter's IP and friendly name, and any classification slots already filled
3939
+ by static metadata or by earlier rules. Can set
3940
+ `EXPORTER_GROUP / ROLE / SITE / REGION / TENANT`.
3941
+ - `enrichment.interface_classifiers` -- runs once per `(exporter, interface)`
3942
+ pair, applied **twice per flow record** (once for the input interface, once
3943
+ for the output). Sees
3944
+ everything an exporter rule sees plus `Interface.Index / Name / Description /
3945
+ Speed / VLAN`. Can set `IN_IF_PROVIDER / OUT_IF_PROVIDER`,
3946
+ `IN_IF_CONNECTIVITY / OUT_IF_CONNECTIVITY`, `IN_IF_BOUNDARY / OUT_IF_BOUNDARY`
3947
+ (1=external, 2=internal), and override `IN_IF_NAME / DESCRIPTION` /
3948
+ `OUT_IF_NAME / DESCRIPTION`.
3949
+
3950
+ The expression language is **Akvorado-compatible for the documented operators
3951
+ and actions**. It implements a subset of Akvorado's `expr-lang`-derived grammar. Akvorado rules
3952
+ using only equality, comparison, `in`, `contains`, `startsWith`, `endsWith`,
3953
+ `matches`, `&&`, `||`, `!`, parentheses, and the documented `Classify*` /
3954
+ `Reject` / `Format` actions will work; arithmetic, ternaries, lambdas, and
3955
+ arbitrary `expr-lang` features are not supported.
3956
+
3957
+ Output values written by `Classify*` actions are **lowercased and stripped to
3958
+ ASCII alphanumerics + `.` + `+` + `-`** before they reach the flow record. So
3959
+ `ClassifyRegion("EU West")` becomes `euwest`. Use `SetName` / `SetDescription`
3960
+ when you want to preserve case and whitespace -- those write directly without
3961
+ normalisation.
3962
+
3963
+ For the cross-cutting Enrichment concept (where classifiers sit in the merge
3964
+ order vs static metadata, GeoIP, IPAM, BGP routing), see
3965
+ [Enrichment](https://learn.netdata.cloud/docs/network-flows/enrichment).
3966
+ method_description: |
3967
+ Each rule is a single boolean expression; an action with no condition (e.g.
3968
+ `Classify("edge")` at top level) is treated as always-true and always fires.
3969
+ Rules are AND/OR-composed, so the typical shape is `condition && Classify*(...)`.
3970
+ The plugin evaluates the list top to bottom, **first-write-wins per slot**:
3971
+ once `EXPORTER_GROUP` is set, no later rule can change it. Order rules from
3972
+ most-specific to least-specific.
3973
+
3974
+ Two short-circuit rules end the loop early. For exporter rules, the loop stops
3975
+ when `group + role + site + region + tenant` are all non-empty. For
3976
+ interface rules, the loop stops when `connectivity + provider + boundary` are
3977
+ all set. `SetName` / `SetDescription` /
3978
+ `Reject` do not contribute to short-circuit.
3979
+
3980
+ A rule that throws at runtime (e.g. comparing a string with `>`) breaks out of
3981
+ the loop for that record and keeps whatever was set so far. Use `matches`, `startsWith`, or `contains`
3982
+ on string fields instead of `>` / `<` to avoid this.
3983
+
3984
+ **Akvorado parity**: if `metadata_static` already filled any classification
3985
+ slot for the target, the matching classifier list does **not run** for that
3986
+ target -- operator-provided classification has priority and the rules cannot
3987
+ override it. Don't try to mix static and rule-based labelling on the same
3988
+ exporter or interface; pick one tool per target.
3989
+
3990
+ Results are cached. The exporter cache keys on `ExporterInfo (ip + name)`. The
3991
+ interface cache keys on `(exporter, exporter_classification, interface)` -- so
3992
+ when the exporter's classification changes (for example after you push new
3993
+ static metadata and restart) the interface caches naturally invalidate. The
3994
+ cache TTL is `enrichment.classifier_cache_duration` (default 5 minutes). It is
3995
+ a last-access TTL so entries live as long as they're queried.
3996
+ supported_platforms:
3997
+ include:
3998
+ - Linux
3999
+ exclude: []
4000
+ multi_instance: false
4001
+ additional_permissions:
4002
+ description: ""
4003
+ default_behavior:
4004
+ auto_detection:
4005
+ description: "Disabled by default. Both rule lists are empty; populate `enrichment.exporter_classifiers` and / or `enrichment.interface_classifiers` to enable."
4006
+ limits:
4007
+ description: "Resource use scales with rule count and the number of distinct exporters and interfaces. The classifier cache limits repeat evaluation for stable exporter/interface inventories."
4008
+ performance_impact:
4009
+ description: |
4010
+ Rules run at decode time, in the flow-pipeline hot path, so cost matters.
4011
+ The cache absorbs nearly all of it: per (exporter, interface) the rule list
4012
+ evaluates only on cache miss. Tune
4013
+ `enrichment.classifier_cache_duration` upwards (15-60 minutes) for very
4014
+ high-cardinality exporter / interface pools where the default 5 minutes
4015
+ still yields visible misses; tune downwards (30-60 seconds) when iterating
4016
+ on rule changes during a config session.
4017
+ setup:
4018
+ prerequisites:
4019
+ list:
4020
+ - title: Know what to classify
4021
+ description: |
4022
+ Classifiers shine when there is a pattern to match -- exporter naming
4023
+ conventions (`edge-...`, `core-...`), management-IP subnets per site,
4024
+ SNMP interface descriptions that follow a template (`BACKBONE-<carrier>`,
4025
+ `TRANSIT-...`, `IX-...`), or 100Gbps-equals-core conventions. If your
4026
+ fleet has no such pattern, [static metadata](https://learn.netdata.cloud/docs/network-flows/enrichment)
4027
+ is the better fit -- it lets you list each exporter and ifIndex by hand.
4028
+ - title: Configure interface metadata first if you want interface rules
4029
+ description: |
4030
+ The plugin does **not** poll SNMP itself, so `Interface.Name`,
4031
+ `Interface.Description`, and `Interface.Speed` are populated only from
4032
+ `enrichment.metadata_static` (the static-metadata integration card). If
4033
+ you have not configured `interfaces:` under `metadata_static.exporters`,
4034
+ those identifiers will be empty strings / zero, and any rule that
4035
+ matches against them will never fire. `Interface.Index` and
4036
+ `Interface.VLAN` come from the flow record itself and are always available.
4037
+ configuration:
4038
+ file:
4039
+ name: netflow.yaml
4040
+ options:
4041
+ description: |
4042
+ Both lists live under `enrichment:`. Each entry is a free-form string
4043
+ containing a single rule expression. The cache TTL is one global setting.
4044
+ folding:
4045
+ title: Config options
4046
+ enabled: true
4047
+ list:
4048
+ - name: enrichment.exporter_classifiers
4049
+ description: |
4050
+ Ordered list of rules applied per exporter. Each rule is a string
4051
+ expression. Available identifiers: `Exporter.IP`, `Exporter.Name`,
4052
+ `CurrentClassification.Group / .Role / .Site / .Region / .Tenant`.
4053
+ Available actions: `Classify` / `ClassifyGroup`, `ClassifyRole`,
4054
+ `ClassifySite`, `ClassifyRegion`, `ClassifyTenant`, plus the
4055
+ `*Regex(input, pattern, template)` variants of each, plus `Reject()`.
4056
+ Interface-only actions (`ClassifyProvider`, `ClassifyConnectivity`,
4057
+ `ClassifyExternal` / `ClassifyInternal`, `SetName`, `SetDescription`)
4058
+ fail at runtime if used here.
4059
+ default_value: "[]"
4060
+ required: false
4061
+ - name: enrichment.interface_classifiers
4062
+ description: |
4063
+ Ordered list of rules applied per `(exporter, interface)` pair. Sees
4064
+ everything an exporter rule sees, plus `Interface.Index`,
4065
+ `Interface.Name`, `Interface.Description`, `Interface.Speed` (bits per
4066
+ second), `Interface.VLAN`, and the per-interface
4067
+ `CurrentClassification.Connectivity / .Provider / .Boundary / .Name /
4068
+ .Description`. Available actions: `ClassifyProvider`,
4069
+ `ClassifyConnectivity`, `ClassifyExternal()`, `ClassifyInternal()`,
4070
+ `SetName`, `SetDescription`, `Reject()`, plus the `*Regex` variants of
4071
+ provider / connectivity. Exporter-only `Classify*` actions fail at
4072
+ runtime if used here.
4073
+ default_value: "[]"
4074
+ required: false
4075
+ - name: enrichment.classifier_cache_duration
4076
+ description: |
4077
+ Last-access TTL for both classifier caches (exporter and interface).
4078
+ Values below 1 second are rejected. The cache prunes opportunistically
4079
+ -- entries idle longer than the TTL are dropped on the next prune pass,
4080
+ capped at one prune every TTL or 30 seconds, whichever is smaller.
4081
+ Restart the plugin to clear caches outright when you change rules.
4082
+ default_value: "5m"
4083
+ required: false
4084
+ examples:
4085
+ folding:
4086
+ title: Config
4087
+ enabled: true
4088
+ list:
4089
+ - name: Exporter classification by name pattern
4090
+ folding:
4091
+ enabled: false
4092
+ description: |
4093
+ Tag exporters by the prefix of their friendly name -- the simplest and
4094
+ most common pattern. Falls back to a regex capture for the region code
4095
+ when the name encodes one. The final `Reject()` rule drops a test
4096
+ exporter from collection entirely.
4097
+ config: |
4098
+ enrichment:
4099
+ exporter_classifiers:
4100
+ # Group by name prefix.
4101
+ - 'Exporter.Name startsWith "edge-" && Classify("edge")'
4102
+ - 'Exporter.Name startsWith "core-" && Classify("core")'
4103
+ - 'Exporter.Name startsWith "agg-" && Classify("aggregation")'
4104
+
4105
+ # Site by management-IP subnet.
4106
+ - 'Exporter.IP startsWith "10.1." && ClassifySite("ny-dc1")'
4107
+ - 'Exporter.IP startsWith "10.2." && ClassifySite("par-dc1")'
4108
+
4109
+ # Region from a name suffix like "edge-fra-01" -> "fra".
4110
+ - 'ClassifyRegionRegex(Exporter.Name, "-([a-z]{3})-[0-9]+$", "$1")'
4111
+
4112
+ # Drop a lab exporter entirely.
4113
+ - 'Exporter.IP startsWith "192.0.2." && Reject()'
4114
+ - name: Interface classification from SNMP descriptions
4115
+ folding:
4116
+ enabled: true
4117
+ description: |
4118
+ Encode the boundary, the provider, and the connectivity tier from the
4119
+ interface description that your network team already maintains. The
4120
+ `(?i)` regex flag is the Rust regex inline-case-insensitive prefix.
4121
+ config: |
4122
+ enrichment:
4123
+ interface_classifiers:
4124
+ # Provider tag from a description prefix.
4125
+ - 'Interface.Description startsWith "BACKBONE-LUMEN" && ClassifyProvider("Lumen")'
4126
+ - 'Interface.Description startsWith "BACKBONE-COGENT" && ClassifyProvider("Cogent")'
4127
+ - 'Interface.Description startsWith "BACKBONE-NTT" && ClassifyProvider("NTT")'
4128
+
4129
+ # Transit links: external boundary + connectivity tag.
4130
+ - 'Interface.Description contains "TRANSIT" && ClassifyConnectivity("transit") && ClassifyExternal()'
4131
+
4132
+ # Peering and IX -- case-insensitive regex.
4133
+ - 'Interface.Description matches "(?i)^(IX|peering)-.*" && ClassifyConnectivity("peering") && ClassifyExternal()'
4134
+
4135
+ # Internal customer-facing access ports.
4136
+ - 'Interface.Description startsWith "CUSTOMER-" && ClassifyConnectivity("customer") && ClassifyInternal()'
4137
+ - name: Boundary inferred from interface speed
4138
+ folding:
4139
+ enabled: true
4140
+ description: |
4141
+ A pragmatic shorthand when descriptions are unreliable but speed is
4142
+ consistent. 100Gbps and faster interfaces are core, 10Gbps are
4143
+ aggregation, 1Gbps and slower are access. `Interface.Speed` is in bits
4144
+ per second -- numeric comparisons are safe.
4145
+ config: |
4146
+ enrichment:
4147
+ interface_classifiers:
4148
+ - 'Interface.Speed >= 100000000000 && ClassifyConnectivity("core")'
4149
+ - 'Interface.Speed >= 10000000000 && ClassifyConnectivity("aggregation")'
4150
+ - 'Interface.Speed > 0 && ClassifyConnectivity("access")'
4151
+ - name: Combining exporter context with interface rules
4152
+ folding:
4153
+ enabled: true
4154
+ description: |
4155
+ Interface rules see the exporter's already-resolved classification
4156
+ via `CurrentClassification.*`. Use it to scope interface rules to
4157
+ specific tiers -- for example: every interface on an edge exporter
4158
+ without a more-specific match falls back to "external".
4159
+ config: |
4160
+ enrichment:
4161
+ exporter_classifiers:
4162
+ - 'Exporter.Name startsWith "edge-" && Classify("edge") && ClassifyRole("border")'
4163
+ - 'Exporter.Name startsWith "core-" && Classify("core") && ClassifyRole("backbone")'
4164
+ interface_classifiers:
4165
+ # Specific provider rules first (most-specific to least-specific).
4166
+ - 'Interface.Description startsWith "BACKBONE-LUMEN" && ClassifyProvider("Lumen")'
4167
+ - 'Interface.Description startsWith "BACKBONE-COGENT" && ClassifyProvider("Cogent")'
4168
+
4169
+ # Generic transit rule.
4170
+ - 'Interface.Description contains "TRANSIT" && ClassifyConnectivity("transit") && ClassifyExternal()'
4171
+
4172
+ # Fallback: any unclassified interface on an edge box is external.
4173
+ - 'CurrentClassification.Role == "border" && CurrentClassification.Boundary == 0 && ClassifyExternal()'
4174
+ - name: Building values with Format and human-readable names
4175
+ folding:
4176
+ enabled: true
4177
+ description: |
4178
+ `Format(pattern, args...)` mimics Go's `fmt.Sprintf` for `%s`, `%v`,
4179
+ `%d`, `%%`. `Classify*`
4180
+ normalises (lowercase + strip non-alphanumeric); `SetName` and
4181
+ `SetDescription` do not, so they preserve the case and spaces of the
4182
+ computed value.
4183
+ config: |
4184
+ enrichment:
4185
+ exporter_classifiers:
4186
+ # Tenant computed from name, normalised on write -> "tenant-edge01".
4187
+ - 'ClassifyTenant(Format("tenant-%s", Exporter.Name))'
4188
+ interface_classifiers:
4189
+ # Human-readable name = "<exporter>:if<index>". Preserved verbatim.
4190
+ - 'SetName(Format("%s:if%d", Exporter.Name, Interface.Index))'
4191
+ - name: Tuning the cache for a large fleet
4192
+ folding:
4193
+ enabled: true
4194
+ description: |
4195
+ The default 5-minute last-access TTL is right for steady-state. Raise
4196
+ it when the (exporter, interface) population is large enough that
4197
+ evicted entries are quickly re-queried. Lower it when
4198
+ actively iterating on rule changes so misses pick up the new rules
4199
+ quickly.
4200
+ config: |
4201
+ enrichment:
4202
+ classifier_cache_duration: 30m
4203
+ exporter_classifiers:
4204
+ - 'Exporter.Name startsWith "edge-" && Classify("edge")'
4205
+ interface_classifiers:
4206
+ - 'Interface.Speed >= 100000000000 && ClassifyConnectivity("core")'
4207
+ troubleshooting:
4208
+ problems:
4209
+ list:
4210
+ - name: Plugin fails to start with a parser error
4211
+ description: |
4212
+ A rule failed to parse. The journal log includes the index in the list
4213
+ and a parser context (`unsupported rule term`, `unsupported value
4214
+ expression`, `Reject() does not accept arguments`, etc.). Common causes:
4215
+ missing `&&` between condition and action; an action used in the wrong
4216
+ list (`ClassifyExternal` in an exporter rule); strings written with
4217
+ single quotes (only JSON-style double quotes are accepted); regex literals
4218
+ that fail to compile.
4219
+ - name: Classifier rules never run for an exporter or interface
4220
+ description: |
4221
+ Likely cause: `metadata_static` already set **any** classification field
4222
+ on that target. By design, the matching list is suppressed entirely when
4223
+ the classification is non-empty. Either remove the static-metadata entry for that target, or
4224
+ keep static-metadata as the sole source for it.
4225
+ - name: A value appears differently in the dashboard than in the rule
4226
+ description: |
4227
+ `Classify*` actions normalise output to `[a-z0-9.+-]` only -- so
4228
+ `ClassifyRegion("EU West")` lands as `euwest`, and
4229
+ `Classify("Edge_Tier_1")` lands as `edgetier1`. Use `SetName` /
4230
+ `SetDescription` to preserve case and whitespace; those write the value
4231
+ verbatim.
4232
+ - name: First rule always wins, later rules never fire for the same slot
4233
+ description: |
4234
+ First-write-wins is by design and per slot. Order your
4235
+ rules from most-specific to least-specific. If you want a tiered
4236
+ fallback, use distinct slots (e.g. `Classify` for the broad group and
4237
+ `ClassifyRole` for the tier within that group).
4238
+ - name: A working rule stops matching some time after startup
4239
+ description: |
4240
+ Cached results expire after `classifier_cache_duration` (default 5
4241
+ minutes, last-access). When you change rules, restart the plugin so the
4242
+ caches clear immediately -- otherwise stale cached classifications keep
4243
+ returning until they idle out.
4244
+ - name: A rule with `>` or `<` aborts the rule list
4245
+ description: |
4246
+ Comparing a string-typed identifier with `>` / `<` / `>=` / `<=` raises
4247
+ a runtime error, and the loop breaks out for that record. Subsequent rules in
4248
+ the list are skipped for that record. Use `matches`, `startsWith`,
4249
+ `endsWith`, `contains`, or `==` / `!=` on string fields. Keep `>` / `<`
4250
+ for `Interface.Index`, `Interface.Speed`, and `Interface.VLAN` (the
4251
+ numeric identifiers).
4252
+ - name: ClassifyExternal fires only on one side
4253
+ description: |
4254
+ Interface classifiers run twice per flow record -- once for the input
4255
+ interface, once for the output. Both invocations see the same rule list. If your rule conditions on
4256
+ `Interface.Index == 42` and that ifIndex appears in `IN_IF` of one flow
4257
+ and `OUT_IF` of another, the rule fires correctly in both places. But
4258
+ the `IN_IF_BOUNDARY` / `OUT_IF_BOUNDARY` columns are independent -- a
4259
+ rule firing on the output side of a flow only sets the output side's
4260
+ boundary, and vice versa.
4261
+ - name: Interface fields are empty in the rule even though SNMP is configured
4262
+ description: |
4263
+ The plugin does not poll SNMP -- `Interface.Name`, `Description`, and
4264
+ `Speed` come exclusively from `enrichment.metadata_static.exporters.<ip>.interfaces.<index>`.
4265
+ If you populate them through an external SNMP discovery and write them
4266
+ into `metadata_static`, the rules will see them. Otherwise those fields
4267
+ resolve to empty strings / zero, and any rule that conditions on them
4268
+ never matches.
4269
+ - name: Referencing Interface.* in an exporter rule silently does nothing
4270
+ description: |
4271
+ Field resolution does not error when the wrong context is missing -- it
4272
+ returns the type's zero value. So `Interface.Speed >= 1` written in an `exporter_classifiers` rule
4273
+ resolves to `0 >= 1` (false) on every call. Use
4274
+ `interface_classifiers` for any rule that needs an interface field.
4275
+ alerts: []
4276
+ metrics:
4277
+ folding:
4278
+ title: Metrics
4279
+ enabled: false
4280
+ description: |
4281
+ Tags flow records with `EXPORTER_GROUP / ROLE / SITE / REGION / TENANT` (from
4282
+ exporter rules) and `IN_IF_PROVIDER / OUT_IF_PROVIDER`,
4283
+ `IN_IF_CONNECTIVITY / OUT_IF_CONNECTIVITY`, `IN_IF_BOUNDARY / OUT_IF_BOUNDARY`,
4284
+ `IN_IF_NAME / OUT_IF_NAME`, `IN_IF_DESCRIPTION / OUT_IF_DESCRIPTION` (from
4285
+ interface rules). Verify on the Network Flows view via those columns. Boundary
4286
+ is `1` for external and `2` for internal.
4287
+ availability: []
4288
+ scopes: []
4289
+ - meta:
4290
+ plugin_name: netflow-plugin
4291
+ module_name: decapsulation
4292
+ monitored_instance:
4293
+ name: Decapsulation
4294
+ link: https://datatracker.ietf.org/doc/html/rfc7348
4295
+ categories:
4296
+ - flows.enrichment-methods
4297
+ icon_filename: network-wired.svg
4298
+ keywords:
4299
+ - decapsulation
4300
+ - srv6
4301
+ - vxlan
4302
+ - tunnel
4303
+ - overlay
4304
+ - inner packet
4305
+ - dataLinkFrameSection
4306
+ - layer2packetSectionData
4307
+ - ipfix ie 315
4308
+ - netflow v9 ie 104
4309
+ - sampled header
4310
+ related_resources:
4311
+ integrations:
4312
+ list:
4313
+ - plugin_name: netflow-plugin
4314
+ module_name: netflow
4315
+ - plugin_name: netflow-plugin
4316
+ module_name: ipfix
4317
+ - plugin_name: netflow-plugin
4318
+ module_name: sflow
4319
+ info_provided_to_referring_integrations:
4320
+ description: ""
4321
+ overview:
4322
+ data_collection:
4323
+ metrics_description: |
4324
+ Enrich network flows with inner source and destination endpoints from VXLAN or
4325
+ SRv6 encapsulated traffic. Decapsulation rewrites the 5-tuple of a flow record
4326
+ from the **outer** (tunnel) endpoints to the **inner** (real) endpoints when the
4327
+ exporter ships the encapsulated frame bytes alongside the standard fields. Without
4328
+ it, every VM-to-VM conversation on a VXLAN fabric or every inner flow on an SRv6
4329
+ transit shows up as the same tunnel pair (hypervisor-to-hypervisor or PE-to-PE),
4330
+ which tells you nothing about the actual traffic.
4331
+
4332
+ Two encapsulations are supported, selected globally for the plugin. The mode set is
4333
+ `none`, `srv6`, or `vxlan`; the default is `none`.
4334
+
4335
+ | Mode | Strips | Surfaces |
4336
+ |---------|--------------------------------------------------|--------------------------------------------------|
4337
+ | `none` | nothing | the outer-header view (default) |
4338
+ | `srv6` | IPv6 outer + extension headers + SRH (type 4) | the inner IPv4 (next-header 4) or IPv6 (41) |
4339
+ | `vxlan` | outer Eth/IP + UDP/4789 + 8-byte VXLAN header | the inner Ethernet frame, then its L3/L4 |
4340
+
4341
+ The plugin only reaches the decap path when the flow record carries the inner
4342
+ frame bytes in a Layer-2 packet section field. Three transport-level paths feed it:
4343
+
4344
+ - **NetFlow v9 IE 104** -- `Layer2packetSectionData` (RFC 5102 / RFC 7270).
4345
+ - **IPFIX IE 315** -- `dataLinkFrameSection` (RFC 7133).
4346
+ - **sFlow `SampledHeader`** -- always present in header-sampling mode.
4347
+
4348
+ When decap succeeds, the inner 5-tuple replaces the outer one in the resulting
4349
+ journal record: `SRC_ADDR`, `DST_ADDR`, `SRC_PORT`, `DST_PORT`, `PROTOCOL`,
4350
+ `ETYPE`, `IPTOS`, `IPTTL`, `IPV6_FLOW_LABEL`, `TCP_FLAGS`, `IP_FRAGMENT_ID`,
4351
+ `IP_FRAGMENT_OFFSET`, ICMP type/code, MPLS labels (if present), and `BYTES`
4352
+ (set to the inner L3 length so byte counts represent inner payload, not outer
4353
+ overhead). For VXLAN, `SRC_MAC`, `DST_MAC`, `SRC_VLAN`, `DST_VLAN` come from the
4354
+ inner Ethernet frame -- the outer MACs and VLANs are lost. The VXLAN VNI is
4355
+ parsed but not exposed as a journal field; pure VNI-based segmentation is
4356
+ not visible.
4357
+
4358
+ The `vxlan` parser matches **only UDP destination port 4789** (RFC 7348).
4359
+ VXLAN-GPE on 4790 and any vendor-custom port are not recognised. The `srv6`
4360
+ parser walks IPv6 extension headers and the Routing Header type 4 (SRH), then
4361
+ surfaces the inner IPv4 or IPv6 packet pointed to by next-header 4 or 41.
4362
+
4363
+ For the cross-cutting concept (how decap composes with the rest of the enrichment
4364
+ pipeline, the non-tunnel "drop, do not fall back" semantics, and per-source
4365
+ dependence on the L2-section path), see
4366
+ [Decapsulation](https://learn.netdata.cloud/docs/network-flows/enrichment).
4367
+ method_description: |
4368
+ Set `protocols.decapsulation_mode` in `netflow.yaml` to `srv6` or `vxlan`. The
4369
+ plugin then runs the inner-packet parser whenever a flow record carries an L2
4370
+ frame section (NetFlow v9 IE 104 / IPFIX IE 315 / sFlow `SampledHeader`). Plain
4371
+ NetFlow / IPFIX records that do **not** carry an L2 section pass through
4372
+ unchanged regardless of the setting -- so enabling decap will not break a mixed
4373
+ stream where only a subset of exporters ship the frame bytes. Enabling decap is
4374
+ half the work; the exporter must also be configured to ship the inner frame.
4375
+ supported_platforms:
4376
+ include:
4377
+ - Linux
4378
+ exclude: []
4379
+ multi_instance: false
4380
+ additional_permissions:
4381
+ description: ""
4382
+ default_behavior:
4383
+ auto_detection:
4384
+ description: "Disabled by default (`decapsulation_mode: none`). You must opt in by setting the mode explicitly."
4385
+ limits:
4386
+ description: "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."
4387
+ performance_impact:
4388
+ description: "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."
4389
+ setup:
4390
+ prerequisites:
4391
+ list:
4392
+ - title: Confirm your exporter ships the L2 frame section
4393
+ description: |
4394
+ Decapsulation requires the exporter to include the inner frame bytes. Verify
4395
+ before enabling the mode:
4396
+
4397
+ - **NetFlow v9** -- the template must contain field type 104
4398
+ (`Layer2packetSectionData`). Capture a packet with `tcpdump`, decode with
4399
+ Wireshark, and inspect the template.
4400
+ - **IPFIX** -- the template must contain Information Element 315
4401
+ (`dataLinkFrameSection`, RFC 7133). Same verification path.
4402
+ - **sFlow** -- header sampling is the default for sFlow agents and ships the
4403
+ truncated raw packet inside `SampledHeader`. No special configuration is
4404
+ required beyond enabling sFlow.
4405
+
4406
+ Section length matters. VXLAN over Ethernet over IPv4 fits in roughly 96-128
4407
+ bytes of inner-frame capture; SRv6 with a Routing Header type 4 needs more
4408
+ (256 bytes is a safe starting point). Truncated captures fail the inner
4409
+ parser and the flow is dropped (see the failure modes on the concept page).
4410
+ - title: Configure your exporter to emit the L2 section
4411
+ description: |
4412
+ Vendor support varies. Recommended exporter paths are:
4413
+
4414
+ - **Juniper inline-monitoring (IPFIX 315)** on platforms supporting
4415
+ `services { inline-monitoring { ... } }` -- the template includes
4416
+ `datalink-frame-size` and a `maximum-clip-length` controls how much of the
4417
+ frame is captured. Reference recipe in the
4418
+ [Akvorado documentation](https://demo.akvorado.net/docs/operations#ipfix-315).
4419
+ - **sFlow** with header sampling -- supported by Juniper QFX, Arista EOS,
4420
+ Mellanox/NVIDIA, MikroTik, and others. Header sampling is the default for
4421
+ most agents; verify the agent emits `SampledHeader` rather than only
4422
+ `SampledIPv4` / `SampledIPv6` records (the latter do not carry inner
4423
+ bytes).
4424
+
4425
+ Cisco IOS-XE and IOS-XR Flexible NetFlow support for Layer-2 frame
4426
+ sections is platform-dependent. Before deploying Cisco decapsulation,
4427
+ inspect the exported template and look for IE 104 (v9) or IE 315 (IPFIX).
4428
+ Do not copy `collect datalink frame-section` snippets into production
4429
+ unless the platform template confirms that the L2 section is exported.
4430
+ configuration:
4431
+ file:
4432
+ name: netflow.yaml
4433
+ options:
4434
+ description: |
4435
+ Decapsulation has a single configuration knob -- `protocols.decapsulation_mode`.
4436
+ folding:
4437
+ title: Config options
4438
+ enabled: true
4439
+ list:
4440
+ - name: protocols.decapsulation_mode
4441
+ description: |
4442
+ One of `none` (default), `srv6`, `vxlan`. The mode applies globally; the
4443
+ plugin cannot decode both VXLAN and SRv6 in the same instance. Setting
4444
+ this only affects records that travel through the L2-section path
4445
+ (NetFlow v9 IE 104 / IPFIX IE 315 / sFlow `SampledHeader`); regular flow
4446
+ records are unaffected. When the mode is set and the inner packet does
4447
+ not match the configured tunnel, the record is dropped -- there is no
4448
+ "fall back to outer view".
4449
+ default_value: none
4450
+ required: false
4451
+ examples:
4452
+ folding:
4453
+ title: Config
4454
+ enabled: true
4455
+ list:
4456
+ - name: VXLAN-based VTEP fleet (decode the inner tenant traffic)
4457
+ folding:
4458
+ enabled: false
4459
+ description: |
4460
+ Hypervisors emit sFlow with header sampling on the underlay. Every flow
4461
+ between two VTEP loopbacks decodes to the inner VM-to-VM 5-tuple instead
4462
+ of the underlay tunnel pair.
4463
+ config: |
4464
+ protocols:
4465
+ decapsulation_mode: vxlan
4466
+ - name: SRv6 transit network (see the inner service traffic)
4467
+ folding:
4468
+ enabled: true
4469
+ description: |
4470
+ Provider-edge routers export IPFIX with IE 315 (`dataLinkFrameSection`)
4471
+ via Juniper inline-monitoring. The plugin walks the IPv6 extension chain,
4472
+ strips the SRH, and surfaces the inner IPv4 or IPv6 5-tuple.
4473
+ config: |
4474
+ protocols:
4475
+ decapsulation_mode: srv6
4476
+ - name: Default (no decapsulation)
4477
+ folding:
4478
+ enabled: true
4479
+ description: |
4480
+ Outer-header view only. Tunnel endpoints appear as the source and
4481
+ destination of every flow.
4482
+ config: |
4483
+ protocols:
4484
+ decapsulation_mode: none
4485
+ troubleshooting:
4486
+ problems:
4487
+ list:
4488
+ - name: Decap mode set but tunnels still show outer endpoints
4489
+ description: |
4490
+ The exporter is not shipping the L2 frame section. Plain NetFlow / IPFIX
4491
+ flow records (no IE 104 / IE 315) take the regular path and are unaffected
4492
+ by `decapsulation_mode`. Inspect the template -- look for field type 104
4493
+ on NetFlow v9 or IE 315 on IPFIX. For sFlow, confirm the agent is sending
4494
+ `SampledHeader` records rather than only `SampledIPv4` / `SampledIPv6`.
4495
+ - name: Records disappear after enabling decap
4496
+ description: |
4497
+ When `decapsulation_mode` is set and a record arrives via the L2-section
4498
+ path with a payload that does not match the configured tunnel, the record
4499
+ is **dropped**. There is no fall back to the outer view. For sFlow with decap on, only `SampledHeader` records are processed;
4500
+ `SampledIPv4`, `SampledIPv6`, `SampledEthernet`, `ExtendedSwitch`,
4501
+ `ExtendedRouter`, `ExtendedGateway` records are skipped. If the same
4502
+ exporter mixes tunnel and non-tunnel traffic on the L2-section path, you
4503
+ will lose the non-tunnel records.
4504
+ - name: VXLAN on a non-default UDP port goes undetected
4505
+ description: |
4506
+ The VXLAN parser matches only UDP destination port 4789. VXLAN-GPE on 4790 and any
4507
+ vendor-custom port are not recognised and the record is dropped under
4508
+ `decapsulation_mode: vxlan`.
4509
+ - name: Frame section truncated, inner parsing fails
4510
+ description: |
4511
+ The exporter's clip / section size is shorter than the outer headers plus
4512
+ the inner L3/L4 needed to populate the 5-tuple. Increase the section size
4513
+ -- 128 bytes for VXLAN over IPv4, 256 bytes or more for SRv6 with extension
4514
+ headers. On Juniper inline-monitoring, the knob is `maximum-clip-length`.
4515
+ - name: VNI-based segmentation invisible
4516
+ description: |
4517
+ Bytes 4-6 of the VXLAN header (the VNI) are not exposed as journal
4518
+ fields. If the inner Ethernet carries a VLAN tag, that VLAN reaches
4519
+ `SRC_VLAN` / `DST_VLAN` and works for segmentation -- pure VNI does not.
4520
+ No workaround inside the plugin; either VLAN-tag the inner traffic or
4521
+ filter at query time using the tunnel-endpoint pair before decap.
4522
+ - name: One mode at a time
4523
+ description: |
4524
+ The plugin cannot decode VXLAN and SRv6 in the same instance. If exporter A
4525
+ ships VXLAN tenant traffic and exporter B ships SRv6 transit traffic, you
4526
+ must choose the mode that matches the traffic this Netdata Agent receives.
4527
alerts: []
4528
metrics:
4529
folding:
4530
title: Metrics
4531
enabled: false
4532
description: |
2218
- Tags flow records with whatever labels your jq transform emits. Verify on the
2219
- Network Flows tab via the `*_NET_*` columns.
4533
+ Decapsulation rewrites flow-record fields in place; it produces no metrics of its
4534
+ own. Verify on the Network Flows view that `SRC_ADDR` / `DST_ADDR` reflect inner
4535
+ endpoints rather than the tunnel pair after enabling the mode.
4536
availability: []
4537
scopes: []