From d7ed936f6d1aa12fdfcaead9d57449ba538cbb5c Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Wed, 30 Mar 2022 23:47:00 +0200 Subject: [PATCH] sphinx-doc - initial draft --- docs/.nojekyll | 0 docs/Makefile | 24 + docs/_config.yml | 4 - docs/a10nsp.md | 74 -- docs/bgp.md | 170 ---- docs/config.md | 950 ------------------ docs/ctrl.md | 292 ------ docs/index.md | 42 - docs/install.md | 149 --- docs/intro.md | 115 --- docs/ipoe.md | 151 --- docs/isis.md | 339 ------- docs/l2tp.md | 387 ------- docs/li.md | 92 -- docs/lspgen.md | 1 - docs/multicast.md | 203 ---- docs/pppoe.md | 181 ---- docs/reports.md | 412 -------- docs/requirements.txt | 3 + docs/source/access/index.rst | 13 + docs/source/access/ipoe.rst | 169 ++++ docs/source/access/l2bsa.rst | 76 ++ docs/source/access/l2tp.rst | 400 ++++++++ docs/source/access/li.rst | 96 ++ docs/source/access/multicast.rst | 217 ++++ docs/source/access/pppoe.rst | 213 ++++ docs/source/access/traffic.rst | 79 ++ docs/source/api/bgp.rst | 27 + docs/source/api/cfm.rst | 23 + docs/source/api/igmp.rst | 19 + docs/source/api/index.rst | 178 ++++ docs/source/api/interfaces.rst | 11 + docs/source/api/isis.rst | 27 + docs/source/api/l2tp.rst | 53 + docs/source/api/li.rst | 11 + docs/source/api/ppp.rst | 23 + docs/source/api/sessions.rst | 39 + docs/source/api/streams.rst | 23 + docs/source/api/traffic.rst | 23 + docs/source/conf.py | 32 + docs/source/configuration/access_line.rst | 27 + .../configuration/access_line_profiles.rst | 113 +++ docs/source/configuration/bgp.rst | 45 + docs/source/configuration/dhcp.rst | 36 + docs/source/configuration/dhcpv6.rst | 24 + docs/source/configuration/igmp.rst | 72 ++ docs/source/configuration/index.rst | 109 ++ docs/source/configuration/interfaces.rst | 33 + .../configuration/interfaces_a10nsp.rst | 21 + .../configuration/interfaces_access.rst | 138 +++ .../configuration/interfaces_network.rst | 51 + docs/source/configuration/ipoe.rst | 24 + docs/source/configuration/isis.rst | 90 ++ docs/source/configuration/isis_external.rst | 15 + .../isis_external_connections.rst | 21 + docs/source/configuration/lns.rst | 53 + docs/source/configuration/ppp.rst | 15 + .../configuration/ppp_authentication.rst | 27 + docs/source/configuration/ppp_ip6cp.rst | 21 + docs/source/configuration/ppp_ipcp.rst | 30 + docs/source/configuration/ppp_lcp.rst | 33 + docs/source/configuration/pppoe.rst | 33 + docs/source/configuration/session_traffic.rst | 24 + docs/source/configuration/sessions.rst | 47 + docs/source/configuration/streams.rst | 110 ++ docs/source/configuration/traffic.rst | 18 + docs/source/faq.rst | 16 + docs/{ => source}/images/bbl_arch.png | Bin docs/{ => source}/images/bbl_header.png | Bin docs/{ => source}/images/bbl_interactive.png | Bin docs/{ => source}/images/bbl_interfaces.png | Bin docs/{ => source}/images/bbl_isis.png | Bin .../images/bbl_session_traffic.png | Bin docs/{ => source}/images/bbl_streams.png | Bin docs/{ => source}/images/logo.png | Bin docs/{ => source}/images/pppoe-fsm.dot | 0 docs/{ => source}/images/pppoe-fsm.svg | 0 docs/source/images/quickstart1.png | Bin 0 -> 308152 bytes docs/source/images/quickstart2.png | Bin 0 -> 74267 bytes docs/{ => source}/images/rtbrick_logo.png | Bin docs/source/index.rst | 96 ++ docs/source/install.rst | 161 +++ docs/source/interfaces.rst | 325 ++++++ docs/source/quickstart.rst | 353 +++++++ docs/source/reference/architecture.rst | 52 + docs/source/reference/index.rst | 8 + docs/source/reference/traffic.rst | 139 +++ docs/source/reports.rst | 265 +++++ docs/source/routing/bgp.rst | 184 ++++ docs/source/routing/index.rst | 13 + docs/source/routing/isis.rst | 359 +++++++ docs/source/routing/mpls.rst | 3 + docs/source/streams.rst | 350 +++++++ docs/source/troubleshooting.rst | 48 + docs/streams.md | 368 ------- docs/traffic.md | 122 --- 96 files changed, 5381 insertions(+), 4052 deletions(-) create mode 100644 docs/.nojekyll create mode 100644 docs/Makefile delete mode 100644 docs/_config.yml delete mode 100644 docs/a10nsp.md delete mode 100644 docs/bgp.md delete mode 100644 docs/config.md delete mode 100644 docs/ctrl.md delete mode 100644 docs/index.md delete mode 100644 docs/install.md delete mode 100644 docs/intro.md delete mode 100644 docs/ipoe.md delete mode 100644 docs/isis.md delete mode 100644 docs/l2tp.md delete mode 100644 docs/li.md delete mode 100644 docs/lspgen.md delete mode 100644 docs/multicast.md delete mode 100644 docs/pppoe.md delete mode 100644 docs/reports.md create mode 100644 docs/requirements.txt create mode 100644 docs/source/access/index.rst create mode 100644 docs/source/access/ipoe.rst create mode 100644 docs/source/access/l2bsa.rst create mode 100644 docs/source/access/l2tp.rst create mode 100644 docs/source/access/li.rst create mode 100644 docs/source/access/multicast.rst create mode 100644 docs/source/access/pppoe.rst create mode 100644 docs/source/access/traffic.rst create mode 100644 docs/source/api/bgp.rst create mode 100644 docs/source/api/cfm.rst create mode 100644 docs/source/api/igmp.rst create mode 100644 docs/source/api/index.rst create mode 100644 docs/source/api/interfaces.rst create mode 100644 docs/source/api/isis.rst create mode 100644 docs/source/api/l2tp.rst create mode 100644 docs/source/api/li.rst create mode 100644 docs/source/api/ppp.rst create mode 100644 docs/source/api/sessions.rst create mode 100644 docs/source/api/streams.rst create mode 100644 docs/source/api/traffic.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/configuration/access_line.rst create mode 100644 docs/source/configuration/access_line_profiles.rst create mode 100644 docs/source/configuration/bgp.rst create mode 100644 docs/source/configuration/dhcp.rst create mode 100644 docs/source/configuration/dhcpv6.rst create mode 100644 docs/source/configuration/igmp.rst create mode 100644 docs/source/configuration/index.rst create mode 100644 docs/source/configuration/interfaces.rst create mode 100644 docs/source/configuration/interfaces_a10nsp.rst create mode 100644 docs/source/configuration/interfaces_access.rst create mode 100644 docs/source/configuration/interfaces_network.rst create mode 100644 docs/source/configuration/ipoe.rst create mode 100644 docs/source/configuration/isis.rst create mode 100644 docs/source/configuration/isis_external.rst create mode 100644 docs/source/configuration/isis_external_connections.rst create mode 100644 docs/source/configuration/lns.rst create mode 100644 docs/source/configuration/ppp.rst create mode 100644 docs/source/configuration/ppp_authentication.rst create mode 100644 docs/source/configuration/ppp_ip6cp.rst create mode 100644 docs/source/configuration/ppp_ipcp.rst create mode 100644 docs/source/configuration/ppp_lcp.rst create mode 100644 docs/source/configuration/pppoe.rst create mode 100644 docs/source/configuration/session_traffic.rst create mode 100644 docs/source/configuration/sessions.rst create mode 100644 docs/source/configuration/streams.rst create mode 100644 docs/source/configuration/traffic.rst create mode 100644 docs/source/faq.rst rename docs/{ => source}/images/bbl_arch.png (100%) rename docs/{ => source}/images/bbl_header.png (100%) rename docs/{ => source}/images/bbl_interactive.png (100%) rename docs/{ => source}/images/bbl_interfaces.png (100%) rename docs/{ => source}/images/bbl_isis.png (100%) rename docs/{ => source}/images/bbl_session_traffic.png (100%) rename docs/{ => source}/images/bbl_streams.png (100%) rename docs/{ => source}/images/logo.png (100%) rename docs/{ => source}/images/pppoe-fsm.dot (100%) rename docs/{ => source}/images/pppoe-fsm.svg (100%) create mode 100644 docs/source/images/quickstart1.png create mode 100644 docs/source/images/quickstart2.png rename docs/{ => source}/images/rtbrick_logo.png (100%) create mode 100644 docs/source/index.rst create mode 100644 docs/source/install.rst create mode 100644 docs/source/interfaces.rst create mode 100644 docs/source/quickstart.rst create mode 100644 docs/source/reference/architecture.rst create mode 100644 docs/source/reference/index.rst create mode 100644 docs/source/reference/traffic.rst create mode 100644 docs/source/reports.rst create mode 100644 docs/source/routing/bgp.rst create mode 100644 docs/source/routing/index.rst create mode 100644 docs/source/routing/isis.rst create mode 100644 docs/source/routing/mpls.rst create mode 100644 docs/source/streams.rst create mode 100644 docs/source/troubleshooting.rst delete mode 100644 docs/streams.md delete mode 100644 docs/traffic.md diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..2246c49f --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,24 @@ +# Makefile for Sphinx documentation + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = . + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +github: + @make html + @cp -a _build/html/. . + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index 9273c4a9..00000000 --- a/docs/_config.yml +++ /dev/null @@ -1,4 +0,0 @@ -title: RtBrick BNG Blaster -description: The BNG Blaster is a test tool to simulate thousands of PPPoE or IPoE subscribers including IPTV, traffic verification and convergence testing capabilities. -logo: images/rtbrick_logo.png -theme: jekyll-theme-minimal diff --git a/docs/a10nsp.md b/docs/a10nsp.md deleted file mode 100644 index bdab7fcb..00000000 --- a/docs/a10nsp.md +++ /dev/null @@ -1,74 +0,0 @@ -# A10NSP - -The A10NSP interface emulates an layer two provider interface. The term A10 -refers to the end-to-end ADSL network reference model from TR-025. - -Following a basic PPPoE/A10NSP configuration example which is -detailed explained in the configuration section. - -```json -{ - "interfaces": { - "rx-interval": 1, - "a10nsp": [ - { - "interface": "eth4", - "qinq": true, - "mac": "02:00:00:ff:ff:01" - }, - { - "interface": "eth5", - "qinq": true, - "mac": "02:00:00:ff:ff:01" - } - ], - "access": [ - { - "__comment__": "PPPoE", - "interface": "eth1", - "type": "pppoe", - "outer-vlan-min": 1, - "outer-vlan-max": 4000, - "inner-vlan": 7, - "stream-group-id": 1 - } - ] - }, - "pppoe": { - "reconnect": true, - "discovery-timeout": 3, - "discovery-retry": 10, - "host-uniq": true, - "vlan-priority": 6 - }, - "dhcpv6": { - "enable": false - }, - "session-traffic": { - "autostart": true, - "ipv4-pps": 10 - }, - "streams": [ - { - "stream-group-id": 2, - "name": "PPPOE-S1", - "type": "ipv4", - "direction": "both", - "priority": 128, - "length": 256, - "pps": 10, - "a10nsp-interface": "eth4" - }, - { - "stream-group-id": 2, - "name": "PPPOE-S2", - "type": "ipv4", - "direction": "both", - "priority": 128, - "length": 256, - "pps": 10, - "a10nsp-interface": "eth5" - } - ] -} -``` diff --git a/docs/bgp.md b/docs/bgp.md deleted file mode 100644 index e58ec2a7..00000000 --- a/docs/bgp.md +++ /dev/null @@ -1,170 +0,0 @@ -# BGP - -The Border Gateway Protocol (BGP) is a standardized exterior gateway protocol -designed to exchange routing and reachability information among autonomous systems -(AS) on the internet. BGP is classified as a path-vector routing protocol, and it -makes routing decisions based on paths, network policies, or rule-sets configured -by a network operator. - -Following an example BGP configuration with one session. - -```json -{ - "interfaces": { - "network": [ - { - "interface": "eth1", - "address": "10.0.1.2/24", - "gateway": "10.0.1.1" - } - ] - }, - "bgp": [ - { - "local-ipv4-address": "10.0.1.2", - "peer-ipv4-address": "10.0.1.1", - "raw-update-file": "test.bgp", - "local-as": 65001, - "peer-as": 65001 - } - ] -} -``` - -## BGP Sessions - -Every BGP session is opened with the capabilities for the following -address families: - -+ IPv4 unicast -+ IPv4 labelled unicast -+ IPv6 unicast -+ IPv6 labelled unicast - -## Limitations - -BGP authentication is currently not supported but already -planned as enhancement in one of the next releases. - -## RAW Update Files - -The BNG Blaster is able to inject BGP messages from a pre-compiled -RAW update file into the defined sessions. A RAW update file is not -more than a pre-compiled binary stream of BGP messages, typically -but not limited to update messages. - -```text - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | | - + + - | | - + + - | Marker | - + + - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Length | Type | ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++++ - . - . - . - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | | - + + - | | - + + - | Marker | - + + - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Length | Type | ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++++ -``` - -Those files can be created using the included BGP RAW update generator -script `bgpupdate` or manually using libraries like scapy or converters -from PCAP or MRT files. - -The configured `raw-update-file` under the BGP session is loaded -during Blaster startup phase and send as soon as the session is -established. - -The `bgp-raw-update` command allows to send further updates during -the session lifetime. - -`$ sudo bngblaster-cli run.sock bgp-raw-update file update1.bgp` - -This allows in example to load a full table after session has -started and manually trigger a series of changes using incremental -updates files. - -All BGP RAW update files are loaded once and can than be used by -multiple sessions. Meaning if two or more sessions reference the -same file identified by file name, this file is loaded once into -memory and used by multiple sessions. - -Therefore for incremental updates, it may makes sense to pre-load -via `bgp-raw-update-files` configuration. - -```json -{ - "bgp": [ - { - "local-ipv4-address": "10.0.1.2", - "peer-ipv4-address": "10.0.1.1", - "raw-update-file": "start.bgp", - "local-as": 65001, - "peer-as": 65001 - } - ], - "bgp-raw-update-files": [ - "update1.bgp", - "update2.bgp" - ] -} -``` - -Incremental updates not listed here will be loaded dynamically as soon -as referenced by first session. - -## BGP RAW Update Generator - -The BGP RAW update generator is a simple tool to generate BGP RAW update -streams for use with the BNG Blaster. - -```text -$ bgpupdate --help -usage: bgpupdate [-h] [-a ASN] -n ADDRESS [-N N] -p PREFIX [-P N] [-m LABEL] - [-M N] [-l LOCAL_PREF] [-f FILE] [-w] [--end-of-rib] - [--append] [--pcap FILE] [--log-level {warning,info,debug}] - -optional arguments: - -h, --help show this help message and exit - -a ASN, --asn ASN autonomous system number - -n ADDRESS, --next-hop-base ADDRESS - next-hop base address (IPv4 or IPv6) - -N N, --next-hop-num N - next-hop count - -p PREFIX, --prefix-base PREFIX - prefix base network (IPv4 or IPv6) - -P N, --prefix-num N prefix count - -m LABEL, --label-base LABEL - label base - -M N, --label-num N label count - -l LOCAL_PREF, --local-pref LOCAL_PREF - local preference - -f FILE, --file FILE output file - -w, --withdraw withdraw prefixes - --end-of-rib add end-of-rib message - --append append to file if exist - --pcap FILE write BGP updates to PCAP file - --log-level {warning,info,debug} - logging Level -``` - -The python BGP RAW update generator is a python script which uses -scapy to build BGP messages. Therefore this tool can be easily -modified, extend or used as blueprint for your own tools to generate -valid BGP update streams. diff --git a/docs/config.md b/docs/config.md deleted file mode 100644 index ad2c6c8f..00000000 --- a/docs/config.md +++ /dev/null @@ -1,950 +0,0 @@ -# Configuration - -Following an example configuration file which is explained in detail below. - -```json -{ - "interfaces": { - "network": { - "interface": "eth2", - "address": "10.0.0.1", - "gateway": "10.0.0.2", - "address-ipv6": "fc66:1337:7331::1", - "gateway-ipv6": "fc66:1337:7331::2" - }, - "access": [ - { - "interface": "eth1", - "outer-vlan-min": 1000, - "outer-vlan-max": 1999, - "inner-vlan-min": 1, - "inner-vlan-max": 4049, - "authentication-protocol": "PAP" - }, - { - "interface": "eth1", - "outer-vlan-min": 2000, - "outer-vlan-max": 2999, - "inner-vlan-min": 1, - "inner-vlan-max": 4049, - "authentication-protocol": "CHAP" - } - ] - }, - "sessions": { - "count": 1000, - "session-time": 0, - "max-outstanding": 800, - "start-rate": 400, - "stop-rate": 400 - }, - "pppoe": { - "reconnect": true, - "discovery-timeout": 3, - "discovery-retry": 10 - }, - "ppp": { - "mru": 1492, - "authentication": { - "username": "user{session-global}@rtbrick.com", - "password": "test", - "timeout": 5, - "retry": 30 - }, - "lcp": { - "conf-request-timeout": 1, - "conf-request-retry": 10, - "keepalive-interval": 30, - "keepalive-retry": 3 - }, - "ipcp": { - "enable": true, - "request-ip": true, - "request-dns1": true, - "request-dns2": true, - "conf-request-timeout": 1, - "conf-request-retry": 10 - }, - "ip6cp": { - "enable": true, - "conf-request-timeout": 1, - "conf-request-retry": 10 - } - }, - "dhcpv6": { - "enable": true, - "rapid-commit": true - }, - "access-line": { - "agent-remote-id": "DEU.RTBRICK.{session-global}", - "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:{session-global}", - "rate-up": 1024, - "rate-down": 16384 - }, - "session-traffic": { - "ipv4-pps": 1, - "ipv6-pps": 1, - "ipv6pd-pps": 1 - } -} -``` - -## Interfaces - -This section describes all attributes of the `interfaces` hierarchy -which allows to modify how to send and receive traffic. - -```json -{ - "interfaces": { - "tx-interval": 0.1, - "rx-interval": 0.1, - "io-slots": 2048, - } -} -``` - -Attribute | Description | Default ---------- | ----------- | ------- -`tx-interval` | TX ring polling interval in milliseconds | 5.0 -`rx-interval` | RX ring polling interval in milliseconds | 5.0 -`qdisc-bypass` | Bypass the kernel's qdisc layer | true -`io-mode` | IO mode | packet_mmap_raw -`io-slots` | IO slots (ring size) | 1024 -`io-stream-max-ppi` | IO traffic stream max packets per interval | 32 -`capture-include-streams` | Include traffic streams in capture | true - -The `tx-interval` and `rx-interval` should be set to at to at least `1.0` (1ms) -if more precise timestamps are needed. This is recommended for IGMP join/leave -or QoS delay measurements. For higher packet rates (>1g) it might be needed to -increase the `io-slots` from the default value of `1024` to `2048` or more. - -The supported IO modes are listed with `bngblaster -v` but except -`packet_mmap_raw` all other modes are currently considered as experimental. In -the default mode (`packet_mmap_raw`) all packets are received in a Packet MMAP -ring buffer and send directly trough RAW packet sockets. - -**WARNING**: Disable `qdisc-bypass` only if BNG Blaster is not sending traffic! - -The interfaces used in BNG Blaster do not need IP addresses configured in the host -operating system but they need to be in up state. - -```cli -sudo ip link set dev up -``` - -It is not possible to send packets larger than the interface MTU which is 1500 per default -but for PPPoE with multiple VLAN headers this might be not enough for large packets. -Therefore the interface MTU should be increased using the following commands. - -```cli -sudo ip link set mtu 9000 dev -``` - -This can be also archived via netplan using the following configuration for each BNG Blaster -interface. - -```yaml -network: - version: 2 - renderer: networkd - ethernets: - eth1: - dhcp4: no - dhcp6: no - link-local: [] - mtu: 9000 - eth2: - dhcp4: no - dhcp6: no - link-local: [] - mtu: 9000 -``` - -The number of interfaces is currently limited to 32! - -### Network Interface - -`"interfaces": { "network": { ... } }` - -Attribute | Description | Default ---------- | ----------- | ------- -`interface` | Network interface name (e.g. eth0, ...) -`address` | Local network interface IPv4 address -`gateway` | Gateway network interface IPv4 address -`address-ipv6` | Local network interface IPv6 address (implicitly /64) | - -`gateway-ipv6` | Gateway network interface IPv6 address (implicitly /64) -`vlan` | Network interface VLAN | 0 (untagged) -`gateway-mac`| Optional set gateway MAC address manually -`gateway-resolve-wait` | Sessions will not start until gateways are resolved | true -`isis-instance-id` | Assign interface to ISIS instance | - -`isis-level` | ISIS interface level | 3 -`isis-p2p` | ISIS P2P interface | true -`isis-l1-metric` | ISIS level 1 interface metric | 10 -`isis-l2-metric` | ISIS level 2 interface metric | 10 - -The BNG Blaster supports also multiple network interfaces -or VLAN ranges as shown in the example below. - -```json -{ - "interfaces": { - "tx-interval": 1, - "rx-interval": 1, - "io-slots": 4096, - "network": [ - { - "interface": "eth2", - "address": "10.0.0.1", - "gateway": "10.0.0.2", - "address-ipv6": "fc66:1337:7331::1", - "gateway-ipv6": "fc66:1337:7331::2" - }, - { - "interface": "eth3", - "address": "10.0.1.1", - "gateway": "10.0.1.2", - "address-ipv6": "fc66:1337:7331:1::1", - "gateway-ipv6": "fc66:1337:7331:1::2" - } - ], - } -} -``` - -Using multiple network interfaces requires to select which network interface -to be used otherwise one of the interface is selected automatically. Therefore -the option `network-interface` is supported in different sections. - -### Access Interfaces - -`"interfaces": { "access": { ... } }` - -Attribute | Description | Default ---------- | ----------- | ------- -`interface` | Access interface name (e.g. eth0, ...) -`network-interface` | Select the corresponding network interface for this session | -`type` | Switch the access type between `pppoe` (PPP over Ethernet) and `ipoe` (IP over Ethernet) | pppoe -`vlan-mode` | Set VLAN mode `1:1` or `N:1` | 1:1 -`qinq` | Set outer VLAN ethertype to QinQ (0x88a8) | false -`outer-vlan-min` | Outer VLAN minimum value | 0 (untagged) -`outer-vlan-max` | Outer VLAN maximum value | 0 (untagged) -`outer-vlan` |Set outer-vlan-min/max equally -`inner-vlan-min` | Inner VLAN minimum value | 0 (untagged) -`inner-vlan-max` | Inner VLAN maximum value | 0 (untagged) -`inner-vlan` |Set inner-vlan-min/max equally -`third-vlan` | Add a fixed third VLAN (most inner VLAN) as required for some lab environments | 0 (untagged) -`address` | Static IPv4 base address (IPoE only) -`address-iter` | Static IPv4 base address iterator (IPoE only) -`gateway` | Static IPv4 gateway address (IPoE only) -`gateway-iter` | Static IPv4 gateway address iterator (IPoE only) -`username` | Optionally overwrite the username from authentication section per access configuration -`password` | Optionally overwrite the password from authentication section per access configuration -`authentication-protocol` | Optionally overwrite the username from authentication section per access configuration -`agent-circuit-id` | Optionally overwrite the agent-circuit-id from access-line section per access configuration -`agent-remote-id` | Optionally overwrite the agent-remote-id from access-line section per access configuration -`rate-up` | Optionally overwrite the rate-up from access-line section per access configuration -`rate-down` | Optionally overwrite the rate-down from access-line section per access configuration -`dsl-type` | Optionally overwrite the dsl-type from access-line section per access configuration -`ipcp` | Optionally enable/disable PPP IPCP per access configuration -`ip6cp` | Optionally enable/disable PPP IP6CP per access configuration -`ipv4` | Optionally enable/disable IPoE IPv4 per access configuration -`ipv6` | Optionally enable/disable IPoE IPv6 per access configuration -`dhcp` | Optionally enable/disable DHCP per access configuration -`dhcpv6` | Optionally enable/disable DHCPv6 per access configuration -`igmp-autostart` | Optionally overwrite IGMP autostart per access configuration -`igmp-version` | Optionally overwrite IGMP protocol version (1, 2 or 3) per access configuration -`stream-group-id` | Optional stream group identifier -`access-line-profile-id` | Optional access-line-profile identifier -`cfm-cc` | Optionally enable/disable EOAM CFM CC (IPoE only) | false -`cfm-level` | Set EOAM CFM maintenance domain level | 0 -`cfm-ma-id` | Set EOAM CFM maintenance association identifier | 0 -`cfm-ma-name` | Set EOAM CFM maintenance association short name -`i1-start` | Iterator for usage in strings `{i1}` | 1 -`i1-step` | Iterator step per session | 1 -`i2-start` | Iterator for usage in strings `{i2}` | 1 -`i2-step` | Iterator step per session | 1 - -For all modes it is possible to configure between zero and three VLAN -tags on the access interface as shown below. - -```text -[ethernet][outer-vlan][inner-vlan][third-vlan][pppoe]... -``` - -#### Untagged - -With untagged only one session is possible. - -```json -{ - "access": { - "interface": "eth1", - "outer-vlan-min": 0, - "outer-vlan-max": 0, - "inner-vlan-min": 0, - "inner-vlan-max": 0 - } -} -``` - -#### Single Tagged - -```json -{ - "access": { - "interface": "eth1", - "outer-vlan-min": 1, - "outer-vlan-max": 4049, - "inner-vlan-min": 0, - "inner-vlan-max": 0 - } -} -``` - -#### Double Tagged - -```json -{ - "access": { - "interface": "eth1", - "outer-vlan-min": 1, - "outer-vlan-max": 4049, - "inner-vlan-min": 7, - "inner-vlan-max": 7 - } -} -``` - -#### Triple Tagged - -```json -{ - "access": { - "interface": "eth1", - "outer-vlan-min": 10, - "outer-vlan-max": 20, - "inner-vlan-min": 128, - "inner-vlan-max": 4000, - "third-vlan": 7 - } -} -``` - -The BNG Blaster supports also multiple access interfaces -or VLAN ranges as shown in the example below. - -```json -{ - "access": [ - { - "interface": "eth1", - "type": "pppoe", - "username": "pta@rtbrick.com", - "outer-vlan-min": 1000, - "outer-vlan-max": 1999, - "inner-vlan-min": 7, - "inner-vlan-max": 7 - }, - { - "interface": "eth1", - "type": "pppoe", - "username": "l2tp@rtbrick.com", - "outer-vlan-min": 2000, - "outer-vlan-max": 2999, - "inner-vlan-min": 7, - "inner-vlan-max": 7 - }, - { - "interface": "eth3", - "type": "pppoe", - "username": "test@rtbrick.com", - "outer-vlan-min": 128, - "outer-vlan-max": 4000, - "inner-vlan-min": 7, - "inner-vlan-max": 7 - }, - { - "interface": "eth4", - "type": "ipoe", - "outer-vlan-min": 8, - "outer-vlan-max": 9, - "address": "200.0.0.1", - "address-iter": "0.0.0.4", - "gateway": "200.0.0.2", - "gateway-iter": "0.0.0.4" - } - ] -} -``` - -Both network and access interfaces are optional but obviously at least -one interface is required to start the BNG Blaster. - -The configuration attributes for username, agent-remote-id and agent-circuit-id -support also some variable substitution. The variable `{session-global}` will -be replaced with a number starting from 1 and incremented for every new session. -where as the variable `{session}` is incremented per interface section. - -In VLAN mode `N:1` only one VLAN combination is supported per access interface section. -This means that only VLAN min or max is considered as VLAN identifier. - -```json -{ - "access": [ - { - "interface": "eth1", - "type": "pppoe", - "vlan-mode": "N:1", - "username": "test@rtbrick.com", - "outer-vlan-min": 7 - }, - { - "interface": "eth2", - "type": "pppoe", - "vlan-mode": "N:1", - "username": "test@rtbrick.com", - "outer-vlan-min": 2000, - "inner-vlan-min": 7, - }, - ] -} -``` - -### A10NSP Interface - -`"interfaces": { "a10nsp": { ... } }` - -Attribute | Description | Default ---------- | ----------- | ------- -`interface` | A10nSP interface name (e.g. eth0, ...) -`qinq` | Set outer VLAN ethertype to QinQ (0x88a8) | false -`mac`| Optional set gateway interface address manually - -The BNG Blaster supports also multiple A10NSP interfaces -as shown in the example below. - -```json -{ - "interfaces": { - "tx-interval": 1, - "rx-interval": 1, - "a10nsp": [ - { - "interface": "eth4", - "qinq": true, - "mac": "02:00:00:ff:ff:01" - }, - { - "interface": "eth5", - "qinq": false, - "mac": "02:00:00:ff:ff:02" - } - ], - } -} -``` - -## Sessions - -This section describes all attributes of the `sessions` hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`count` | Sessions (PPPoE + IPoE) | 1 -`max-outstanding` | Max outstanding sessions | 800 -`start-rate` | Setup request rate in sessions per second | 400 -`stop-rate` | Teardown request rate in sessions per second | 400 -`iterate-vlan-outer` | Iterate on outer VLAN first | false -`start-delay` | Wait N seconds after all interface are resolved before starting sessions | 0 - -Per default sessions are created by iteration over inner VLAN range first and outer VLAN second. -Which can be changed by `iterate-vlan-outer` to iterate on outer VLAN first and inner VLAN second. - -Therefore the following configuration generates the sessions on VLAN (outer:inner) 1:3, 1:4, 2:3, 2:4 per default or alternative 1:3, 2:3, 1:4, 2:4 with `iterate-vlan-outer` enabled. - -```json -{ - "outer-vlan-min": 1, - "outer-vlan-max": 2, - "inner-vlan-min": 3, - "inner-vlan-max": 4 -} -``` - -## IPoE - -This section describes all attributes of the `ipoe` (IP over Ethernet) hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`ipv4` | Enable/disable IPv4 | true (enabled) -`arp-timeout` | Initial ARP resolve timeout/retry interval in seconds | 1 -`arp-interval` | Periodic ARP interval in seconds (0 means disabled) | 300 -`ipv6` | Enable/disable IPv6 | true (enabled) - -## PPPoE - -This section describes all attributes of the `pppoe` (PPP over Ethernet) hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`session-time` | Max PPPoE session time in seconds | 0 (infinity) -`reconnect` | Automatically reconnect sessions if terminated | false -`discovery-timeout` | PPPoE discovery (PADI and PADR) timeout in seconds | 5 -`discovery-retry` | PPPoE discovery (PADI and PADR) max retry | 10 -`service-name` | PPPoE discovery service name | -`host-uniq` | PPPoE discovery host-uniq | false -`vlan-priority` | VLAN PBIT for all PPPoE/PPP control traffic | 0 - -## PPP - -This section describes all attributes of the `ppp` hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`mru` | Define the maximum receive unit proposed via PPP | 1492 - -### PPP Authentication - -`"ppp": { "authentication": { ... } }` - -Attribute | Description | Default ---------- | ----------- | ------- -`username` | Username | user{session-global}@rtbrick.com -`password` |Password | test -`timeout` | Authentication request timeout in seconds | 5 -`retry` | Authentication request max retry | 30 -`protocol` | This value can be set to `PAP` or `CHAP` to reject the other protocol | allow PAP and CHAP - -### PPP LCP - -`"ppp": { "lcp": { ... } }` - -Attribute | Description | Default ---------- | ----------- | ------- -`conf-request-timeout` | LCP configuration request timeout in seconds | 5 -`conf-request-retry` | LCP configuration request max retry | 10 -`keepalive-interval` | LCP echo request interval in seconds (0 means disabled) | 30 -`keepalive-retry` | PPP LCP echo request max retry | 3 -`start-delay` | PPP LCP initial request delay in milliseconds | 0 -`ignore-vendor-specific` | Ignore LCP vendor specific requests | false -`connection-status-message` | Accept LCP connection status messages | false - -### PPP IPCP - -`"ppp": { "ipcp": { ... } }` - -Attribute | Description | Default ---------- | ----------- | ------- -`enable` | This option allows to enable or disable the IPCP protocol | true -`request-ip` | Include IP-Address with 0.0.0.0 in initial LCP configuration request | true -`request-dns1` | Request Primary DNS Server Address (option 129) | true -`request-dns2` | Request Secondary DNS Server Address (option 131) | true -`conf-request-timeout` | IPCP configuration request timeout in seconds | 5 -`conf-request-retry` | IPCP configuration request max retry | 10 - -### PPP IP6CP - -`"ppp": { "ipcp": { ... } }` - -Attribute | Description | Default ---------- | ----------- | ------- -`enable` | This option allows to enable or disable the IP6CP protocol | true -`conf-request-timeout` | IP6CP configuration request timeout in seconds | 5 -`conf-request-retry` | IP6CP configuration request max retry | 10 - -## DHCP - -This section describes all attributes of the `dhcp` hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`enable` | This option allows to enable or disable DHCP | false -`broadcast` | DHCP broadcast flag | false -`timeout` | DHCP timeout in seconds | 5 -`retry` | DHCP retry | 10 -`release-interval` | DHCP release interval | 1 -`release-retry` | DHCP release retry | 3 -`tos` | IPv4 TOS for all DHCP control traffic | 0 -`vlan-priority` | VLAN PBIT for all DHCP control traffic | 0 - -## DHCPv6 - -This section describes all attributes of the `dhcpv6` hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`enable` | This option allows to enable or disable DHCPv6 | true -`rapid-commit` | DHCPv6 rapid commit (2 way handshake) | true -`timeout` | DHCPv6 timeout in seconds | 5 -`retry` | DHCPv6 retry | 10 - -## IGMP - -This section describes all attributes of the `igmp` hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`autostart` | Automatically join after session is established | true -`version` | IGMP protocol version (1, 2 or 3) | 3 -`combined-leave-join` | Combine leave and join records within a single IGMPv3 report | true -`start-delay` | Delay between session established and initial IGMP join in seconds | 1 -`group` | Multicast group base address (e.g. 239.0.0.1) | 0.0.0.0 (disabled) -`group-iter` | Multicast group iterator | 0.0.0.1 -`group-count` | Multicast group count | 1 -`source` | Multicast source address (e.g. 1.1.1.1) | 0.0.0.0 (ASM) -`zapping-interval` | IGMP channel zapping interval in seconds | 0 (disabled) -`zapping-count` | Define the amount of channel changes before starting view duration | 0 (disabled) -`view-duration` | Define the view duration in seconds | 0 (disabled) -`send-multicast-traffic` | Generate multicast traffic | false -`multicast-traffic-length` | Multicast traffic IP length | 76 -`multicast-traffic-tos` | Multicast traffic TOS priority | 0 -`network-interface` | Multicast traffic source interface | - -Per default join and leave requests are send using dedicated reports. The option `combined-leave-join` allows -the combination of leave and join records within a single IGMPv3 report using multiple group records. -This option is applicable to IGMP version 3 only! - -If `send-multicast-traffic` is true, the BNG Blaster generates multicast traffic on the network interface -based on the specified group and source attributes mentioned before. This traffic includes some special -signatures for faster processing and more detailed analysis. - -If group is set to 293.0.0.1 with group-iter of 0.0.0.2, source 1.1.1.1 and group-count 3 the result are the following -three groups (S.G) 1.1.1.1,239.0.0.1, 1.1.1.1,239.0.0.3 and 1.1.1.1,239.0.0.5. - -## L2TP Server (LNS) - -This section describes all attributes of the `l2tp-server` (LNS) hierarchy -as explained in [L2TPv2](l2tp). - -The BNG Blaster supports multiple L2TPv2 servers (LNS) over the network interface -as shown in the example below. - -```json -{ - "interfaces": { - "network": { - "interface": "eth2", - "address": "10.0.0.1", - "gateway": "10.0.0.2" - } - }, - "l2tp-server": [ - { - "name": "LNS1", - "address": "10.0.0.10", - "secret": "test1", - }, - { - "name": "LNS2", - "address": "10.0.0.11", - "secret": "test2", - }, - ] -} -``` - -There is actually no hard limit in the amount of L2TP servers. - -Attribute | Description | Default ---------- | ----------- | ------- -`name` | Mandatory L2TP LNS server hostname (AVP 7) | -`address` | Mandatory L2TP server address | -`secret` | Tunnel secret | -`receive-window-size` | Control messages receive window size | 4 -`max-retry` | Control messages max retry | 30 -`congestion-mode` | Control messages congestion mode | default -`data-control-priority` | Set the priority bit in the L2TP header for all non-IP data packets (LCP, IPCP, ...) | false -`data-length` | Set length bit for all data packets | false -`data-offset` | Set offset bit with offset zero for all data packets | false -`control-tos` | L2TP control traffic (SCCRQ, ICRQ, ...) TOS priority | 0 -`data-control-tos` | Set the L2TP tunnel TOS priority (outer IPv4 header) for all non-IP data packets (LCP, IPCP, ...) | 0 - -The BNG Blaster supports different congestion modes for the -reliable delivery of control messages. The `default` mode -is described in RFC2661 appendix A (Control Channel Slow Start and -Congestion Avoidance). The mode `slow` uses a fixed control window -size of 1 where `aggressive` sticks to max permitted based on peer -received window size. - -## Traffic - -This section describes all attributes of the `traffic` hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`autostart` | Automatically start traffic | true -`stop-verified` | Automatically stop traffic streams if verified | false - -## Session Traffic - -This section describes all attributes of the `session-traffic` hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`autostart` | Automatically start session traffic after session is established | true -`ipv4-pps` | Generate bidirectional IPv4 traffic between network interface and all session framed IPv4 addresses | 0 (disabled) -`ipv6-pps` | Generate bidirectional IPv6 traffic between network interface and all session framed IPv6 addresses | 0 (disabled) -`ipv6pd-pps` | Generate bidirectional Ipv6 traffic between network interface and all session delegated IPv6 addresses | 0 (disabled) - -## Traffic Streams - -This section describes all attributes of the `streams` hierarchy -as explained in [Traffic Streams](streams). - -Attribute | Description | Default ---------- | ----------- | ------- -`name` | Mandatory stream name | -`stream-group-id` | Stream group identifier | 0 (raw) -`type` | Mandatory stream type (`ipv4`, `ipv6` or `ipv6pd`) | -`direction` | Mandatory stream direction (`upstream`, `downstream` or `both`) | `both` -`priority` | IPv4 TOS / IPv6 TC | 0 -`vlan-priority` | VLAN priority | 0 -`length` | Layer 3 (IP + payload) traffic length (76 - 9000) | 128 -`pps` | Stream traffic rate in packets per second | 1 -`bps` | Stream traffic rate in bits per second (layer 3) | -`a10nsp-interface` | Select the corresponding A10NSP interface for this stream | -`network-interface` | Select the corresponding network interface for this stream | -`network-ipv4-address` | Overwrite network interface IPv4 address | -`network-ipv6-address` | Overwrite network interface IPv6 address | -`destination-ipv4-address` | Overwrite the IPv4 destination address | -`destination-ipv6-address` | Overwrite the IPv6 destination address | -`access-ipv4-source-address` | Overwrite the access IPv4 source address (client) | -`access-ipv6-source-address` | Overwrite the access IPv6 source address (client) | -`threaded` | Run those streams in separate threads | false -`thread-group` | Assign this stream to thread group (1-255) | 0 (thread per stream) -`max-packets` | Send a burst of N packets and stop | 0 (infinity) -`start-delay` | Wait N seconds after session is established before start | 0 -`tx-label1` | MPLS send (TX) label (outer label) | -`tx-label1-exp` | EXP bits of first label (outer label) | 0 -`tx-label1-ttl` | TTL of first label (outer label) | 255 -`tx-label2` | MPLS send (TX) label (inner label) | -`tx-label2-exp` | EXP bits of first label (inner label) | 0 -`tx-label2-ttl` | TTL of first label (inner label) | 255 -`rx-label1` | Expected receive MPLS label (outer label) | -`rx-label2` | Expected receive MPLS label (inner label) | - -For L2TP downstream traffic the IPv4 TOS is applied to the outer IPv4 and inner IPv4 header. - -The `pps` option supports also float numbers like 0.1, or 2.5 PPS and has priority over `bps` -where second is only a helper to calculate the `pps` based on given `bps` and `length`. - -The options `access-ipv4-source-address` and `access-ipv6-source-address` are used -to test the BNG RPF functionality with traffic send from source addresses different -to those assigned to the client. - -## Access-Line - -This section describes all attributes of the `access-line` hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`agent-circuit-id` | Agent-Circuit-Id | -`agent-remote-id` | Agent-Remote-Id | -`rate-up` | Actual Data Rate Upstream | -`rate-down` | Actual Data Rate Downstream | -`dsl-type` | DSL-Type | - -## Access-Line-Profiles - -This section describes all attributes of the `access-line-profiles` hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`access-line-profile-id` | Mandatory access-line-profile identifier -`act-up` | Actual Data Rate Upstream | 0 -`act-down` | Actual Data Rate Downstream | 0 -`min-up` | Minimum Data Rate Upstream | 0 -`min-down` | Minimum Data Rate Downstream | 0 -`att-up` | Attainable DataRate Upstream | 0 -`att-down` | Attainable DataRate Downstream | 0 -`max-up` | Maximum Data Rate Upstream | 0 -`max-down` | Maximum Data Rate Downstream | 0 -`min-up-low` | Min Data Rate Upstream in low power state | 0 -`min-down-low` | Min Data Rate Downstream in low power state | 0 -`max-interl-delay-up` | Max Interleaving Delay Upstream | 0 -`act-interl-delay-up` | Actual Interleaving Delay Upstream | 0 -`max-interl-delay-down` | Max Interleaving Delay Downstream | 0 -`act-interl-delay-down` | Actual Interleaving Delay Downstream | 0 -`data-link-encaps` | Data Link Encapsulation | 0 -`dsl-type` | DSL Type | 0 -`pon-type` | PON Access Type | 0 -`etr-up` | Expected Throughput (ETR) Upstream | 0 -`etr-down` | Expected Throughput (ETR) Downstream | 0 -`attetr-up` | Attainable Expected Throughput (ATTETR) Upstream | 0 -`attetr-down` | Attainable Expected Throughput (ATTETR) Downstream | 0 -`gdr-up` | Gamma Data Rate (GDR) Upstream | 0 -`gdr-down` | Gamma Data Rate (GDR) Downstream | 0 -`attgdr-up` | Attainable Gamma Data Rate (ATTGDR) Upstream | 0 -`attgdr-down` | Attainable Gamma Data Rate (ATTGDR) Downstream | 0 -`ont-onu-avg-down` | ONT/ONU Average Data Rate Downstream | 0 -`ont-onu-peak-down` | ONT/ONUPeak Data Rate Downstream | 0 -`ont-onu-max-up` | ONT/ONU Maximum Data Rate Upstream | 0 -`ont-onu-ass-up` | ONT/ONU Assured Data Rate Upstream | 0 -`pon-max-up` | PON Tree Maximum Data Rate Upstream | 0 -`pon-max-down` | PON Tree Maximum Data Rate Downstream | 0 - -Attributes with value set to 0 will not be send. - -The values for `rate-up`, `rate-down` and `dsl-type` defined in the -access-line or interface section have priority over those defined -here. - -```json -{ - "access-line-profiles": [ - { - "access-line-profile-id": 1, - "act-up": 2000, - "act-down": 16000, - "min-up": 64, - "min-down": 1024, - "att-up": 2048, - "att-down": 16384, - "max-up": 2040, - "max-down": 16380, - "min-up-low": 32, - "min-down-low": 1024, - "max-interl-delay-up": 100, - "act-interl-delay-up": 10, - "max-interl-delay-down": 100, - "act-interl-delay-down": 10, - "data-link-encaps": 525061, - "dsl-type": 5, - }, - { - "access-line-profile-id": 2, - "act-up": 40000, - "act-down": 100000, - "pon-type": 1, - "etr-up": 40000, - "etr-down": 100000, - "attetr-up": 40000, - "attetr-down": 100000, - "gdr-up": 40000, - "gdr-down": 100000, - "attgdr-up": 40000, - "attgdr-down": 100000, - "ont-onu-avg-down": 100000, - "ont-onu-peak-down": 100000, - "ont-onu-max-up": 40000, - "ont-onu-ass-up": 40000, - "pon-max-up": 1000000, - "pon-max-down": 2400000 - } - ] -} -``` - -## ISIS - -This section describes all attributes of the `isis` hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`instance-id` | ISIS instance identifier | -`level` | ISIS level | 3 -`overload` | ISIS overload | false -`protocol-ipv4` | Enable/disable IPv4 | true -`protocol-ipv6` | Enable/disable IPv6 | true -`level1-auth-key` | ISIS level 1 authentication key | -`level1-auth-type` | ISIS level 1 authentication type (simple or md5) | disabled -`level2-auth-key` | ISIS level 2 authentication key | -`level2-auth-type` | ISIS level 2 authentication type (simple or md5) | disabled -`hello-interval` | ISIS hello interval in seconds | 10 -`hello-padding` | ISIS hello padding | false -`holding-time` | ISIS holding time in seconds | 30 -`lsp-lifetime` | ISIS LSP lifetime in seconds | 65535 -`lsp-refresh-interval` | ISIS LSP refresh interval in seconds | 300 -`lsp-retry-interval` | ISIS LSP retry interval in seconds | 5 -`lsp-tx-interval` | ISIS LSP TX interval in ms (time between LSP send windows) | 10 -`lsp-tx-window-size` | ISIS LSP TX window size (LSP send per window) | 1 -`csnp-interval` | ISIS CSNP interval in seconds | 30 -`hostname` | ISIS hostname | bngblaster -`router-id` | ISIS router identifier | 10.10.10.10 -`system-id` | ISIS system identifier | 0100.1001.0010 -`area` | ISIS area(s) | 49.0001/24 -`sr-base` | ISIS SR base | -`sr-range` | ISIS SR range | -`sr-node-sid` | ISIS SR node SID | -`teardown-time` | ISIS teardown time in seconds | 5 - -### ISIS External - -The BNG Blaster allows to inject LSP's via MRT files as defined in -[RFC6396](https://datatracker.ietf.org/doc/html/rfc6396). Details -to MRT files can be found in [ISIS](isis). - -`"isis": { "external": { ... } }` - -Attribute | Description | Default ---------- | ----------- | ------- -`mrt-file` | ISIS MRT file | - -It is also possible to define external connections as required -to connect the ISIS instance with the link state graph in the MTR -file. - -`"isis": { "external": { "connections": [] } }` - -Attribute | Description | Default ---------- | ----------- | ------- -`system-id` | ISIS system identifier | -`l1-metric` | ISIS level 1 interface metric | 10 -`l2-metric` | ISIS level 2 interface metric | 10 - -```json -{ - "isis": [ - { - "instance-id": 1, - "system-id": "0100.1001.0010", - "router-id": "10.10.10.10", - "hostname": "R1", - "external": { - "mrt-file": "test.mrt", - "connections": [ - { - "system-id": "0000.0000.0001", - "l1-metric": 1000, - "l2-metric": 2000 - } - ] - } - } - ] -} -``` - -## BGP - -This section describes all attributes of the `bgp` hierarchy. - -Attribute | Description | Default ---------- | ----------- | ------- -`network-interface` | BGP local interface (source-interface) | first network interface -`local-ipv4-address` | BGP local IPv4 address (source-address) | network interface address -`local-as` | BGP local AS | 65000 -`peer-ipv4-address` | BGP peer address | -`peer-as` | BGP peer AS | local AS -`holdtime` | BGP holdtime in seconds | 90 -`id` | BGP identifier | 1.2.3.4 -`reconnect` | BGP reconnect | true -`start-traffic` | BGP start global traffic after RAW update | false -`teardown-time` | BGP teardown time in seconds | 5 -`raw-update-file` | BGP RAW update file | - -```json -{ - "bgp": [ - { - "local-ipv4-address": "10.0.1.2", - "peer-ipv4-address": "10.0.1.1", - "raw-update-file": "start.bgp", - "local-as": 65001, - "peer-as": 65001 - } - ] -} -``` \ No newline at end of file diff --git a/docs/ctrl.md b/docs/ctrl.md deleted file mode 100644 index e0a6fa05..00000000 --- a/docs/ctrl.md +++ /dev/null @@ -1,292 +0,0 @@ -# Control Socket - -The control socket is an unix domain stream socket which allows the control daemon to -interact with the BNG Blaster using JSON RPC. This interface was primary developed for -the BNG Blaster Controller but can be also used manually or by other tools like the -simple CLI tool `bngblaster-cli` for interactive communication with the BNG Blaster. - -The control socket will be optionally enabled by providing the path to the socket file -using the argument `-S` (`bngblaster -S test.socket`). - -`$ cat command.json | jq .` - -```json -{ - "command": "session-counters" -} -``` - -`$ cat command.json | sudo nc -U test.socket | jq .` - -```json -{ - "status": "ok", - "code": 200, - "session-counters": { - "sessions": 3, - "sessions-established": 3, - "sessions-flapped": 3, - "dhcpv6-sessions-established": 3 - } -} -``` - -Each request must contain at least the `command` element which carries -the actual command which is invoked with optional arguments. - -`$ cat command.json | jq .` - -```json -{ - "command": "session-info", - "arguments": { - "session-id": 1 - } -} -``` - -`$ cat command.json | sudo nc -U test.socket | jq .` - -```json -{ - "status": "ok", - "code": 200, - "session-info": { - "type": "pppoe", - "session-id": 1, - "session-state": "Established", - "interface": "eth1", - "outer-vlan": 1000, - "inner-vlan": 1, - "mac": "02:00:00:00:00:01", - "username": "user1@rtbrick.com", - "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:1", - "agent-remote-id": "DEU.RTBRICK.1", - "lcp-state": "Opened", - "ipcp-state": "Opened", - "ip6cp-state": "Opened", - "ipv4-address": "10.100.128.0", - "ipv4-dns1": "10.0.0.3", - "ipv4-dns2": "10.0.0.4", - "ipv6-prefix": "fc66:1000:1::/64", - "ipv6-delegated-prefix": "fc66:2000::/56", - "ipv6-dns1": "fc66::3", - "ipv6-dns2": "fc66::4", - "dhcpv6-state": "Bound", - "dhcpv6-dns1": "fc66::3", - "dhcpv6-dns2": "fc66::4", - "tx-packets": 30, - "rx-packets": 26, - "rx-fragmented-packets": 0, - "session-traffic": { - "total-flows": 6, - "verified-flows": 6, - "first-seq-rx-access-ipv4": 2, - "first-seq-rx-access-ipv6": 2, - "first-seq-rx-access-ipv6pd": 1, - "first-seq-rx-network-ipv4": 2, - "first-seq-rx-network-ipv6": 2, - "first-seq-rx-network-ipv6pd": 1, - "access-tx-session-packets": 5, - "access-rx-session-packets": 4, - "access-rx-session-packets-loss": 0, - "network-tx-session-packets": 5, - "network-rx-session-packets": 4, - "network-rx-session-packets-loss": 0, - "access-tx-session-packets-ipv6": 5, - "access-rx-session-packets-ipv6": 4, - "access-rx-session-packets-ipv6-loss": 0, - "network-tx-session-packets-ipv6": 5, - "network-rx-session-packets-ipv6": 4, - "network-rx-session-packets-ipv6-loss": 0, - "access-tx-session-packets-ipv6pd": 4, - "access-rx-session-packets-ipv6pd": 4, - "access-rx-session-packets-ipv6pd-loss": 0, - "network-tx-session-packets-ipv6pd": 4, - "network-rx-session-packets-ipv6pd": 4, - "network-rx-session-packets-ipv6pd-loss": 0 - } - } -} -``` - -The response contains at least the status element with the value `ok` and status code `2xx` -if request was successfully. The status can be also set to `warning` or -`error` with corresponding error code and an optional error message. - -`$ cat command.json | sudo nc -U test.socket | jq .` - -```json -{ - "status": "warning", - "code": 404, - "message": "session not found" -} -``` - -## BNG Blaster CLI - -The python script `bngblaster-cli` provides a simple CLI tool -for interactive communication with the BNG Blaster. - -```cli -$ sudo bngblaster-cli -BNG Blaster Control Socket Client - -bngblaster-cli [arguments] - -Examples: - bngblaster-cli run.sock session-info session-id 1 - bngblaster-cli run.sock igmp-join session-id 1 group 239.0.0.1 source1 1.1.1.1 source2 2.2.2.2 source3 3.3.3.3 - bngblaster-cli run.sock igmp-info session-id 1 - bngblaster-cli run.sock l2tp-csurq tunnel-id 1 sessions [1,2] -``` - -`$ sudo bngblaster-cli run.sock session-counters | jq .` - -```json -{ - "status": "ok", - "code": 200, - "session-counters": { - "sessions": 1, - "sessions-established": 1, - "sessions-flapped": 0, - "dhcpv6-sessions-established": 1 - } -} -``` - -## Control Socket Commands - -### Global Commands - -Attribute | Description ---------- | ----------- -`interfaces` | List all interfaces with index -`session-counters` | Return session counters -`terminate` | Terminate all sessions similar to sending SIGINT (ctr+c) -`session-traffic` | Display session traffic statistics -`session-traffic-start` (Alias: `session-traffic-enabled`) | Start sending session traffic for all sessions -`session-traffic-stop` (Alias: `session-traffic-disabled`) | Stop sending session traffic for all sessions -`stream-traffic-start` (Alias: `stream-traffic-enabled`) | Start sending stream traffic for all sessions -`stream-traffic-stop` (Alias: `stream-traffic-disabled`) | Stop sending stream traffic for all sessions -`stream-stats` | Display global stream traffic statistics -`stream-info` | Display stream traffic statistics identified by flow identifier (`flow-id `) -`multicast-traffic-start` | Start sending multicast traffic from network interface -`multicast-traffic-stop` | Stop sending multicast traffic from network interface -`li-flows` | List all LI flows with detailed statistics -`sessions-pending` | List all sessions not established -`cfm-cc-start` | Start EOAM CFM CC -`cfm-cc-stop` | Stop EOAM CFM CC -`cfm-cc-rdi-on` | Set EOAM CFM CC RDI -`cfm-cc-rdi-off` | Unset EOAM CFM CC RDI -`traffic-start` | Start all traffic (session and streams) -`traffic-stop` | Stop all traffic (session and streams) - -### Session Commands - -The following commands must be execute with either `session-id` or alternative with -interface index and VLAN of the session for which the command is executed. The interface -index (`ifindex`) can be requests using the `interfaces` command or skipped. The first -access interface is automatically used if the argument `ifindex` is not present in the -command. For N:1 sessions only `session-id` is supported because multiple sessions can -be assigned to a single VLAN in this mode. - -`$ cat command.json | jq .` - -```json -{ - "command": "session-info", - "arguments": { - "ifindex": 10, - "outer-vlan": 1, - "inner-vlan": 1 - } -} -``` - -Attribute | Description | Mandatory Arguments | Optional Arguments ---------- | ----------- | ------------------- | ------------------ -`session-info` | Session information | | -`terminate` | Terminate session | | -`ipcp-open` | Open IPCP | | -`ipcp-close` | Close IPCP | | -`ip6cp-open`| Open IP6CP | | -`ip6cp-close` | Close IP6CP | | -`session-traffic-start` (Alias: `session-traffic-enabled`) | Enable session traffic | | -`session-traffic-stop` (Alias: `session-traffic-disabled`) | Disable session traffic | | -`session-streams` | Session traffic stream information | | -`stream-traffic-start` (Alias: `stream-traffic-enabled`) | Enable session stream traffic | | -`stream-traffic-stop` (Alias: `stream-traffic-disabled`) | Disable session stream traffic | | -`igmp-join` | Join group | `group` | `source1`, `source2`, `source3` -`igmp-leave` | Leave group | `group` | -`igmp-info` | IGMP information | | -`cfm-cc-start` | Start EOAM CFM CC -`cfm-cc-stop` | Stop EOAM CFM CC -`cfm-cc-rdi-on` | Set EOAM CFM CC RDI -`cfm-cc-rdi-off` | Unset EOAM CFM CC RDI - -The `session-id` is the same as used for `{session-global}` in the -configuration section. This number starts with 1 and is increased -per session added. In example if username is configured as -`user{session-global}@rtbrick.com` and logged in user is -`user10@rtbrick.com` the `session-id` of this user is `10`. - -### L2TP Commands - -Attribute | Description | Mandatory Arguments | Optional Arguments ---------- | ----------- | ------------------- | ------------------ -`l2tp-tunnels` | L2TP tunnel information | | -`l2tp-sessions` | L2TP session information | | `tunnel-id`, `session-id` -`l2tp-csurq`| Send L2TP CSURQ | `tunnel-id` | `sessions` -`l2tp-tunnel-terminate` | Terminate L2TP tunnel | `tunnel-id` | `result-code`, `error-code`, `error-message` -`l2tp-session-terminate` | Terminate L2TP session | `session-id` | `result-code`, `error-code`, `error-message`, `disconnect-code`, `disconnect-protocol`, `disconnect-direction`, `disconnect-message` - -The L2TP CSURQ command expects the local tunnel-id and a list of remote -session-id for which a connect speed update is requested. - -`$ cat command.json | jq .` - -```json -{ - "command": "l2tp-csurq", - "arguments": { - "tunnel-id": 1, - "sessions": [ - 1, - 2, - 3, - 4 - ] - } -} -``` - -This command can be executed as shown below using the CLI tool. - -`$ sudo bngblaster-cli run.sock l2tp-csurq tunnel-id 1 sessions [1,2,3,4]` - -The L2TP session terminate command allows to test result (RFC2661) and disconnect (RFC3145) codes. - -`$ sudo bngblaster-cli run.sock l2tp-session-terminate session-id 1 result-code 2 error-message "LCP request" disconnect-code 3 disconnect-message "LCP terminate request"` - -### ISIS Commands - -Attribute | Description | Mandatory Arguments | Optional Arguments ---------- | ----------- | ------------------- | ------------------ -`isis-adjacencies` | Display all ISIS adjacencies | | -`isis-database` | ISIS database information | `instance`, `level` | -`isis-load-mrt` | Load ISIS MRT file | `instance`, `file` | -`isis-lsp-update` | Update ISIS LSP | `instance`, `pdu` | -`isis-teardown` | Teardown all ISIS adjacencies | | - -### BGP Commands - -Attribute | Description | Mandatory Arguments | Optional Arguments ---------- | ----------- | ------------------- | ------------------ -`bgp-sessions` | Display all matching BGP sessions | | `local-ipv4-address`, `peer-ipv4-address` -`bgp-disconnect` | Disconnect all matching BGP sessions | | `local-ipv4-address`, `peer-ipv4-address` -`bgp-teardown` | Teardown all BGP sessions | | -`bgp-raw-update-list` | List all loaded BGP RAW update files in memory | | -`bgp-raw-update` | Update all matching BGP session | `file` | `local-ipv4-address`, `peer-ipv4-address` diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 6c804672..00000000 --- a/docs/index.md +++ /dev/null @@ -1,42 +0,0 @@ -# Documentation - -- [Introduction](intro) -- [Installation](install) -- [Configuration](config) -- [Reports](reports) -- [Control Socket](ctrl) -- [PPPoE](pppoe) -- [L2TPv2](l2tp) -- [IPoE](ipoe) -- [Traffic](traffic) -- [Traffic Streams](streams) -- [Multicast](multicast) -- [Legal Interception](li) -- [A10NSP](a10nsp) -- [ISIS](isis) -- [BGP](bgp) - -The BNG Blaster is an open source network test tool which is able to simulate more -than hundred thousand PPPoE and IPoE subscribers including IPTV, L2TPv2, QoS, forwarding -verification and convergence testing capabilities. The BNG Blaster is also contently -enhanced for more common (non-BNG) network testing. - -A short [introduction](https://youtu.be/EHJ70p0_Sw0 "BNG Blaster") and good presentation -from [DENOG13](https://youtu.be/LVg6rlVEfNU "DENOG13") can be found on YouTube. - -![BBL Interactive](images/bbl_interactive.png "BNG Blaster (Interactive Mode)") - -## License - -BNG Blaster is licensed under the BSD 3-Clause License, which means that you are free to get and use it for -commercial and non-commercial purposes as long as you fulfill its conditions. - -See the LICENSE file for more details. - -## Copyright - -Copyright (C) 2020-2022, RtBrick, Inc. - -## Contact - -bngblaster@rtbrick.com \ No newline at end of file diff --git a/docs/install.md b/docs/install.md deleted file mode 100644 index da8141b7..00000000 --- a/docs/install.md +++ /dev/null @@ -1,149 +0,0 @@ -# Installation - -The BNG Blaster should run on any modern linux distribution -but is primary tested on Ubuntu 18.04 LTS and Ubuntu 20.04 LTS. - -## Install Ubuntu - -Install dependencies: - -```cli -sudo apt install -y libssl1.1 libncurses5 libjansson4 -``` - -Download and install debian package: -[https://github.com/rtbrick/bngblaster/releases](https://github.com/rtbrick/bngblaster/releases) - -```cli -sudo dpkg -i -``` - -This command installs the BNG Blaster to `/usr/sbin/bngblaster`. - -## Build from Sources - -### Dependencies - -The BNG Blaster has dependencies to the RtBrick -[libdict fork](https://github.com/rtbrick/libdict) -and the following standard dependencies: - -```cli -# libdict -wget https://github.com/rtbrick/libdict/releases/download/v1.0.1/libdict-debian.zip -sudo dpkg -i libdict_1.0.1_amd64.deb -sudo dpkg -i libdict-dev_1.0.1_amd64.deb - -# standard dependencies -sudo apt install -y cmake \ - libcunit1-dev \ - libncurses5-dev \ - libssl-dev \ - libjansson-dev -``` - -### Build - -Per default cmake (`cmake .`) will build the BNG Blaster as release -version with optimization and without debug symbols. - -```cli -mkdir build -cd build -cmake -DCMAKE_BUILD_TYPE=Release .. -make all -``` - -Alternative it is also possible to build a debug -version for detailed troubleshooting using gdb. - -```cli -mkdir build -cd build -cmake -DCMAKE_BUILD_TYPE=Debug .. -make all -``` - -There are also CPack files generated which allows to easily generate a debian -package by just executing `cpack` from build directory. - -It is also recommended to provide the GIT commit details to be included in the -manually build version as shown below: - -```cli -cmake -DGIT_REF=`git rev-parse --abbrev-ref HEAD` -DGIT_SHA=`git rev-parse HEAD` . -``` - -*Example:* - -```cli -$ bngblaster -v -GIT: - REF: dev - SHA: df453a5ee9dbf6440aefbfb9630fa0f06e326d44 -IO Modes: packet_mmap_raw (default), packet_mmap, raw -``` - -### Install - -Then BNG Blaster can be installed using make install target. - -```cli -sudo make install -``` - -This command installs the BNG Blaster to `/usr/sbin/bngblaster`. - -### Build and Run Unit Tests - -Building and running unit tests requires CMocka to be installed: - -```cli -sudo apt install libcmocka-dev -``` - -The option `BNGBLASTER_TESTS` enables to build unit tests. - -```cli -cmake -DCMAKE_BUILD_TYPE=Debug -DBNGBLASTER_TESTS=ON . -make all -make test -``` - -*Example:* - -```cli -$ make test -Running tests... -Test project - Start 1: TestProtocols -1/1 Test #1: TestProtocols .................... Passed 0.00 sec - -100% tests passed, 0 tests failed out of 1 - -Total Test time (real) = 0.00 sec -``` - -### Running BNG Blaster - -The BNG Blaster needs permissions to send raw packets and change network interface -settings. The easiest way to run the BNG Blaster is either as the root user or with -sudo: - -```cli -# As root -bngblaster -C config.json -I - -# As a normal user: -sudo bngblaster -C config.json -I -``` - -A third option is to set capabilities on the binary with in example `setcap` -as shown below: - -```cli -sudo setcap cap_net_raw,cap_net_admin,cap_dac_read_search+eip `which bngblaster` - -# As normal user: -bngblaster -C config.json -I -``` diff --git a/docs/intro.md b/docs/intro.md deleted file mode 100644 index b540a3ef..00000000 --- a/docs/intro.md +++ /dev/null @@ -1,115 +0,0 @@ -# Introduction - -Building a BNG from scratch requires a lot of testing but commercial BNG test software -is often very expensive, resource intensive and provide a lot of administrative overhead -to maintain such. - -Therefore we decided to build an open source network test software initially focused on BNG -and IPTV testing but constantly enhanced and planned for more common (non-BNG) network testing. -The BNG Blaster was completely build from scratch, targeted for max scaling with small -resource footprint, simple to use and easy to integrate in any test automation infrastructure. - -The BNG Blaster is able to simulate more than hundred thousand PPPoE and IPoE (DHCP) subscribers including -IPTV, L2TPv2 (LNS emulation), L2BSA, QoS, forwarding verification and convergence testing capabilities. - -* *High Scaling:* > 100K sessions, > 1M PPS, and > 1M traffic flows -* *Low CPU and Memory Footprint:* ~300MB memory for 16K sessions -* *Portable:* runs on every modern linux, virtual machines and containers -* *User Space:* all protocols implemented in user-space from scratch and optimized for performance -* *IPTV:* IGMP version 1, 2 and 3 with automated channel zapping test -* *QoS:* define and analyze traffic streams -* *Automation:* the BNG Blaster Controller provides an automation friendly REST API and robot keywords - -**Info:** _The BNG Blaster Controller is not yet published but you can send -a mail to bngblaster@rtbrick.com if you are interested to get early access!_ - -```cli -$ bngblaster --help - - - ____ __ ____ _ __ ,/ - / __ \ / /_ / __ ) _____ (_)_____ / /__ ,'/ - / /_/ // __// __ |/ ___// // ___// //_/ ,' / - / _, _// /_ / /_/ // / / // /__ / ,< ,' /_____, - /_/ |_| \__//_____//_/ /_/ \___//_/|_| .'____ ,' - ____ _ _ ______ ____ _ _ / ,' - / __ ) / | / // ____/ / __ ) / /____ _ _____ / /_ ___ ____ / ,' - / __ |/ |/ // / __ / __ |/ // __ `// ___// __// _ \ / ___/ /,' - / /_/ // /| // /_/ / / /_/ // // /_/ /(__ )/ /_ / __// / / - /_____//_/ |_/ \____/ /_____//_/ \__,_//____/ \__/ \___//_/ - -Usage: bngblaster [OPTIONS] - - -v --version - -h --help - -C --config - -T --stream-config - -l --logging debug|error|igmp|io|pppoe|info|pcap|timer|timer-detail|ip|loss|l2tp|dhcp - -L --log-file - -u --username - -p --password - -P --pcap-capture - -j --json-report-content sessions|streams - -J --json-report-file - -c --session-count - -g --mc-group - -s --mc-source - -r --mc-group-count - -z --mc-zapping-interval - -S --control-socket - -I --interactive - -b --hide-banner - -f --force - -``` - -The BNG Blaster includes an optional interactive mode (`-I`) with realtime stats and -log viewer as shown below. - -![BNG Blaster Interactive](images/bbl_interactive.png) - -## Theory Of Operation - -The BNG Blaster has been completely built from scratch, including user-space implementations of the entire protocol -stack you need for interfacing with a BNG. It’s core is based on a very simple event loop which serves timers and signals. -The timers have been built using a lightweight constant time (`O(1)`) library which we built purposely to start, restart -and delete the protocol session FSM timers quickly and at scale. - -The BNG Blaster expects a Linux kernel network interface which is up, but not configured with any IP addresses or VLAN as it -expects to receive and transmit RAW ethernet packets. - -The BNG Blaster does I/O using high-speed polling timers with a mix of Linux -[RAW Packet Sockets](https://man7.org/linux/man-pages/man7/packet.7.html) and -[Packet MMAP](https://www.kernel.org/doc/html/latest/networking/packet_mmap.html). - -The second one is a so-called PACKET_RX_RING/PACKET_TX_RING abstraction where a user-space program gets a fast-lane into reading -and writing to kernel interfaces using a shared ring buffer. The shared ring buffer is a memory mapped "window" that is shared -between kernel and user-space. This low overhead abstraction allows to transmit and receive traffic without doing expensive system calls. -Sending and transmitting traffic via Packet MMAP is as easy as just by copying a packet into a buffer and setting a flag. - -![BNG Blaster Architecture](images/bbl_arch.png) - -The BNG Blaster supports multiple configurable I/O modes listed with `bngblaster -v` but except `packet_mmap_raw` all other modes -are currently considered as experimental. In the default mode (`packet_mmap_raw`) all packets are received in a Packet MMAP ring -buffer and send directly trough RAW packet sockets. This combination was the most efficient in our benchmark tests. - -BNG Blasters primary design goal is to simulate thousands of subscriber CPE's with a small hardware resource footprint. Simple -to use and easy to integrate in our robot test automation infrastructure. This allows to simulate more than hundred thousand -PPPoE or IPoE (DHCP) subscribers including IPTV, traffic verification and convergence testing from a single medium scale -virtual machine or to run the blaster directly from a laptop. - -The BNG Blaster provides three types of interfaces. The first interface is called the access interface which emulates the PPPoE -sessions. The second interface-type is called network interface. This is used for emulating the core-facing side of the -internet. The last type is called a10nsp interface which emulates an layer two provider interface. The term A10 -refers to the end-to-end ADSL network reference model from TR-025. - -![BNG Blaster Interfaces](images/bbl_interfaces.png) - -This allows to verify IP reachability by sending bidirectional traffic between all PPPoE sessions on access-interface and the -network interface. The network interface is also used to inject downstream multicast test traffic for IPTV tests. It is also -possible to send RAW traffic streams between multiple network interfaces without any access interface defined for non-BNG -testing. - -One popular example for non-BNG tests with the BNG Blaster is the verification of a BGP full-table by injecting around 1M -prefixes and setting up traffic streams for all prefixes with at least one PPS (1M PPS). The BNG Blaster is able to verify -and analyze every single flow with detailed per flow statistics (receive rate, loss, latency, ...). diff --git a/docs/ipoe.md b/docs/ipoe.md deleted file mode 100644 index 2f291bf9..00000000 --- a/docs/ipoe.md +++ /dev/null @@ -1,151 +0,0 @@ -# IPoE - -The BNG Blaster is able to emulate IP over Ethernet (IPoE) -subscribers with static and dynamic address assignment -supporting 1:1 and N:1 VLAN mode. - -## Static Addresses - -Static addresses means that the IP address and gateway is assigned -statically as shown in the example below. - -```json -{ - "interfaces": { - "access": [ - { - "interface": "eth1", - "type": "ipoe", - "vlan-mode": "1:1", - "outer-vlan-min": 128, - "outer-vlan-max": 4000, - "address": "200.0.0.1", - "address-iter": "0.0.0.4", - "gateway": "200.0.0.2", - "gateway-iter": "0.0.0.4", - } - ] - } -} -``` - -## DHCPv4/v6 - -The most common case for IPoE is using DHCPv4/v6 as shown below. - -```json -{ - "interfaces": { - "access": [ - { - "interface": "eth1", - "type": "ipoe", - "outer-vlan": 7, - "vlan-mode": "N:1" - } - ] - }, - "dhcp": { - "enable": true, - }, - "dhcpv6": { - "enable": true - }, - "access-line": { - "agent-remote-id": "DEU.RTBRICK.{session-global}", - "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:{session-global}" - } -} -``` - -## IPoE Session Information - -The control socket command `session-info session-id ` provides -detailed information for IPoE sessions. - -`$ sudo bngblaster-cli run.sock session-info session-id 1 | jq .` - -```json -{ - "status": "ok", - "code": 200, - "session-information": { - "type": "ipoe", - "session-id": 1, - "session-state": "Established", - "interface": "eth1", - "outer-vlan": 8, - "inner-vlan": 1, - "mac": "02:00:00:00:00:01", - "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:1", - "agent-remote-id": "DEU.RTBRICK.1", - "ipv4-address": "1.1.1.3", - "ipv4-netmask": "255.255.255.255", - "ipv4-gateway": "1.1.1.1", - "ipv4-dns1": "10.0.0.3", - "ipv4-dns2": "10.0.0.4", - "ipv6-prefix": "fc66:1337:2222::3/128", - "ipv6-delegated-prefix": "fc66:1337:3333:2::/64", - "dhcp-state": "Bound", - "dhcp-server": "1.1.1.1", - "dhcp-lease-time": 300, - "dhcp-lease-expire": 299, - "dhcp-lease-expire-t1": 149, - "dhcp-lease-expire-t2": 261, - "dhcp-tx": 2, - "dhcp-rx": 2, - "dhcp-tx-discover": 1, - "dhcp-rx-offer": 1, - "dhcp-tx-request": 1, - "dhcp-rx-ack": 1, - "dhcp-rx-nak": 0, - "dhcp-tx-release": 0, - "dhcpv6-state": "Bound", - "dhcpv6-lease-time": 14400, - "dhcpv6-lease-expire": 14399, - "dhcpv6-lease-expire-t1": 899, - "dhcpv6-lease-expire-t2": 1439, - "dhcpv6-tx": 1, - "dhcpv6-rx": 1, - "dhcpv6-tx-solicit": 1, - "dhcpv6-rx-advertise": 0, - "dhcpv6-tx-request": 0, - "dhcpv6-rx-reply": 1, - "dhcpv6-tx-renew": 0, - "dhcpv6-tx-release": 0, - "dhcpv6-dns1": "fc66::3", - "dhcpv6-dns2": "fc66::4", - "tx-packets": 6, - "rx-packets": 6, - "rx-fragmented-packets": 0, - "session-traffic": { - "total-flows": 6, - "verified-flows": 0, - "first-seq-rx-access-ipv4": 0, - "first-seq-rx-access-ipv6": 0, - "first-seq-rx-access-ipv6pd": 0, - "first-seq-rx-network-ipv4": 0, - "first-seq-rx-network-ipv6": 0, - "first-seq-rx-network-ipv6pd": 0, - "access-tx-session-packets": 0, - "access-rx-session-packets": 0, - "access-rx-session-packets-loss": 0, - "network-tx-session-packets": 0, - "network-rx-session-packets": 0, - "network-rx-session-packets-loss": 0, - "access-tx-session-packets-ipv6": 0, - "access-rx-session-packets-ipv6": 0, - "access-rx-session-packets-ipv6-loss": 0, - "network-tx-session-packets-ipv6": 0, - "network-rx-session-packets-ipv6": 0, - "network-rx-session-packets-ipv6-loss": 0, - "access-tx-session-packets-ipv6pd": 0, - "access-rx-session-packets-ipv6pd": 0, - "access-rx-session-packets-ipv6pd-loss": 0, - "network-tx-session-packets-ipv6pd": 0, - "network-rx-session-packets-ipv6pd": 0, - "network-rx-session-packets-ipv6pd-loss": 0 - } - } -} -``` diff --git a/docs/isis.md b/docs/isis.md deleted file mode 100644 index e3f7ff4f..00000000 --- a/docs/isis.md +++ /dev/null @@ -1,339 +0,0 @@ -# ISIS - -Intermediate System to Intermediate System (ISIS, also written IS-IS) -is a routing protocol designed to move information efficiently within -a network. - -The ISIS protocol is defined in ISO/IEC 10589:2002 as an international -standard within the Open Systems Interconnection (OSI) reference design. -The Internet Engineering Task Force (IETF) republished ISIS in RFC 1142, -but that RFC was later marked as historic by RFC 7142 because it republished -a draft rather than a final version of the ISO standard, causing confusion. - -ISIS has been called the de facto standard for large service provider -network backbones. - -The BNG Blaster is able to emulate multiple ISIS instances. An ISIS instance -is a virtual ISIS node with one or more network interfaces attached. Such a -node behaves like a "real router" including database synchronization and -flooding. Every instance generates a `self` originated LSP describing the -node itself. - -Following an example ISIS configuration with one instance -attached to two network interfaces. - -```json -{ - "interfaces": { - "network": [ - { - "interface": "eth1", - "address": "10.0.1.2/24", - "gateway": "10.0.1.1", - "address-ipv6": "fc66:1337:7331:1::2/64", - "gateway-ipv6": "fc66:1337:7331:1::1", - "isis-instance-id": 1, - "isis-level": 1, - "isis-l1-metric": 100, - }, - { - "interface": "eth2", - "address": "10.0.2.2/24", - "gateway": "10.0.2.1", - "address-ipv6": "fc66:1337:7331:2::2/64", - "gateway-ipv6": "fc66:1337:7331:2::1", - "isis-instance-id": 1 - } - ] - }, - "isis": [ - { - "instance-id": 1, - "system-id": "0100.1001.0010", - "router-id": "10.10.10.10", - "hostname": "R1", - "area": [ - "49.0001/24", - "49.0002/24" - ], - "hello-padding": true, - "lsp-lifetime": 65535, - "level1-auth-key": "secret", - "level1-auth-type": "md5", - "sr-base": 2000, - "sr-range": 3600 - } - ] -} -``` - -All supported ISIS [configuration](config) options and [commands](ctrl) are -detailed explained corresponding sections of this documentation. - -The support for multiple instances allows different use cases. One example might -be to create two instances connected to the device or network under test. Now -inject a LSP on one instance and check if learned over the tested network on -the other instance. - -Every ISIS instance can be also connected to an emulated link state graph loaded -by MRT files as shown in the example below. - -![BBL ISIS](images/bbl_isis.png "ISIS") - -```json -{ - "isis": [ - { - "instance-id": 1, - "system-id": "0100.1001.0011", - "router-id": "10.10.10.11", - "hostname": "B1", - "external": { - "mrt-file": "test.mrt", - "connections": [ - { - "system-id": "0000.0000.0001", - "l1-metric": 1000, - "l2-metric": 2000 - } - ] - } - }, - { - "instance-id": 1, - "system-id": "0100.1001.0011", - "router-id": "10.10.10.12", - "hostname": "B2" - } - ] -} -``` - -The node `N1` in this example also needs to advertise the -reachability to the node `B1`. - -## Adjacencies - -The BNG Blaster supports P2P adjacencies with 3-way-handshake only. - -`$ sudo bngblaster-cli run.sock isis-adjacencies` -```json -{ - "status": "ok", - "code": 200, - "isis-adjacencies": [ - { - "interface": "eth1", - "type": "P2P", - "level": "L1", - "instance-id": 2, - "adjacency-state": "Up", - "peer": { - "system-id": "0100.1001.0022" - } - }, - { - "interface": "eth2", - "type": "P2P", - "level": "L1", - "instance-id": 1, - "adjacency-state": "Up", - "peer": { - "system-id": "0100.1001.0021" - } - } - ] -} -``` - -## Database - -The BNG Blaster distinguishes between three different source types of -LSP entries in the ISIS database. - -The type `self` is used for the self originated LSP describing the own -BNG Blaster ISIS instance. LSP entries of type `adjacency` are learned -via ISIS adjacencies. The type `external` is used for those LSP entries -learned via MRT files or injected via `isis-lsp-update` command. - -`$ sudo bngblaster-cli run.sock isis-database instance 1 level 1` -```json -{ - "status": "ok", - "code": 200, - "isis-database": [ - { - "id": "0000.0000.0001.00-00", - "seq": 1, - "lifetime": 65535, - "lifetime-remaining": 65529, - "source-type": "external" - }, - { - "id": "0100.1001.0011.00-00", - "seq": 2, - "lifetime": 65535, - "lifetime-remaining": 65507, - "source-type": "self" - }, - { - "id": "0100.1001.0021.00-00", - "seq": 2, - "lifetime": 65524, - "lifetime-remaining": 65506, - "source-type": "adjacency", - "source-system-id": "0100.1001.0021" - }, - { - "id": "0100.1001.0022.00-00", - "seq": 2, - "lifetime": 65524, - "lifetime-remaining": 65506, - "source-type": "adjacency", - "source-system-id": "0100.1001.0021" - } - ] -} -``` - -The BNG Blaster automatically purges all LSP's of type -`self` and `external` during teardown. This is done by -generating LSP's with a newer sequence numbers and lifetime -of 30 seconds only. This lifetime is enough to flood the purge -LSP over te whole network under test. - -## Flooding - -The BNG Blaster floods LSP's received to all other active -adjacencies of the ISIS instance except to those with peer -system-id equal to the source system-id of the LSP. - -## Limitations - -Currently only ISIS P2P links are supported. There is also -no support for route leaking between levels. - -## MRT Files - -The BNG Blaster is able to load LSP's from a MRT file as defined in -[RFC6396](https://datatracker.ietf.org/doc/html/rfc6396). - -```text - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Timestamp | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Subtype | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message... (variable) - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -``` - -The message field contains the complete ISIS LSP PDU including -the ISIS common header starting with `0x83`. - -Those files can be loaded at startup via configuration option -`"isis": { "external": { "mrt-file": "" } }` or alternative -via `isis-load-mrt` command. - -`$ sudo bngblaster-cli run.sock isis-load-mrt file test.mrt instance 1` - -## LSP Update Command - -It is also possible to inject external LSP's using the `isis-lsp-update` -command. - -The command expects a list of hex encoded PDU's including -the ISIS common header starting with `0x83`, - -`$ cat command.json | jq .` -```json -{ - "command": "isis-lsp-update", - "arguments": { - "instance": 1, - "pdu": [ - "831b0100120100000021ffff010203040506000000000003c0d103010403490001", - "831b0100120100000021ffff010203040506000100000003bad603010403490001" - ] - } -} -``` - -## LSPGEN - -The BNG Blaster includes a tool called `lspgen` which is able to generate -link state packets and topologies for export as MRT and PCAP files or directly -injected via BNG Blaster LSP update command. This tool is detailed explained -in the chapter [LSPGEN](lspgen) of this documentation. - -## LSP Update via Scapy - -The following example shows how to generate LSP's via Scapy -and inject them using the `isis-lsp-update` command. - -```python -import sys -import socket -import os -import json - -from scapy.contrib.isis import * - -def error(*args, **kwargs): - """print error and exit""" - print(*args, file=sys.stderr, **kwargs) - sys.exit(1) - - -def execute_command(socket_path, request): - if os.path.exists(socket_path): - client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - try: - client.connect(socket_path) - client.send(json.dumps(request).encode('utf-8')) - data = "" - while True: - junk = client.recv(1024) - if junk: - data += junk.decode('utf-8') - else: - break - print(json.dumps(json.loads(data), indent=4)) - except Exception as e: - error(e) - finally: - client.close() - else: - error("socket %s not found" % socket_path) - - -def main(): - """main function""" - socket_path = sys.argv[1] - - command = { - "command": "isis-lsp-update", - "arguments": { - "instance": 1, - "pdu": [] - } - } - - tlvs = ISIS_AreaTlv(areas=ISIS_AreaEntry(areaid='49.0001')) - pdu = ISIS_CommonHdr()/ISIS_L1_LSP(lifetime=65535, lspid='0102.0304.0506.00-00', seqnum=3, tlvs=tlvs) - command["arguments"]["pdu"].append(pdu.build().hex()) - - pdu = ISIS_CommonHdr()/ISIS_L1_LSP(lifetime=65535, lspid='0102.0304.0506.00-01', seqnum=3, tlvs=tlvs) - command["arguments"]["pdu"].append(pdu.build().hex()) - - execute_command(socket_path, command) - - -if __name__ == "__main__": - main() - -``` \ No newline at end of file diff --git a/docs/l2tp.md b/docs/l2tp.md deleted file mode 100644 index efddf250..00000000 --- a/docs/l2tp.md +++ /dev/null @@ -1,387 +0,0 @@ -# L2TPv2 - -The BNG Blaster is able to emulate L2TPv2 (RFC2661) LNS servers to -be able to test the L2TPv2 LAC functionality of the BNG device under -test. - -Following an example with 30 L2TP LNS servers. - -```json -{ - "interfaces": { - "network": { - "interface": "eth2", - "address": "10.0.0.1", - "gateway": "10.0.0.2", - "address-ipv6": "fc66:1337:7331:8::10", - "gateway-ipv6": "fc66:1337:7331:8::1" - }, - "access": [ - { - "interface": "eth1", - "outer-vlan-min": 1, - "outer-vlan-max": 4000, - "inner-vlan-min": 7, - "inner-vlan-max": 7, - "authentication-protocol": "PAP" - }, - { - "interface": "eth1", - "outer-vlan-min": 1, - "outer-vlan-max": 4000, - "inner-vlan-min": 8, - "inner-vlan-max": 8, - "authentication-protocol": "CHAP" - } - ] - }, - "pppoe": { - "reconnect": true, - "discovery-timeout": 3, - "discovery-retry": 10 - }, - "ppp": { - "mru": 1492, - "authentication": { - "username": "blaster@l2tp.de", - "password": "test", - "timeout": 1, - "retry": 60 - }, - "lcp": { - "conf-request-timeout": 5, - "conf-request-retry": 30, - "keepalive-interval": 30, - "keepalive-retry": 3 - }, - "ipcp": { - "enable": true - }, - "ip6cp": { - "enable": true - } - }, - "access-line": { - "agent-remote-id": "DEU.RTBRICK.{session}", - "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:{session}", - "rate-up": 1024, - "rate-down": 16384 - }, - "l2tp-server": [ - { - "name": "LNS1", - "address": "10.0.0.11", - "secret": "test1", - "receive-window-size": 8 - }, - { - "name": "LNS2", - "address": "10.0.0.12", - "secret": "test2", - "receive-window-size": 8 - }, - { - "name": "LNS3", - "address": "10.0.0.13", - "secret": "test3", - "receive-window-size": 8 - }, - { - "name": "LNS4", - "address": "10.0.0.14", - "secret": "test4", - "receive-window-size": 8 - }, - { - "name": "LNS5", - "address": "10.0.0.15", - "secret": "test5", - "receive-window-size": 8 - }, - { - "name": "LNS6", - "address": "10.0.0.16", - "secret": "test6", - "receive-window-size": 8 - }, - { - "name": "LNS7", - "address": "10.0.0.17", - "secret": "test7", - "receive-window-size": 8 - }, - { - "name": "LNS8", - "address": "10.0.0.18", - "secret": "test8", - "receive-window-size": 8 - }, - { - "name": "LNS9", - "address": "10.0.0.19", - "secret": "test9", - "receive-window-size": 8 - }, - { - "name": "LNS10", - "address": "10.0.0.20", - "secret": "test10", - "receive-window-size": 8 - }, - { - "name": "LNS11", - "address": "10.0.0.21", - "secret": "test11", - "receive-window-size": 8 - }, - { - "name": "LNS12", - "address": "10.0.0.22", - "secret": "test12", - "receive-window-size": 8 - }, - { - "name": "LNS13", - "address": "10.0.0.23", - "secret": "test13", - "receive-window-size": 8 - }, - { - "name": "LNS14", - "address": "10.0.0.24", - "secret": "test14", - "receive-window-size": 8 - }, - { - "name": "LNS15", - "address": "10.0.0.25", - "secret": "test15", - "receive-window-size": 8 - }, - { - "name": "LNS16", - "address": "10.0.0.26", - "secret": "test16", - "receive-window-size": 8 - }, - { - "name": "LNS17", - "address": "10.0.0.27", - "secret": "test17", - "receive-window-size": 8 - }, - { - "name": "LNS18", - "address": "10.0.0.28", - "secret": "test18", - "receive-window-size": 8 - }, - { - "name": "LNS19", - "address": "10.0.0.29", - "secret": "test19", - "receive-window-size": 8 - }, - { - "name": "LNS20", - "address": "10.0.0.30", - "secret": "test20", - "receive-window-size": 8 - }, - { - "name": "LNS21", - "address": "10.0.0.31", - "secret": "test21", - "receive-window-size": 8 - }, - { - "name": "LNS22", - "address": "10.0.0.32", - "secret": "test22", - "receive-window-size": 8 - }, - { - "name": "LNS23", - "address": "10.0.0.33", - "secret": "test23", - "receive-window-size": 8 - }, - { - "name": "LNS24", - "address": "10.0.0.34", - "secret": "test24", - "receive-window-size": 8 - }, - { - "name": "LNS25", - "address": "10.0.0.35", - "secret": "test25", - "receive-window-size": 8 - }, - { - "name": "LNS26", - "address": "10.0.0.36", - "secret": "test26", - "receive-window-size": 8 - }, - { - "name": "LNS27", - "address": "10.0.0.37", - "secret": "test27", - "receive-window-size": 8 - }, - { - "name": "LNS28", - "address": "10.0.0.38", - "secret": "test28", - "receive-window-size": 8 - }, - { - "name": "LNS29", - "address": "10.0.0.39", - "secret": "test29", - "receive-window-size": 8 - }, - { - "name": "LNS30", - "address": "10.0.0.40", - "secret": "test30", - "receive-window-size": 8 - } - ], - "session-traffic": { - "autostart": true, - "ipv4-pps": 1 - } -} -``` - -## Receive Tunnel Information - -`$ sudo bngblaster-cli run.sock l2tp-tunnels` - -```json -{ - "status": "ok", - "code": 200, - "l2tp-tunnels": [ - { - "state": "Established", - "server-name": "LNS1", - "server-address": "10.0.0.11", - "tunnel-id": 1, - "peer-tunnel-id": 50011, - "peer-name": "BNG", - "peer-address": "10.0.0.2", - "peer-vendor": "RtBrick, Inc.", - "secret": "test1", - "control-packets-rx": 102, - "control-packets-rx-dup": 0, - "control-packets-rx-out-of-order": 0, - "control-packets-tx": 102, - "control-packets-tx-retry": 0, - "data-packets-rx": 1406, - "data-packets-tx": 206 - } - ] -} -``` - -## Receive Session Information - -The `l2tp-sessions` command returns all L2TP sessions. - -`$ sudo bngblaster-cli run.sock l2tp-sessions` - -```json -{ - "status": "ok", - "code": 200, - "l2tp-sessions": [ - { - "state": "Established", - "tunnel-id": 1, - "session-id": 1, - "peer-tunnel-id": 50011, - "peer-session-id": 32867, - "peer-proxy-auth-name": "blaster@l2tp.de", - "peer-called-number": "N/A", - "peer-calling-number": "N/A", - "peer-sub-address": "N/A", - "peer-tx-bps": 48000, - "peer-rx-bps": 1000, - "peer-ari": "DEU.RTBRICK.1", - "peer-aci": "0.0.0.0/0.0.0.0 eth 0:1", - "data-packets-rx": 79, - "data-packets-tx": 79, - "data-ipv4-packets-rx": 15, - "data-ipv4-packets-tx": 15 - } - ] -} -``` - -This output can be also filtered to return only sessions -of a given tunnel. - -`sudo bngblaster-cli run.sock l2tp-sessions tunnel-id 1` - -It is also possible to display a single session. - -`$ sudo bngblaster-cli run.sock l2tp-sessions tunnel-id 1 session-id 1` - -## RFC5515 - -The Agent-Circuit-Id and Agent-Remote-Id AVP defined in RFC5515 -is supported and stored for each session if received. Received -CSUN messages are processed correctly and via control socket it -is possible to send also CSURQ requests to the LAC. - -## Variable Data Header - -The L2TP protocol allows different data header options resulting in -variable header lengths. The most common options can be tested with just -four servers as shown in the example below. - -```json -{ - "l2tp-server": [ - { - "name": "LNS1", - "address": "10.0.0.11", - "secret": "test1", - "receive-window-size": 8, - "congestion-mode": "default", - "data-control-priority": true - }, - { - "name": "LNS2", - "address": "10.0.0.12", - "secret": "test2", - "receive-window-size": 8, - "congestion-mode": "default", - "data-control-priority": true, - "data-length": true - }, - { - "name": "LNS3", - "address": "10.0.0.11", - "secret": "test3", - "receive-window-size": 8, - "congestion-mode": "default", - "data-control-priority": true, - "data-offset": true - }, - { - "name": "LNS4", - "address": "10.0.0.12", - "secret": "test4", - "receive-window-size": 8, - "congestion-mode": "default", - "data-control-priority": true, - "data-length": true, - "data-offset": true - } - ] -} -``` diff --git a/docs/li.md b/docs/li.md deleted file mode 100644 index 5c1ab058..00000000 --- a/docs/li.md +++ /dev/null @@ -1,92 +0,0 @@ -# Legal Interception (LI) - -The BNG Blaster can be used to emulate a mediation device providing detailed statistics -about the received flows. Today only the BCM QMX LI header format is supported but further -headers can be easily integrated. - -*BCM QMX LI Header Format* - -```text - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| D | PT | SPT | LIID | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -``` - -The functionality is automatically enabled on the network interface -and works combined with sessions in one instance or as standalone -mediation device as shown in the following example. - -```json -{ - "interfaces": { - "tx-interval": 10, - "rx-interval": 1, - "network": { - "interface": "eth2", - "address": "100.0.0.10", - "gateway": "100.0.0.2" - } - } -} -``` - -The received flows can be queried using the control socket. - -`$ sudo bngblaster-cli run.sock li-flows` - -```json -{ - "status": "ok", - "code": 200, - "li-flows": [ - { - "source-address": "1.1.1.1", - "source-port": 49152, - "destination-address": "1.1.1.2", - "destination-port": 49152, - "direction": "downstream", - "packet-type": "ethernet", - "sub-packet-type": "double-tagged", - "liid": 4194301, - "bytes-rx": 94, - "packets-rx": 1, - "packets-rx-ipv4": 0, - "packets-rx-ipv4-tcp": 0, - "packets-rx-ipv4-udp": 0, - "packets-rx-ipv4-host-internal": 0, - "packets-rx-ipv6": 0, - "packets-rx-ipv6-tcp": 0, - "packets-rx-ipv6-udp": 0, - "packets-rx-ipv6-host-internal": 0, - "packets-rx-ipv6-no-next-header": 0 - }, - { - "source-address": "1.1.1.1", - "source-port": 49152, - "destination-address": "1.1.1.2", - "destination-port": 49152, - "direction": "upstream", - "packet-type": "ethernet", - "sub-packet-type": "double-tagged", - "liid": 4194301, - "bytes-rx": 160720, - "packets-rx": 820, - "packets-rx-ipv4": 820, - "packets-rx-ipv4-tcp": 0, - "packets-rx-ipv4-udp": 0, - "packets-rx-ipv4-host-internal": 820, - "packets-rx-ipv6": 0, - "packets-rx-ipv6-tcp": 0, - "packets-rx-ipv6-udp": 0, - "packets-rx-ipv6-host-internal": 0, - "packets-rx-ipv6-no-next-header": 0 - } - ] -} -``` - -The `packets-rx-ipv4-host-internal` refers to the IPv4 protocol number 61 (any host internal protocol) -which is used by some network testers as default type for traffic streams. -The same is valid for `packets-rx-ipv6-host-internal` which refers to next header 61 and -`packets-rx-ipv6-no-next-header` with next header 59. diff --git a/docs/lspgen.md b/docs/lspgen.md deleted file mode 100644 index 0bd55af8..00000000 --- a/docs/lspgen.md +++ /dev/null @@ -1 +0,0 @@ -# LSPGEN \ No newline at end of file diff --git a/docs/multicast.md b/docs/multicast.md deleted file mode 100644 index 1a930c64..00000000 --- a/docs/multicast.md +++ /dev/null @@ -1,203 +0,0 @@ -# Multicast - -The BNG Blaster provides advanced functionalities for testing multicast -over PPPoE sessions with focus on IPTV. Therefore IGMP version 1, 2 and 3 -is implemented with support for up to 8 group records per session and 3 -sources per group. - -Multicast testing is supported using external multicast traffic like real -world IPTV traffic or by generating multicast traffic on the network interface. - -## Generate Multicast Traffic - -The BNG Blaster is recognizing loss using the BNG Blaster header sequence numbers. -After first multicast traffic is received for a particular group, for every further -packet it checks if there is a gap between last and new sequence number which is than -reported as loss. The loss logging option (-l loss) allows also to search for the missing -packets in the corresponding capture files (see test.log). - -It is also possible to start a dedicated BNG Blaster instance to generate multicast -traffic which can be consumed by multiple BNG Blaster instances. The BNG Blaster -header allows to do the same measurements on traffic generated from same or different -BNG Blaster instance. - -The following example shows generates traffic for 100 multicast groups -with one packet per millisecond for every group as required to measure the join and leave -delay in milliseconds. - -```json -{ - "interfaces": { - "tx-interval": 1.0, - "rx-interval": 1.0, - "network": { - "interface": "eth2", - "address": "100.0.0.10", - "gateway": "100.0.0.2" - } - }, - "igmp": { - "group": "239.0.0.1", - "group-iter": "0.0.0.1", - "group-count": 100, - "source": "100.0.0.10", - "send-multicast-traffic": true - } -} -``` - -The `tx-interval` and `rx-interval` should be set to at to at least `1.0` (1ms) for more -precise IGMP join/leave delay measurements. - -It is also possible to generate multicast traffic using RAW streams as shown in the -example below: - -```json -{ - "streams": [ - { - "name": "MC1", - "type": "ipv4", - "direction": "downstream", - "priority": 128, - "network-ipv4-address": "1.1.1.1", - "destination-ipv4-address": "239.0.0.1", - "length": 256, - "pps": 1, - "network-interface": "eth1" - }, - { - "name": "MC2", - "type": "ipv4", - "direction": "downstream", - "priority": 128, - "network-ipv4-address": "2.2.2.2", - "destination-ipv4-address": "239.0.0.2", - "length": 256, - "pps": 1, - "network-interface": "eth2" - } - ] -} -``` - -Using RAW streams allows to generate streams distributed over multiple network interfaces. -Setting the `destination-ipv4-address` to an multicast IPv4 address is enough to generate -proper multicast streams. All headers including the BNG Blaster header will be automatically -set for multicast. Therefore such streams can be also used to measure the IGMP join and leave -delay. - -## Manual Join/Leave Testing - -It is possible to join and leave multicast groups manually using the <> as -shown in the example below. - -`$ sudo bngblaster-cli run.sock igmp-join session-id 1 group 232.1.1.1 source1 202.11.23.101 source2 202.11.23.102 source3 202.11.23.103` - -```json -{ - "status": "ok" -} -``` - -`$ sudo bngblaster-cli run.sock igmp-info session-id 1` - -```json -{ - "status": "ok", - "igmp-groups": [ - { - "group": "232.1.1.1", - "igmp-sources": [ - "202.11.23.101", - "202.11.23.102", - "202.11.23.103" - ], - "packets": 1291, - "loss": 0, - "state": "active", - "join-delay-ms": 139 - } - ] -} -``` - -`$ sudo bngblaster-cli run.sock igmp-leave session-id 1 group 232.1.1.1` - -```json -{ - "status": "ok" -} -``` - -`$ sudo bngblaster-cli run.sock igmp-info session-id 1` - -```json -{ - "status": "ok", - "igmp-groups": [ - { - "group": "232.1.1.1", - "igmp-sources": [ - "202.11.23.101", - "202.11.23.102", - "202.11.23.103" - ], - "packets": 7456, - "loss": 0, - "state": "idle", - "leave-delay-ms": 114 - } - ] -} -``` - -## IPTV Zapping Test - -A key element of IPTV services is the delay in changing channels. -How long does it take to change from one channel to another, is -the right channel received and the old channel stopped without overlap -between old and new channel which may leads into traffic congestions if -both channels are send at the same time. Verify that fast channel changes -(zapping) works reliable as well. - -The BNG Blaster is able to emulate different client zapping behaviors and -measure the resulting join/leave delays and possible multicast traffic loss. - -The join delay is the time in milliseconds between sending join and receiving -first multicast packet of the requested group. The leave delay is the time between -sending leave and the last multicast packet received for this group. Multicast packets -received for the leaved group after first packet of joined group is received are counted -as overlap. - -The following <> output shows an example for the `igmp` section -for a typical zapping test. - -```json -{ - "igmp": { - "version": 3, - "start-delay": 10, - "group": "239.0.0.1", - "group-iter": "0.0.0.1", - "group-count": 20, - "source": "100.0.0.10", - "zapping-interval": 5, - "zapping-count": 5, - "zapping-view-duration": 30, - "zapping-wait": false, - "combined-leave-join": true, - "send-multicast-traffic": true - } -} -``` - -## Multicast Limitations - -The BNG Blaster IGMP implementation supports up to 3 sources per group record -and 8 group records per session. - -The IGMP protocol stops working if IPCP has closed also if session IPCP renegotiates. -The whole session needs to be disconnected to restart IGMP. - -The check for overlapping multicast traffic is supported for zapping tests only. diff --git a/docs/pppoe.md b/docs/pppoe.md deleted file mode 100644 index a4e8ba9b..00000000 --- a/docs/pppoe.md +++ /dev/null @@ -1,181 +0,0 @@ -# PPPoE - -Emulating PPP over Ethernet (PPPoE) sessions was initial -use case of the BNG Blaster supporting 1:1 and N:1 VLAN -mode. - -Following a basic PPPoE configuration example which is -detailed explained in the configuration section. - -```json -{ - "interfaces": { - "network": { - "interface": "eth2", - "address": "10.0.0.1", - "gateway": "10.0.0.2", - "address-ipv6": "fc66:1337:7331::1", - "gateway-ipv6": "fc66:1337:7331::2" - }, - "access": [ - { - "interface": "eth1", - "type": "pppoe", - "outer-vlan-min": 1000, - "outer-vlan-max": 1999, - "inner-vlan-min": 1, - "inner-vlan-max": 4049, - "authentication-protocol": "PAP" - }, - { - "interface": "eth1", - "type": "pppoe", - "outer-vlan-min": 2000, - "outer-vlan-max": 2999, - "inner-vlan-min": 1, - "inner-vlan-max": 4049, - "authentication-protocol": "CHAP" - } - ] - }, - "sessions": { - "count": 1000, - "session-time": 0, - "max-outstanding": 800, - "start-rate": 400, - "stop-rate": 400 - }, - "pppoe": { - "reconnect": true, - "discovery-timeout": 3, - "discovery-retry": 10 - }, - "ppp": { - "mru": 1492, - "authentication": { - "username": "user{session-global}@rtbrick.com", - "password": "test", - "timeout": 5, - "retry": 30 - }, - "lcp": { - "conf-request-timeout": 1, - "conf-request-retry": 10, - "keepalive-interval": 30, - "keepalive-retry": 3 - }, - "ipcp": { - "enable": true, - "request-ip": true, - "request-dns1": true, - "request-dns2": true, - "conf-request-timeout": 1, - "conf-request-retry": 10 - }, - "ip6cp": { - "enable": true, - "conf-request-timeout": 1, - "conf-request-retry": 10 - } - }, - "dhcpv6": { - "enable": true, - "rapid-commit": true - }, - "access-line": { - "agent-remote-id": "DEU.RTBRICK.{session-global}", - "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:{session-global}", - "rate-up": 1024, - "rate-down": 16384 - }, - "session-traffic": { - "ipv4-pps": 1, - "ipv6-pps": 1, - "ipv6pd-pps": 1 - } -} -``` - -## LCP Vendor Extension - -This chapter refers to RFC 2153 PPP vendor extensions. - -Per default all LCP vendor specific requests will be rejected sending a -LCP code reject message. With `ppp->lcp->ignore-vendor-specific` enabled, -those messages will be ignored as required to emulate different CPE -behaviors. - -The option `ppp->lcp->connection-status-message` allows to accept LCP vendor requests -with any OUI if kind is set to `1` by responding with vendor request of -kind `2`. The OUI from request is copied to response in this case. -The value from request is stored in the session as `connection-status-message`. - -## PPPoE Session Information - -The control socket command `session-info session-id ` provides -detailed information for PPPoE sessions. - -`$ sudo bngblaster-cli run.sock session-info session-id 1 | jq .` - -```json -{ - "status": "ok", - "code": 200, - "session-information": { - "type": "pppoe", - "session-id": 1, - "session-state": "Established", - "interface": "eth1", - "outer-vlan": 1000, - "inner-vlan": 1, - "mac": "02:00:00:00:00:01", - "username": "user1@rtbrick.com", - "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:1", - "agent-remote-id": "DEU.RTBRICK.1", - "lcp-state": "Opened", - "ipcp-state": "Opened", - "ip6cp-state": "Opened", - "ipv4-address": "10.100.128.0", - "ipv4-dns1": "10.0.0.3", - "ipv4-dns2": "10.0.0.4", - "ipv6-prefix": "fc66:1000:1::/64", - "ipv6-delegated-prefix": "fc66:2000::/56", - "ipv6-dns1": "fc66::3", - "ipv6-dns2": "fc66::4", - "dhcpv6-state": "Bound", - "dhcpv6-dns1": "fc66::3", - "dhcpv6-dns2": "fc66::4", - "tx-packets": 10036, - "rx-packets": 10083, - "rx-fragmented-packets": 0, - "session-traffic": { - "total-flows": 6, - "verified-flows": 6, - "first-seq-rx-access-ipv4": 2, - "first-seq-rx-access-ipv6": 3, - "first-seq-rx-access-ipv6pd": 3, - "first-seq-rx-network-ipv4": 2, - "first-seq-rx-network-ipv6": 3, - "first-seq-rx-network-ipv6pd": 3, - "access-tx-session-packets": 3266, - "access-rx-session-packets": 3265, - "access-rx-session-packets-loss": 0, - "network-tx-session-packets": 3266, - "network-rx-session-packets": 3265, - "network-rx-session-packets-loss": 0, - "access-tx-session-packets-ipv6": 3266, - "access-rx-session-packets-ipv6": 3264, - "access-rx-session-packets-ipv6-loss": 0, - "network-tx-session-packets-ipv6": 3266, - "network-rx-session-packets-ipv6": 3264, - "network-rx-session-packets-ipv6-loss": 0, - "access-tx-session-packets-ipv6pd": 3266, - "access-rx-session-packets-ipv6pd": 3264, - "access-rx-session-packets-ipv6pd-loss": 0, - "network-tx-session-packets-ipv6pd": 3266, - "network-rx-session-packets-ipv6pd": 3264, - "network-rx-session-packets-ipv6pd-loss": 0 - } - } -} -``` diff --git a/docs/reports.md b/docs/reports.md deleted file mode 100644 index 2fbc6722..00000000 --- a/docs/reports.md +++ /dev/null @@ -1,412 +0,0 @@ -# Reports - -The BNG Blaster is able to generate detailed result reports -at the end of of the test execution. - -## Standard Output Reports - -```text - - ____ __ ____ _ __ ,/ - / __ \ / /_ / __ ) _____ (_)_____ / /__ ,'/ - / /_/ // __// __ |/ ___// // ___// //_/ ,' / - / _, _// /_ / /_/ // / / // /__ / ,< ,' /_____, - /_/ |_| \__//_____//_/ /_/ \___//_/|_| .'____ ,' - ____ _ _ ______ ____ _ _ / ,' - / __ ) / | / // ____/ / __ ) / /____ _ _____ / /_ ___ ____ / ,' - / __ |/ |/ // / __ / __ |/ // __ `// ___// __// _ \ / ___/ /,' - / /_/ // /| // /_/ / / /_/ // // /_/ /(__ )/ /_ / __// / / - /_____//_/ |_/ \____/ /_____//_/ \__,_//____/ \__/ \___//_/ - -Report: - -Sessions PPPoE: 500 IPoE: 0 -Sessions established: 500/500 -DHCPv6 sessions established: 500 -Setup Time: 396 ms -Setup Rate: 1262.63 CPS (MIN: 1262.63 AVG: 1262.63 MAX: 1262.63) -Flapped: 0 - -Network Interface ( eth2 ): - TX: 25503 packets - RX: 24254 packets - TX Session: 8500 packets - RX Session: 8248 packets (0 loss) - TX Session IPv6: 8500 packets - RX Session IPv6: 8000 packets (0 loss) - TX Session IPv6PD: 8500 packets - RX Session IPv6PD: 8000 packets (0 loss) - TX Multicast: 0 packets - RX Drop Unknown: 1 packets - TX Encode Error: 0 - RX Decode Error: 0 packets - TX Send Failed: 0 - TX No Buffer: 0 - TX Poll Kernel: 0 - RX Poll Kernel: 3932 - -Access Interface ( eth1 ): - TX: 33250 packets - RX: 34047 packets - TX Session: 8500 packets - RX Session: 8248 packets (0 loss, 0 wrong session) - TX Session IPv6: 8500 packets - RX Session IPv6: 8000 packets (0 loss, 0 wrong session) - TX Session IPv6PD: 8500 packets - RX Session IPv6PD: 8000 packets (0 loss, 0 wrong session) - RX Multicast: 0 packets (0 loss) - RX Drop Unknown: 1 packets - TX Encode Error: 33250 packets - RX Decode Error: 0 packets - TX Send Failed: 0 - TX No Buffer: 0 - TX Poll Kernel: 0 - RX Poll Kernel: 3932 - - Access Interface Protocol Packet Stats: - ARP TX: 0 RX: 0 - PADI TX: 500 RX: 0 - PADO TX: 0 RX: 500 - PADR TX: 500 RX: 0 - PADS TX: 0 RX: 500 - PADT TX: 1 RX: 499 - LCP TX: 2249 RX: 2249 - PAP TX: 250 RX: 250 - CHAP TX: 250 RX: 500 - IPCP TX: 1500 RX: 1500 - IP6CP TX: 1500 RX: 1500 - IGMP TX: 0 RX: 1298 - ICMP TX: 0 RX: 0 - ICMPv6 TX: 500 RX: 500 - DHCPv6 TX: 500 RX: 500 - - Access Interface Protocol Timeout Stats: - LCP Echo Request: 0 - LCP Request: 0 - IPCP Request: 0 - IP6CP Request: 0 - PAP: 0 - CHAP: 0 - ICMPv6 RS: 0 - DHCPv6 Request: 0 - -Session Traffic: - Config: - IPv4 PPS: 1 - IPv6 PPS: 1 - IPv6PD PPS: 1 - Verified Traffic Flows: 3000/3000 - Access IPv4: 500 - Access IPv6: 500 - Access IPv6PD: 500 - Network IPv4: 500 - Network IPv6: 500 - Network IPv6PD: 500 - First Sequence Number Received: - Access IPv4 MIN: 1 ( 1.000s) MAX: 2 ( 2.000s) - Access IPv6 MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) - Access IPv6PD MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) - Network IPv4 MIN: 1 ( 1.000s) MAX: 2 ( 2.000s) - Network IPv6 MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) - Network IPv6PD MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) -``` - -## JSON Reports - -A detailed JSON report is generated if enabled using the optional argument `-J ` -as shown in the example below. - -```json -{ - "report": { - "sessions": 500, - "sessions-pppoe": 500, - "sessions-ipoe": 0, - "sessions-established": 500, - "sessions-flapped": 0, - "setup-time-ms": 396, - "setup-rate-cps": 1263, - "setup-rate-cps-min": 1263, - "setup-rate-cps-avg": 1263, - "setup-rate-cps-max": 1263, - "dhcpv6-sessions-established": 500, - "network-interfaces": [ - { - "name": "eth2", - "tx-packets": 25503, - "rx-packets": 24254, - "tx-session-packets": 8500, - "rx-session-packets": 8248, - "rx-session-packets-loss": 0, - "tx-session-packets-avg-pps-max": 500, - "rx-session-packets-avg-pps-max": 500, - "tx-session-packets-ipv6": 8500, - "rx-session-packets-ipv6": 8000, - "rx-session-packets-ipv6-loss": 0, - "tx-session-packets-avg-pps-max-ipv6": 500, - "rx-session-packets-avg-pps-max-ipv6": 500, - "tx-session-packets-ipv6pd": 8500, - "rx-session-packets-ipv6pd": 8000, - "rx-session-packets-ipv6pd-loss": 0, - "tx-session-packets-avg-pps-max-ipv6pd": 500, - "rx-session-packets-avg-pps-max-ipv6pd": 500, - "tx-multicast-packets": 0 - } - ], - "access-interfaces": [ - { - "name": "eth1", - "tx-packets": 33250, - "rx-packets": 34047, - "tx-session-packets": 8500, - "rx-session-packets": 8248, - "rx-session-packets-loss": 0, - "rx-session-packets-wrong-session": 0, - "tx-session-packets-avg-pps-max": 500, - "rx-session-packets-avg-pps-max": 500, - "tx-session-packets-ipv6": 8500, - "rx-session-packets-ipv6": 8000, - "rx-session-packets-ipv6-loss": 0, - "rx-session-packets-ipv6-wrong-session": 0, - "tx-session-packets-avg-pps-max-ipv6": 500, - "rx-session-packets-avg-pps-max-ipv6": 500, - "tx-session-packets-ipv6pd": 8500, - "rx-session-packets-ipv6pd": 8000, - "rx-session-packets-ipv6pd-loss": 0, - "rx-session-packets-ipv6pd-wrong-session": 0, - "tx-session-packets-avg-pps-max-ipv6pd": 500, - "rx-session-packets-avg-pps-max-ipv6pd": 500, - "rx-multicast-packets": 0, - "rx-multicast-packets-loss": 0, - "protocol-stats": { - "arp-tx": 0, - "arp-rx": 0, - "padi-tx": 500, - "pado-rx": 500, - "padr-tx": 500, - "pads-rx": 500, - "padt-tx": 1, - "padt-rx": 499, - "lcp-tx": 2249, - "lcp-rx": 2249, - "pap-tx": 250, - "pap-rx": 250, - "chap-tx": 250, - "chap-rx": 500, - "ipcp-tx": 1500, - "ipcp-rx": 1500, - "ip6cp-tx": 1500, - "ip6cp-rx": 1500, - "igmp-tx": 0, - "igmp-rx": 1298, - "icmp-tx": 0, - "icmp-rx": 0, - "icmpv6-tx": 500, - "icmpv6-rx": 500, - "dhcpv6-tx": 500, - "dhcpv6-rx": 500, - "lcp-echo-timeout": 0, - "lcp-request-timeout": 0, - "ipcp-request-timeout": 0, - "ip6cp-request-timeout": 0, - "pap-timeout": 0, - "chap-timeout": 0, - "icmpv6-rs-timeout": 0, - "dhcpv6-timeout": 0 - } - } - ], - "session-traffic": { - "config-ipv4-pps": 1, - "config-ipv6-pps": 1, - "config-ipv6pd-pps": 1, - "total-flows": 3000, - "verified-flows": 3000, - "verified-flows-access-ipv4": 500, - "verified-flows-access-ipv6": 500, - "verified-flows-access-ipv6pd": 500, - "verified-flows-network-ipv4": 500, - "verified-flows-network-ipv6": 500, - "verified-flows-network-ipv6pd": 500, - "first-seq-rx-access-ipv4-min": 1, - "first-seq-rx-access-ipv4-max": 2, - "first-seq-rx-access-ipv6-min": 2, - "first-seq-rx-access-ipv6-max": 2, - "first-seq-rx-access-ipv6pd-min": 2, - "first-seq-rx-access-ipv6pd-max": 2, - "first-seq-rx-network-ipv4-min": 1, - "first-seq-rx-network-ipv4-max": 2, - "first-seq-rx-network-ipv6-min": 2, - "first-seq-rx-network-ipv6-max": 2, - "first-seq-rx-network-ipv6pd-min": 2, - "first-seq-rx-network-ipv6pd-max": 2 - } - } -} -``` - -The optional argument `-j sessions` allows to include per session statistics -in the report file. Similar with `-j streams` which allows to include per stream -statistics. Both options could be also combined. - -## Interface Statistics - -## Session Traffic Statistics - -Those statistics are related to the test traffic send between PPPoE sessions -and the network interface. - -Flow | Description ----- | ----------- -Access RX | Network traffic received on access interface (downstream) -Access TX | Network traffic send from access interface (Upstream) -Network RX | Access traffic received on network interface (Upstream) -Network TX | Access traffic send from network interface (downstream) - -### Verified Traffic Flows - -Counts the verified traffic flows per type and direction. - -The `Access IPv4` tells how many sessions have successfully received -session verification traffic IPv4 traffic on the access interface. Similar -for IPv6 or IPv6PD (prefix delegation). Session verification traffic received -on the network interface is counted similar using the `Network IP...` statistics. - -Assuming session traffic is enabled for IPv4, IPv6 and IPv6PD, in this case -all statics should be equal matching the number of sessions. - -*Example report output for 100 sessions:* - -```text -Session Traffic: - Config: - IPv4 PPS: 1 - IPv6 PPS: 1 - IPv6PD PPS: 1 - Verified Traffic Flows: 3000/3000 - Access IPv4: 500 - Access IPv6: 500 - Access IPv6PD: 500 - Network IPv4: 500 - Network IPv6: 500 - Network IPv6PD: 500 - First Sequence Number Received: - Access IPv4 MIN: 1 MAX: 2 - Access IPv6 MIN: 2 MAX: 2 - Access IPv6PD MIN: 2 MAX: 2 - Network IPv4 MIN: 1 MAX: 2 - Network IPv6 MIN: 2 MAX: 2 - Network IPv6PD MIN: 2 MAX: 2 -``` - -JSON: - -```json -{ - "session-traffic": { - "config-ipv4-pps": 1, - "config-ipv6-pps": 1, - "config-ipv6pd-pps": 1, - "total-flows": 3000, - "verified-flows": 3000, - "verified-flows-access-ipv4": 500, - "verified-flows-access-ipv6": 500, - "verified-flows-access-ipv6pd": 500, - "verified-flows-network-ipv4": 500, - "verified-flows-network-ipv6": 500, - "verified-flows-network-ipv6pd": 500, - "first-seq-rx-access-ipv4-min": 1, - "first-seq-rx-access-ipv4-max": 2, - "first-seq-rx-access-ipv6-min": 2, - "first-seq-rx-access-ipv6-max": 2, - "first-seq-rx-access-ipv6pd-min": 2, - "first-seq-rx-access-ipv6pd-max": 2, - "first-seq-rx-network-ipv4-min": 1, - "first-seq-rx-network-ipv4-max": 2, - "first-seq-rx-network-ipv6-min": 2, - "first-seq-rx-network-ipv6-max": 2, - "first-seq-rx-network-ipv6pd-min": 2, - "first-seq-rx-network-ipv6pd-max": 2 - } -} -``` - -The flow verification status can be also queried via -global control socket command `session-traffic`. - -`$ cat command.json | jq .` - -```json -{ - "command": "session-traffic" -} -``` - -`$ cat command.json | sudo nc -U test.socket | jq .` - -```json -{ - "status": "ok", - "code": 200, - "session-traffic": { - "total-flows": 3000, - "verified-flows": 3000 - } -} -``` - -### First Sequence Number Received - -If session traffic is enabled, the BNG Blaster will start sending bidirectional -traffic between PPPoE session and network interface as soon as the session is -established using the rate as configured starting with sequence number 1 for -each flow. - -*Example config output with 1 packet per second:* - -```json -{ - "session-traffic": { - "ipv4-pps": 1, - "ipv6-pps": 1, - "ipv6pd-pps": 1 - } -} -``` - -Assuming the first sequence number received for given flow is 5 -combined with a rate of 1 PPS would mean that it took between 4 -and 5 seconds until forwarding is working. - -*Example report output with 1 packet per second:* - -```text -STDOUT: - - First Sequence Number Received: - Access IPv4 MIN: 1 MAX: 1 - Access IPv6 MIN: 1 MAX: 1 - Access IPv6PD MIN: 1 MAX: 1 - Network IPv4 MIN: 1 MAX: 1 - Network IPv6 MIN: 1 MAX: 1 - Network IPv6PD MIN: 1 MAX: 1 -``` - -JSON: - -```json -{ - "first-seq-rx-access-ipv4-min": 1, - "first-seq-rx-access-ipv4-max": 1, - "first-seq-rx-access-ipv6-min": 1, - "first-seq-rx-access-ipv6-max": 1, - "first-seq-rx-access-ipv6pd-min": 1, - "first-seq-rx-access-ipv6pd-max": 1, - "first-seq-rx-network-ipv4-min": 1, - "first-seq-rx-network-ipv4-max": 1, - "first-seq-rx-network-ipv6-min": 1, - "first-seq-rx-network-ipv6-max": 1, - "first-seq-rx-network-ipv6pd-min": 1, - "first-seq-rx-network-ipv6pd-max": 1 -} -``` diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..b334d495 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,3 @@ +sphinx +sphinx-rtd-theme +sphinx-tabs \ No newline at end of file diff --git a/docs/source/access/index.rst b/docs/source/access/index.rst new file mode 100644 index 00000000..84977079 --- /dev/null +++ b/docs/source/access/index.rst @@ -0,0 +1,13 @@ +Access Protocols +================ + +.. toctree:: + :maxdepth: 1 + + pppoe.rst + ipoe.rst + l2tp.rst + l2bsa.rst + traffic.rst + multicast.rst + li.rst diff --git a/docs/source/access/ipoe.rst b/docs/source/access/ipoe.rst new file mode 100644 index 00000000..ee5e56e3 --- /dev/null +++ b/docs/source/access/ipoe.rst @@ -0,0 +1,169 @@ +.. _ipoe: + +IPoE +---- + +The BNG Blaster is able to emulate IP over Ethernet (IPoE) +subscribers with static and dynamic address assignment +supporting 1:1 and N:1 VLAN mode. + +Static Addresses +~~~~~~~~~~~~~~~~ + +Static addresses means that the IP address and gateway is assigned +statically as shown in the example below. + +.. code-block:: json + + { + "interfaces": { + "access": [ + { + "interface": "eth1", + "type": "ipoe", + "vlan-mode": "1:1", + "outer-vlan-min": 128, + "outer-vlan-max": 4000, + "address": "200.0.0.1", + "address-iter": "0.0.0.4", + "gateway": "200.0.0.2", + "gateway-iter": "0.0.0.4", + } + ] + } + } + +DHCPv4/v6 +~~~~~~~~~ + +The most common case for IPoE is using DHCPv4/v6 as shown below. + +.. code-block:: json + + { + "interfaces": { + "access": [ + { + "interface": "eth1", + "type": "ipoe", + "outer-vlan": 7, + "vlan-mode": "N:1" + } + ] + }, + "dhcp": { + "enable": true, + }, + "dhcpv6": { + "enable": true + }, + "access-line": { + "agent-remote-id": "DEU.RTBRICK.{session-global}", + "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:{session-global}" + } + } + +IPoE +^^^^^ +.. include:: ../configuration/ipoe.rst + +DHCP +^^^^ +.. include:: ../configuration/dhcp.rst + +DHCPv6 +^^^^^^ +.. include:: ../configuration/dhcpv6.rst + +IPoE Commands +~~~~~~~~~~~~~ + +The control socket command ``session-info session-id `` provides +detailed information for IPoE sessions. + +``$ sudo bngblaster-cli run.sock session-info session-id 1 | jq .`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "session-information": { + "type": "ipoe", + "session-id": 1, + "session-state": "Established", + "interface": "eth1", + "outer-vlan": 8, + "inner-vlan": 1, + "mac": "02:00:00:00:00:01", + "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:1", + "agent-remote-id": "DEU.RTBRICK.1", + "ipv4-address": "1.1.1.3", + "ipv4-netmask": "255.255.255.255", + "ipv4-gateway": "1.1.1.1", + "ipv4-dns1": "10.0.0.3", + "ipv4-dns2": "10.0.0.4", + "ipv6-prefix": "fc66:1337:2222::3/128", + "ipv6-delegated-prefix": "fc66:1337:3333:2::/64", + "dhcp-state": "Bound", + "dhcp-server": "1.1.1.1", + "dhcp-lease-time": 300, + "dhcp-lease-expire": 299, + "dhcp-lease-expire-t1": 149, + "dhcp-lease-expire-t2": 261, + "dhcp-tx": 2, + "dhcp-rx": 2, + "dhcp-tx-discover": 1, + "dhcp-rx-offer": 1, + "dhcp-tx-request": 1, + "dhcp-rx-ack": 1, + "dhcp-rx-nak": 0, + "dhcp-tx-release": 0, + "dhcpv6-state": "Bound", + "dhcpv6-lease-time": 14400, + "dhcpv6-lease-expire": 14399, + "dhcpv6-lease-expire-t1": 899, + "dhcpv6-lease-expire-t2": 1439, + "dhcpv6-tx": 1, + "dhcpv6-rx": 1, + "dhcpv6-tx-solicit": 1, + "dhcpv6-rx-advertise": 0, + "dhcpv6-tx-request": 0, + "dhcpv6-rx-reply": 1, + "dhcpv6-tx-renew": 0, + "dhcpv6-tx-release": 0, + "dhcpv6-dns1": "fc66::3", + "dhcpv6-dns2": "fc66::4", + "tx-packets": 6, + "rx-packets": 6, + "rx-fragmented-packets": 0, + "session-traffic": { + "total-flows": 6, + "verified-flows": 0, + "first-seq-rx-access-ipv4": 0, + "first-seq-rx-access-ipv6": 0, + "first-seq-rx-access-ipv6pd": 0, + "first-seq-rx-network-ipv4": 0, + "first-seq-rx-network-ipv6": 0, + "first-seq-rx-network-ipv6pd": 0, + "access-tx-session-packets": 0, + "access-rx-session-packets": 0, + "access-rx-session-packets-loss": 0, + "network-tx-session-packets": 0, + "network-rx-session-packets": 0, + "network-rx-session-packets-loss": 0, + "access-tx-session-packets-ipv6": 0, + "access-rx-session-packets-ipv6": 0, + "access-rx-session-packets-ipv6-loss": 0, + "network-tx-session-packets-ipv6": 0, + "network-rx-session-packets-ipv6": 0, + "network-rx-session-packets-ipv6-loss": 0, + "access-tx-session-packets-ipv6pd": 0, + "access-rx-session-packets-ipv6pd": 0, + "access-rx-session-packets-ipv6pd-loss": 0, + "network-tx-session-packets-ipv6pd": 0, + "network-rx-session-packets-ipv6pd": 0, + "network-rx-session-packets-ipv6pd-loss": 0 + } + } + } diff --git a/docs/source/access/l2bsa.rst b/docs/source/access/l2bsa.rst new file mode 100644 index 00000000..e3578037 --- /dev/null +++ b/docs/source/access/l2bsa.rst @@ -0,0 +1,76 @@ +.. _l2bsa: + +L2BSA +----- + +The A10NSP interface emulates an layer two provider interface. The term A10 +refers to the end-to-end ADSL network reference model from TR-025. + +Following a basic PPPoE/A10NSP configuration example which is +detailed explained in the configuration section. + +.. code-block:: json + + { + "interfaces": { + "a10nsp": [ + { + "interface": "eth4", + "qinq": true, + "mac": "02:00:00:ff:ff:01" + }, + { + "interface": "eth5", + "qinq": true, + "mac": "02:00:00:ff:ff:01" + } + ], + "access": [ + { + "__comment__": "PPPoE", + "interface": "eth1", + "type": "pppoe", + "outer-vlan-min": 1, + "outer-vlan-max": 4000, + "inner-vlan": 7, + "stream-group-id": 1 + } + ] + }, + "pppoe": { + "reconnect": true, + "discovery-timeout": 3, + "discovery-retry": 10, + "host-uniq": true, + "vlan-priority": 6 + }, + "dhcpv6": { + "enable": false + }, + "session-traffic": { + "autostart": true, + "ipv4-pps": 10 + }, + "streams": [ + { + "stream-group-id": 2, + "name": "PPPOE-S1", + "type": "ipv4", + "direction": "both", + "priority": 128, + "length": 256, + "pps": 10, + "a10nsp-interface": "eth4" + }, + { + "stream-group-id": 2, + "name": "PPPOE-S2", + "type": "ipv4", + "direction": "both", + "priority": 128, + "length": 256, + "pps": 10, + "a10nsp-interface": "eth5" + } + ] + } diff --git a/docs/source/access/l2tp.rst b/docs/source/access/l2tp.rst new file mode 100644 index 00000000..6269fede --- /dev/null +++ b/docs/source/access/l2tp.rst @@ -0,0 +1,400 @@ +.. _l2tp: + +L2TP +---- + +The BNG Blaster is able to emulate L2TPv2 (RFC2661) LNS servers to +be able to test the L2TPv2 LAC functionality of the BNG device under +test. + +Configuration +~~~~~~~~~~~~~ + +Following an example with 30 L2TP LNS servers. + +.. code-block:: json + + { + "interfaces": { + "network": { + "interface": "eth2", + "address": "10.0.0.1", + "gateway": "10.0.0.2", + "address-ipv6": "fc66:1337:7331:8::10", + "gateway-ipv6": "fc66:1337:7331:8::1" + }, + "access": [ + { + "interface": "eth1", + "outer-vlan-min": 1, + "outer-vlan-max": 4000, + "inner-vlan-min": 7, + "inner-vlan-max": 7, + "authentication-protocol": "PAP" + }, + { + "interface": "eth1", + "outer-vlan-min": 1, + "outer-vlan-max": 4000, + "inner-vlan-min": 8, + "inner-vlan-max": 8, + "authentication-protocol": "CHAP" + } + ] + }, + "pppoe": { + "reconnect": true, + "discovery-timeout": 3, + "discovery-retry": 10 + }, + "ppp": { + "mru": 1492, + "authentication": { + "username": "blaster@l2tp.de", + "password": "test", + "timeout": 1, + "retry": 60 + }, + "lcp": { + "conf-request-timeout": 5, + "conf-request-retry": 30, + "keepalive-interval": 30, + "keepalive-retry": 3 + }, + "ipcp": { + "enable": true + }, + "ip6cp": { + "enable": true + } + }, + "access-line": { + "agent-remote-id": "DEU.RTBRICK.{session}", + "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:{session}", + "rate-up": 1024, + "rate-down": 16384 + }, + "l2tp-server": [ + { + "name": "LNS1", + "address": "10.0.0.11", + "secret": "test1", + "receive-window-size": 8 + }, + { + "name": "LNS2", + "address": "10.0.0.12", + "secret": "test2", + "receive-window-size": 8 + }, + { + "name": "LNS3", + "address": "10.0.0.13", + "secret": "test3", + "receive-window-size": 8 + }, + { + "name": "LNS4", + "address": "10.0.0.14", + "secret": "test4", + "receive-window-size": 8 + }, + { + "name": "LNS5", + "address": "10.0.0.15", + "secret": "test5", + "receive-window-size": 8 + }, + { + "name": "LNS6", + "address": "10.0.0.16", + "secret": "test6", + "receive-window-size": 8 + }, + { + "name": "LNS7", + "address": "10.0.0.17", + "secret": "test7", + "receive-window-size": 8 + }, + { + "name": "LNS8", + "address": "10.0.0.18", + "secret": "test8", + "receive-window-size": 8 + }, + { + "name": "LNS9", + "address": "10.0.0.19", + "secret": "test9", + "receive-window-size": 8 + }, + { + "name": "LNS10", + "address": "10.0.0.20", + "secret": "test10", + "receive-window-size": 8 + }, + { + "name": "LNS11", + "address": "10.0.0.21", + "secret": "test11", + "receive-window-size": 8 + }, + { + "name": "LNS12", + "address": "10.0.0.22", + "secret": "test12", + "receive-window-size": 8 + }, + { + "name": "LNS13", + "address": "10.0.0.23", + "secret": "test13", + "receive-window-size": 8 + }, + { + "name": "LNS14", + "address": "10.0.0.24", + "secret": "test14", + "receive-window-size": 8 + }, + { + "name": "LNS15", + "address": "10.0.0.25", + "secret": "test15", + "receive-window-size": 8 + }, + { + "name": "LNS16", + "address": "10.0.0.26", + "secret": "test16", + "receive-window-size": 8 + }, + { + "name": "LNS17", + "address": "10.0.0.27", + "secret": "test17", + "receive-window-size": 8 + }, + { + "name": "LNS18", + "address": "10.0.0.28", + "secret": "test18", + "receive-window-size": 8 + }, + { + "name": "LNS19", + "address": "10.0.0.29", + "secret": "test19", + "receive-window-size": 8 + }, + { + "name": "LNS20", + "address": "10.0.0.30", + "secret": "test20", + "receive-window-size": 8 + }, + { + "name": "LNS21", + "address": "10.0.0.31", + "secret": "test21", + "receive-window-size": 8 + }, + { + "name": "LNS22", + "address": "10.0.0.32", + "secret": "test22", + "receive-window-size": 8 + }, + { + "name": "LNS23", + "address": "10.0.0.33", + "secret": "test23", + "receive-window-size": 8 + }, + { + "name": "LNS24", + "address": "10.0.0.34", + "secret": "test24", + "receive-window-size": 8 + }, + { + "name": "LNS25", + "address": "10.0.0.35", + "secret": "test25", + "receive-window-size": 8 + }, + { + "name": "LNS26", + "address": "10.0.0.36", + "secret": "test26", + "receive-window-size": 8 + }, + { + "name": "LNS27", + "address": "10.0.0.37", + "secret": "test27", + "receive-window-size": 8 + }, + { + "name": "LNS28", + "address": "10.0.0.38", + "secret": "test28", + "receive-window-size": 8 + }, + { + "name": "LNS29", + "address": "10.0.0.39", + "secret": "test29", + "receive-window-size": 8 + }, + { + "name": "LNS30", + "address": "10.0.0.40", + "secret": "test30", + "receive-window-size": 8 + } + ], + "session-traffic": { + "autostart": true, + "ipv4-pps": 1 + } + } + +.. include:: ../configuration/lns.rst + +Variable Data Header +~~~~~~~~~~~~~~~~~~~~ + +The L2TP protocol allows different data header options resulting in +variable header lengths. The most common options can be tested with just +four servers as shown in the example below. + +.. code-block:: json + + { + "l2tp-server": [ + { + "name": "LNS1", + "address": "10.0.0.11", + "secret": "test1", + "receive-window-size": 8, + "congestion-mode": "default", + "data-control-priority": true + }, + { + "name": "LNS2", + "address": "10.0.0.12", + "secret": "test2", + "receive-window-size": 8, + "congestion-mode": "default", + "data-control-priority": true, + "data-length": true + }, + { + "name": "LNS3", + "address": "10.0.0.11", + "secret": "test3", + "receive-window-size": 8, + "congestion-mode": "default", + "data-control-priority": true, + "data-offset": true + }, + { + "name": "LNS4", + "address": "10.0.0.12", + "secret": "test4", + "receive-window-size": 8, + "congestion-mode": "default", + "data-control-priority": true, + "data-length": true, + "data-offset": true + } + ] + } + +RFC5515 +~~~~~~~ + +The Agent-Circuit-Id and Agent-Remote-Id AVP defined in RFC5515 +is supported and stored for each session if received. Received +CSUN messages are processed correctly and via control socket it +is possible to send also CSURQ requests to the LAC. + +L2TP Commands +~~~~~~~~~~~~~ + +The control socket command ``session-info l2tp-tunnels`` provides +detailed information about L2TP tunnels. + +``$ sudo bngblaster-cli run.sock l2tp-tunnels`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "l2tp-tunnels": [ + { + "state": "Established", + "server-name": "LNS1", + "server-address": "10.0.0.11", + "tunnel-id": 1, + "peer-tunnel-id": 50011, + "peer-name": "BNG", + "peer-address": "10.0.0.2", + "peer-vendor": "RtBrick, Inc.", + "secret": "test1", + "control-packets-rx": 102, + "control-packets-rx-dup": 0, + "control-packets-rx-out-of-order": 0, + "control-packets-tx": 102, + "control-packets-tx-retry": 0, + "data-packets-rx": 1406, + "data-packets-tx": 206 + } + ] + } + +The ``l2tp-sessions`` command returns all L2TP sessions. + +``$ sudo bngblaster-cli run.sock l2tp-sessions`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "l2tp-sessions": [ + { + "state": "Established", + "tunnel-id": 1, + "session-id": 1, + "peer-tunnel-id": 50011, + "peer-session-id": 32867, + "peer-proxy-auth-name": "blaster@l2tp.de", + "peer-called-number": "N/A", + "peer-calling-number": "N/A", + "peer-sub-address": "N/A", + "peer-tx-bps": 48000, + "peer-rx-bps": 1000, + "peer-ari": "DEU.RTBRICK.1", + "peer-aci": "0.0.0.0/0.0.0.0 eth 0:1", + "data-packets-rx": 79, + "data-packets-tx": 79, + "data-ipv4-packets-rx": 15, + "data-ipv4-packets-tx": 15 + } + ] + } + +This output can be also filtered to return only sessions +of a given tunnel. + +``sudo bngblaster-cli run.sock l2tp-sessions tunnel-id 1`` + +It is also possible to display a single session. + +``$ sudo bngblaster-cli run.sock l2tp-sessions tunnel-id 1 session-id 1`` + diff --git a/docs/source/access/li.rst b/docs/source/access/li.rst new file mode 100644 index 00000000..6c5cbdfb --- /dev/null +++ b/docs/source/access/li.rst @@ -0,0 +1,96 @@ +.. _li: + +Legal Interception (LI) +----------------------- + +The BNG Blaster can be used to emulate a mediation device providing detailed statistics +about the received flows. Today only the BCM QMX LI header format is supported but further +headers can be easily integrated. + +*BCM QMX LI Header Format* + +.. code-block:: none + + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | D | PT | SPT | LIID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +The functionality is automatically enabled on the network interface +and works combined with sessions in one instance or as standalone +mediation device as shown in the following example. + +.. code-block:: json + + { + "interfaces": { + "tx-interval": 10, + "rx-interval": 1, + "network": { + "interface": "eth2", + "address": "100.0.0.10/24", + "gateway": "100.0.0.2" + } + } + } + +The received flows can be displayed with the command `li-flows`. + +``$ sudo bngblaster-cli run.sock li-flows`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "li-flows": [ + { + "source-address": "1.1.1.1", + "source-port": 49152, + "destination-address": "1.1.1.2", + "destination-port": 49152, + "direction": "downstream", + "packet-type": "ethernet", + "sub-packet-type": "double-tagged", + "liid": 4194301, + "bytes-rx": 94, + "packets-rx": 1, + "packets-rx-ipv4": 0, + "packets-rx-ipv4-tcp": 0, + "packets-rx-ipv4-udp": 0, + "packets-rx-ipv4-host-internal": 0, + "packets-rx-ipv6": 0, + "packets-rx-ipv6-tcp": 0, + "packets-rx-ipv6-udp": 0, + "packets-rx-ipv6-host-internal": 0, + "packets-rx-ipv6-no-next-header": 0 + }, + { + "source-address": "1.1.1.1", + "source-port": 49152, + "destination-address": "1.1.1.2", + "destination-port": 49152, + "direction": "upstream", + "packet-type": "ethernet", + "sub-packet-type": "double-tagged", + "liid": 4194301, + "bytes-rx": 160720, + "packets-rx": 820, + "packets-rx-ipv4": 820, + "packets-rx-ipv4-tcp": 0, + "packets-rx-ipv4-udp": 0, + "packets-rx-ipv4-host-internal": 820, + "packets-rx-ipv6": 0, + "packets-rx-ipv6-tcp": 0, + "packets-rx-ipv6-udp": 0, + "packets-rx-ipv6-host-internal": 0, + "packets-rx-ipv6-no-next-header": 0 + } + ] + } + +The ``packets-rx-ipv4-host-internal`` refers to the IPv4 protocol number 61 +(any host internal protocol) which is used by some network testers as default +type for traffic streams. The same is valid for ``packets-rx-ipv6-host-internal`` +which refers to next header 61 and ``packets-rx-ipv6-no-next-header`` with next +header 59. diff --git a/docs/source/access/multicast.rst b/docs/source/access/multicast.rst new file mode 100644 index 00000000..8e3f2326 --- /dev/null +++ b/docs/source/access/multicast.rst @@ -0,0 +1,217 @@ +.. _multicast: + +Multicast and IPTV +------------------ + +The BNG Blaster provides advanced functionalities for testing multicast +over PPPoE sessions with focus on IPTV. Therefore IGMP version 1, 2 and 3 +is implemented with support for up to 8 group records per session and 3 +sources per group. + +Multicast testing is supported using external multicast traffic like real +world IPTV traffic or by generating multicast traffic on the network interface. + +Generate Multicast Traffic +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The BNG Blaster supports different ways to generate multicast traffic. The first +one is via igmp configuration and second one using raw streams. + +The following example shows how to generate traffic for 100 multicast groups +with one packet per millisecond for every group. + +.. code-block:: json + + { + "interfaces": { + "tx-interval": 1.0, + "rx-interval": 1.0, + "network": { + "interface": "eth2", + "address": "100.0.0.10", + "gateway": "100.0.0.2" + } + }, + "igmp": { + "group": "239.0.0.1", + "group-iter": "0.0.0.1", + "group-count": 100, + "source": "100.0.0.10", + "send-multicast-traffic": true + } + } + +It is recommended to send multicast traffic with 1000 PPS per group +to measure the join and leave delay in milliseconds. Therefore the +``tx-interval`` and ``rx-interval`` should be set to at to at least +`1.0` (1ms) for more precise IGMP join/leave delay measurements. + +It is also possible to generate multicast traffic using RAW streams as shown in the +example below: + +.. code-block:: json + + { + "streams": [ + { + "name": "MC1", + "type": "ipv4", + "direction": "downstream", + "priority": 128, + "network-ipv4-address": "1.1.1.1", + "destination-ipv4-address": "239.0.0.1", + "length": 256, + "pps": 1, + "network-interface": "eth1" + }, + { + "name": "MC2", + "type": "ipv4", + "direction": "downstream", + "priority": 128, + "network-ipv4-address": "2.2.2.2", + "destination-ipv4-address": "239.0.0.2", + "length": 256, + "pps": 1, + "network-interface": "eth2" + } + ] + } + +Using RAW streams allows to generate streams distributed over multiple network interfaces +with higher transmit rate using threaded streams if needed. + +Setting the ``destination-ipv4-address`` to an multicast IPv4 address is enough to generate +proper multicast streams. All headers including the BNG Blaster header will be automatically +set for multicast. Therefore such streams can be also used to measure the IGMP join and leave +delay. + +The BNG Blaster is recognizing loss using the :ref:`BNG Blaster header ` +sequence numbers. After first multicast traffic is received for a particular group, +for every further packet it checks if there is a gap between last and new sequence number +which is than reported as loss. The argument option ``-l loss`` enables loss logging which +allows to search for the missing packets in the corresponding capture files. + +.. tip:: + It is also possible to start a dedicated BNG Blaster instance to generate multicast + traffic which can be consumed by multiple BNG Blaster instances. The BNG Blaster + header allows to do the same measurements on traffic generated from same or different + BNG Blaster instance. + +Manual Join/Leave Testing +~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to join and leave multicast groups manually using the <> as +shown in the example below. + +``$ sudo bngblaster-cli run.sock igmp-join session-id 1 group 232.1.1.1 source1 202.11.23.101 source2 202.11.23.102 source3 202.11.23.103`` + +.. code-block:: json + + { + "status": "ok" + } + +``$ sudo bngblaster-cli run.sock igmp-info session-id 1`` + +.. code-block:: json + + { + "status": "ok", + "igmp-groups": [ + { + "group": "232.1.1.1", + "igmp-sources": [ + "202.11.23.101", + "202.11.23.102", + "202.11.23.103" + ], + "packets": 1291, + "loss": 0, + "state": "active", + "join-delay-ms": 139 + } + ] + } + +``$ sudo bngblaster-cli run.sock igmp-leave session-id 1 group 232.1.1.1`` + +.. code-block:: json + + { + "status": "ok" + } + +``$ sudo bngblaster-cli run.sock igmp-info session-id 1`` + +.. code-block:: json + + { + "status": "ok", + "igmp-groups": [ + { + "group": "232.1.1.1", + "igmp-sources": [ + "202.11.23.101", + "202.11.23.102", + "202.11.23.103" + ], + "packets": 7456, + "loss": 0, + "state": "idle", + "leave-delay-ms": 114 + } + ] + } + +IPTV Zapping Test +~~~~~~~~~~~~~~~~~ + +A key element of IPTV services is the delay in changing channels. +How long does it take to change from one channel to another, is +the right channel received and the old channel stopped without overlap +between old and new channel which may leads into traffic congestions if +both channels are send at the same time. Verify that fast channel changes +(zapping) works reliable as well. + +The BNG Blaster is able to emulate different client zapping behaviors and +measure the resulting join/leave delays and possible multicast traffic loss. + +The join delay is the time in milliseconds between sending join and receiving +first multicast packet of the requested group. The leave delay is the time between +sending leave and the last multicast packet received for this group. Multicast packets +received for the leaved group after first packet of joined group is received are counted +as overlap. + +The following configuration shows an example of the `igmp` section +for a typical zapping test. + +.. code-block:: json + + { + "igmp": { + "version": 3, + "start-delay": 10, + "group": "239.0.0.1", + "group-iter": "0.0.0.1", + "group-count": 20, + "source": "100.0.0.10", + "zapping-interval": 5, + "zapping-count": 5, + "zapping-view-duration": 30, + "zapping-wait": false, + "combined-leave-join": true, + "send-multicast-traffic": true + } + } + +Multicast Limitations +~~~~~~~~~~~~~~~~~~~~~ + +The BNG Blaster IGMP implementation supports up to 3 sources per group record +and 8 group records per session. + +The IGMP protocol stops working if IPCP has closed also if session IPCP renegotiates. +The whole session needs to be disconnected to restart IGMP. + +The check for overlapping multicast traffic is supported for zapping tests only. diff --git a/docs/source/access/pppoe.rst b/docs/source/access/pppoe.rst new file mode 100644 index 00000000..1e59b58f --- /dev/null +++ b/docs/source/access/pppoe.rst @@ -0,0 +1,213 @@ +.. _pppoe: + +PPPoE +----- + +Emulating PPP over Ethernet (PPPoE) sessions was initial +use case of the BNG Blaster supporting 1:1 and N:1 VLAN +mode. + +Configuration +~~~~~~~~~~~~~ + +Following a basic PPPoE configuration example. + +.. code-block:: json + + { + "interfaces": { + "network": { + "interface": "eth2", + "address": "10.0.0.1", + "gateway": "10.0.0.2", + "address-ipv6": "fc66:1337:7331::1", + "gateway-ipv6": "fc66:1337:7331::2" + }, + "access": [ + { + "interface": "eth1", + "type": "pppoe", + "outer-vlan-min": 1000, + "outer-vlan-max": 1999, + "inner-vlan-min": 1, + "inner-vlan-max": 4049, + "authentication-protocol": "PAP" + }, + { + "interface": "eth1", + "type": "pppoe", + "outer-vlan-min": 2000, + "outer-vlan-max": 2999, + "inner-vlan-min": 1, + "inner-vlan-max": 4049, + "authentication-protocol": "CHAP" + } + ] + }, + "sessions": { + "count": 1000, + "session-time": 0, + "max-outstanding": 800, + "start-rate": 400, + "stop-rate": 400 + }, + "pppoe": { + "reconnect": true, + "discovery-timeout": 3, + "discovery-retry": 10 + }, + "ppp": { + "mru": 1492, + "authentication": { + "username": "user{session-global}@rtbrick.com", + "password": "test", + "timeout": 5, + "retry": 30 + }, + "lcp": { + "conf-request-timeout": 1, + "conf-request-retry": 10, + "keepalive-interval": 30, + "keepalive-retry": 3 + }, + "ipcp": { + "enable": true, + "request-ip": true, + "request-dns1": true, + "request-dns2": true, + "conf-request-timeout": 1, + "conf-request-retry": 10 + }, + "ip6cp": { + "enable": true, + "conf-request-timeout": 1, + "conf-request-retry": 10 + } + }, + "dhcpv6": { + "enable": true, + "rapid-commit": true + }, + "access-line": { + "agent-remote-id": "DEU.RTBRICK.{session-global}", + "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:{session-global}", + "rate-up": 1024, + "rate-down": 16384 + }, + "session-traffic": { + "ipv4-pps": 1, + "ipv6-pps": 1, + "ipv6pd-pps": 1 + } + } + +PPPoE +^^^^^ +.. include:: ../configuration/pppoe.rst + +PPP +^^^ +.. include:: ../configuration/ppp.rst + +PPP Authentication +^^^^^^^^^^^^^^^^^^ +.. include:: ../configuration/ppp_authentication.rst + +PPP LCP +^^^^^^^ +.. include:: ../configuration/ppp_lcp.rst + +PPP IPCP (IPv4) +^^^^^^^^^^^^^^^ +.. include:: ../configuration/ppp_ipcp.rst + +PPP IP6CP (IPv6) +^^^^^^^^^^^^^^^^ +.. include:: ../configuration/ppp_ip6cp.rst + + +LCP Vendor Extension +~~~~~~~~~~~~~~~~~~~~ + +This chapter refers to RFC 2153 PPP vendor extensions. + +Per default all LCP vendor specific requests will be rejected sending a +LCP code reject message. With the LCP option ``ignore-vendor-specific`` +enabled, those messages will be ignored as required to emulate different CPE +behaviors. + +The LCP option ``connection-status-message`` allows to accept LCP vendor requests +with any OUI if kind is set to ``1`` by responding with vendor request of +kind ``2``. The OUI from request is copied to response in this case. +The value from request is stored in the session as ``connection-status-message``. + +PPPoE Commands +~~~~~~~~~~~~~~ + +The control socket command ``session-info session-id `` provides +detailed information for PPPoE sessions. + +``$ sudo bngblaster-cli run.sock session-info session-id 1 | jq .`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "session-information": { + "type": "pppoe", + "session-id": 1, + "session-state": "Established", + "interface": "eth1", + "outer-vlan": 1000, + "inner-vlan": 1, + "mac": "02:00:00:00:00:01", + "username": "user1@rtbrick.com", + "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:1", + "agent-remote-id": "DEU.RTBRICK.1", + "lcp-state": "Opened", + "ipcp-state": "Opened", + "ip6cp-state": "Opened", + "ipv4-address": "10.100.128.0", + "ipv4-dns1": "10.0.0.3", + "ipv4-dns2": "10.0.0.4", + "ipv6-prefix": "fc66:1000:1::/64", + "ipv6-delegated-prefix": "fc66:2000::/56", + "ipv6-dns1": "fc66::3", + "ipv6-dns2": "fc66::4", + "dhcpv6-state": "Bound", + "dhcpv6-dns1": "fc66::3", + "dhcpv6-dns2": "fc66::4", + "tx-packets": 10036, + "rx-packets": 10083, + "rx-fragmented-packets": 0, + "session-traffic": { + "total-flows": 6, + "verified-flows": 6, + "first-seq-rx-access-ipv4": 2, + "first-seq-rx-access-ipv6": 3, + "first-seq-rx-access-ipv6pd": 3, + "first-seq-rx-network-ipv4": 2, + "first-seq-rx-network-ipv6": 3, + "first-seq-rx-network-ipv6pd": 3, + "access-tx-session-packets": 3266, + "access-rx-session-packets": 3265, + "access-rx-session-packets-loss": 0, + "network-tx-session-packets": 3266, + "network-rx-session-packets": 3265, + "network-rx-session-packets-loss": 0, + "access-tx-session-packets-ipv6": 3266, + "access-rx-session-packets-ipv6": 3264, + "access-rx-session-packets-ipv6-loss": 0, + "network-tx-session-packets-ipv6": 3266, + "network-rx-session-packets-ipv6": 3264, + "network-rx-session-packets-ipv6-loss": 0, + "access-tx-session-packets-ipv6pd": 3266, + "access-rx-session-packets-ipv6pd": 3264, + "access-rx-session-packets-ipv6pd-loss": 0, + "network-tx-session-packets-ipv6pd": 3266, + "network-rx-session-packets-ipv6pd": 3264, + "network-rx-session-packets-ipv6pd-loss": 0 + } + } + } diff --git a/docs/source/access/traffic.rst b/docs/source/access/traffic.rst new file mode 100644 index 00000000..69d4651e --- /dev/null +++ b/docs/source/access/traffic.rst @@ -0,0 +1,79 @@ +.. _session-traffic: + +Session Traffic +--------------- + +The BNG Blaster is able to generate bidirectional unicast +session traffic for all addresses assigned to a session +(IPv4, IPv6 and IPv6PD). + +.. image:: ../images/bbl_session_traffic.png + :alt: Session Traffic + +This is a powerful tool to quickly verify that forwarding +is correctly setup and working. + +Configuration +~~~~~~~~~~~~~ + +The following example shows how to enable session-traffic. + +.. code-block:: json + + { + "session-traffic": { + "ipv4-pps": 1, + "ipv6-pps": 1, + "ipv6pd-pps": 1 + } + } + +.. include:: ../configuration/isis.rst + +This traffic is generated between the session and a network +interface. In case of multiple network interfaces, the preferred +network interfaces can be selected using the ``network-interface`` +option in the corresponding access configuration. + +Verification +~~~~~~~~~~~~ + +The final report includes detailed information +for session traffic. + +*Example report output for 100 sessions:* + +.. code-block:: none + + Session Traffic: + Config: + IPv4 PPS: 1 + IPv6 PPS: 1 + IPv6PD PPS: 1 + Verified Traffic Flows: 3000/3000 + Access IPv4: 500 + Access IPv6: 500 + Access IPv6PD: 500 + Network IPv4: 500 + Network IPv6: 500 + Network IPv6PD: 500 + First Sequence Number Received: + Access IPv4 MIN: 1 ( 1.000s) MAX: 2 ( 2.000s) + Access IPv6 MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) + Access IPv6PD MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) + Network IPv4 MIN: 1 ( 1.000s) MAX: 2 ( 2.000s) + Network IPv6 MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) + Network IPv6PD MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) + + +The statistics starting with ``Access ...`` correspond to traffic +received on the access interface (network->access) where those +starting with ``Network ...`` correspond to traffic received on +the network interface (access->network). + +The ``First Sequence Number Received`` is used to measure the forwarding +convergence. The session traffic starts automatically as soo as the session +is established using the rate configured. All traffic flows in the BNG Blaster +start with the 64bit sequence number 1. Assuming the first sequence number +received for given flow is 5 combined with a rate of 1 PPS would mean that +it took between 4 and 5 seconds until forwarding is working. \ No newline at end of file diff --git a/docs/source/api/bgp.rst b/docs/source/api/bgp.rst new file mode 100644 index 00000000..53ddf4d7 --- /dev/null +++ b/docs/source/api/bgp.rst @@ -0,0 +1,27 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `bgp-sessions` + - Display all matching BGP sessions + - + - `local-ipv4-address`, `peer-ipv4-address` + * - `bgp-disconnect` + - Disconnect all matching BGP sessions + - + - `local-ipv4-address`, `peer-ipv4-address` + * - `bgp-teardown` + - Teardown BGP + - + - + * - `bgp-raw-update-list` + - List all loaded BGP RAW update files + - + - + * - `bgp-raw-update` + - Update all matching BGP session + - `file` + - `local-ipv4-address`, `peer-ipv4-address` diff --git a/docs/source/api/cfm.rst b/docs/source/api/cfm.rst new file mode 100644 index 00000000..2e4d75bd --- /dev/null +++ b/docs/source/api/cfm.rst @@ -0,0 +1,23 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `cfm-cc-start` + - Start EOAM CFM CC + - + - `session-id` + * - `cfm-cc-stop` + - Stop EOAM CFM CC + - + - `session-id` + * - `cfm-cc-rdi-on` + - Set EOAM CFM CC RDI + - + - `session-id` + * - `cfm-cc-rdi-off` + - Unset EOAM CFM CC RDI + - + - `session-id` \ No newline at end of file diff --git a/docs/source/api/igmp.rst b/docs/source/api/igmp.rst new file mode 100644 index 00000000..0c779d0c --- /dev/null +++ b/docs/source/api/igmp.rst @@ -0,0 +1,19 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `igmp-join` + - Join group + - `group` + - `source1`, `source2`, `source3` + * - `igmp-leave` + - Leave group + - `group` + - + * - `igmp-info` + - Display group information + - + - \ No newline at end of file diff --git a/docs/source/api/index.rst b/docs/source/api/index.rst new file mode 100644 index 00000000..1e579365 --- /dev/null +++ b/docs/source/api/index.rst @@ -0,0 +1,178 @@ +.. _api: + +API/CLI +======= + +The control socket is an unix domain stream socket that +allows interacting with the BNG Blaster using JSON RPC. + +We developed this interface for the BNG Blaster Controller +but it can be also used by other tools. One example is the +included CLI tool ``bngblaster-cli``. You can use this for +interactive communication with the BNG Blaster. + +You need to enable the control socket by providing the path to +the socket file with the argument ``-S`` (``bngblaster -S run.sock``). + +Each request must contain at least the ``command`` element which carries +the actual command with optional arguments. + +.. code-block:: json + + { + "command": "" + "arguments": { + "": "" + } + } + +Following an example RPC request with corresponding response. + +``$ cat command.json | jq .`` + +.. code-block:: json + + { + "command": "session-counters" + } + +``$ cat command.json | sudo nc -U run.sock | jq .`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "session-counters": { + "sessions": 3, + "sessions-established": 3, + "sessions-flapped": 3, + "dhcpv6-sessions-established": 3 + } + } + +The response contains at least the status element with the +value ``ok`` and status code ``2xx`` if request was successfully. +The status can be also set to ``warning`` or ``error`` with +corresponding error code and an optional error message. + +``$ cat command.json | sudo nc -U test.socket | jq .`` + +.. code-block:: json + + { + "status": "warning", + "code": 404, + "message": "session not found" + } + + +The ``session-id`` is the same as used for ``{session-global}`` in the +configuration. This number starts with 1 and is increased +per session added. In example if username is configured as +``user{session-global}@rtbrick.com`` and logged in user is +``user10@rtbrick.com`` the ``session-id`` of this user is ``10``. + +.. tip:: + The argument ``session-id`` can be alternatively replaced + with interface index and VLAN of the session. The interface + index (``ifindex``) can be requested using the ``interfaces`` + command or skipped. The first access interface is automatically + used if the argument ``ifindex`` is not present in the command. + + This is not supported for N:1 sessions because multiple + sessions can be assigned to a single VLAN. + + .. code-block:: json + + { + "command": "session-info", + "arguments": { + "ifindex": 10, + "outer-vlan": 1, + "inner-vlan": 1 + } + } + +BNG Blaster CLI +--------------- + +The python script ``bngblaster-cli`` provides a simple CLI tool +for interactive communication with the BNG Blaster. + +.. code-block:: none + + $ sudo bngblaster-cli + BNG Blaster Control Socket Client + + bngblaster-cli [arguments] + + Examples: + bngblaster-cli run.sock session-info session-id 1 + bngblaster-cli run.sock igmp-join session-id 1 group 239.0.0.1 source1 1.1.1.1 source2 2.2.2.2 source3 3.3.3.3 + bngblaster-cli run.sock igmp-info session-id 1 + bngblaster-cli run.sock l2tp-csurq tunnel-id 1 sessions [1,2] + +``$ sudo bngblaster-cli run.sock session-counters | jq .`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "session-counters": { + "sessions": 1, + "sessions-established": 1, + "sessions-flapped": 0, + "dhcpv6-sessions-established": 1 + } + } + + +Interfaces +---------- +.. include:: interfaces.rst + +Sessions +-------- +.. include:: sessions.rst + +PPP +--- +.. include:: ppp.rst + +L2TP +---- +.. include:: l2tp.rst + +IGMP +---- +.. include:: igmp.rst + +Traffic +------- +.. include:: traffic.rst + +Streams +------- +.. include:: streams.rst + +ISIS +---- +.. include:: isis.rst + +BGP +--- +.. include:: bgp.rst + +CFM +--- +.. include:: cfm.rst + +Legal Interception (LI) +----------------------- + +This is explained detailed in the +:ref:`Legal Interception (LI)
  • ` section. + +.. include:: li.rst diff --git a/docs/source/api/interfaces.rst b/docs/source/api/interfaces.rst new file mode 100644 index 00000000..ad5a181b --- /dev/null +++ b/docs/source/api/interfaces.rst @@ -0,0 +1,11 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `interfaces` + - List all interfaces with index + - + - diff --git a/docs/source/api/isis.rst b/docs/source/api/isis.rst new file mode 100644 index 00000000..27a11523 --- /dev/null +++ b/docs/source/api/isis.rst @@ -0,0 +1,27 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `isis-adjacencies` + - Display ISIS adjacencies + - + - + * - `isis-database` + - Display ISIS database (LSDB) + - `instance`, `level` + - + * - `isis-load-mrt` + - Load ISIS MRT file + - `instance`, `file` + - + * - `isis-lsp-update` + - Update ISIS LSP + - `instance`, `pdu` + - + * - `isis-teardown` + - Teardown ISIS + - + - \ No newline at end of file diff --git a/docs/source/api/l2tp.rst b/docs/source/api/l2tp.rst new file mode 100644 index 00000000..c6918344 --- /dev/null +++ b/docs/source/api/l2tp.rst @@ -0,0 +1,53 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `l2tp-tunnels` + - Display all L2TP tunnels + - + - + * - `l2tp-sessions` + - L2TP all matching sessions + - + - `tunnel-id`, `session-id` + * - `l2tp-csurq` + - Send L2TP CSURQ + - `tunnel-id` + - `sessions` (list of remote session-id) + * - `l2tp-tunnel-terminate` + - Terminate L2TP tunnel + - `tunnel-id` + - `result-code`, `error-code`, `error-message` + * - `l2tp-session-terminate` + - Terminate L2TP session + - `session-id` + - `result-code`, `error-code`, `error-message`, `disconnect-code`, `disconnect-protocol`, `disconnect-direction`, `disconnect-message` + +The L2TP CSURQ command expects the local tunnel-id and a list of remote +session-id for which a connect speed update is requested. + +.. code-block:: json + + { + "command": "l2tp-csurq", + "arguments": { + "tunnel-id": 1, + "sessions": [ + 1, + 2, + 3, + 4 + ] + } + } + +This command can be executed as shown below using the CLI tool. + +``$ sudo bngblaster-cli run.sock l2tp-csurq tunnel-id 1 sessions [1,2,3,4]`` + +The L2TP session terminate command allows to test result (RFC2661) and disconnect (RFC3145) codes. + +``$ sudo bngblaster-cli run.sock l2tp-session-terminate session-id 1 result-code 2 error-message "LCP request" disconnect-code 3 disconnect-message "LCP terminate request"`` diff --git a/docs/source/api/li.rst b/docs/source/api/li.rst new file mode 100644 index 00000000..665c5eb1 --- /dev/null +++ b/docs/source/api/li.rst @@ -0,0 +1,11 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `li-flows` + - List all LI flows with detailed statistics + - + - diff --git a/docs/source/api/ppp.rst b/docs/source/api/ppp.rst new file mode 100644 index 00000000..c1b77030 --- /dev/null +++ b/docs/source/api/ppp.rst @@ -0,0 +1,23 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `ipcp-open` + - Open IPCP + - + - `session-id` + * - `ipcp-close` + - Close IPCP + - + - `session-id` + * - `ip6cp-open` + - Open IP6CP + - + - `session-id` + * - `ip6cp-close` + - Close IP6CP + - + - `session-id` diff --git a/docs/source/api/sessions.rst b/docs/source/api/sessions.rst new file mode 100644 index 00000000..eb7ffe39 --- /dev/null +++ b/docs/source/api/sessions.rst @@ -0,0 +1,39 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `session-info` + - Display session information + - + - `session-id` + * - `session-counters` + - Display session counters + - + - + * - `sessions-pending` + - List all sessions not established + - + - + * - `session-traffic` + - Display session traffic statistics + - + - + * - `session-traffic-start` + - Enable/start session traffic + - + - `session-id` + * - `session-traffic-stop` + - Disable/stop session traffic + - + - `session-id` + * - `session-streams` + - Display session streams + - `session-id` + - + * - `terminate` + - Terminate session + - + - `session-id` \ No newline at end of file diff --git a/docs/source/api/streams.rst b/docs/source/api/streams.rst new file mode 100644 index 00000000..5c7b41aa --- /dev/null +++ b/docs/source/api/streams.rst @@ -0,0 +1,23 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `stream-stats` + - Display stream traffic statistics + - + - + * - `stream-info` + - Display stream/flow information + - + - `flow-id` + * - `stream-traffic-start` + - Enable/start traffic streams + - + - `session-id` + * - `stream-traffic-stop` + - Disable stop traffic streams + - + - `session-id` diff --git a/docs/source/api/traffic.rst b/docs/source/api/traffic.rst new file mode 100644 index 00000000..d3419a26 --- /dev/null +++ b/docs/source/api/traffic.rst @@ -0,0 +1,23 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `traffic-start` + - Start all traffic (session and streams) + - + - + * - `traffic-stop` + - Stop all traffic (session and streams) + - + - + * - `multicast-traffic-start` + - Start multicast traffic + - + - + * - `multicast-traffic-stop` + - Stop multicast traffic + - + - \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..a4700486 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,32 @@ +# Configuration file for the Sphinx documentation builder. + +# -- Project information + +project = 'BNG Blaster' +copyright = '2020-2022, RtBrick, Inc.' +author = 'Christian Giese' +release = '0.0' +version = '0.0.0' + +# -- General configuration + +extensions = [ + 'sphinx_tabs.tabs' +] + +master_doc = 'index' +html_logo = 'images/rtbrick_logo.png' + +templates_path = ['_templates'] + +# -- Options for HTML output + +html_theme = 'sphinx_rtd_theme' +html_theme_options = { + 'logo_only': False, + 'display_version': False, +} + +# -- Options for EPUB output + +epub_show_urls = 'footnote' diff --git a/docs/source/configuration/access_line.rst b/docs/source/configuration/access_line.rst new file mode 100644 index 00000000..952a7a1d --- /dev/null +++ b/docs/source/configuration/access_line.rst @@ -0,0 +1,27 @@ +.. code-block:: json + + { "access-line": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `agent-circuit-id` + - Agent-Circuit-Id + - + * - `agent-remote-id` + - Agent-Remote-Id + - + * - `rate-up` + - Actual Data Rate Upstream + - + * - `rate-down` + - Actual Data Rate Downstream + - + * - `dsl-type` + - DSL-Type + - \ No newline at end of file diff --git a/docs/source/configuration/access_line_profiles.rst b/docs/source/configuration/access_line_profiles.rst new file mode 100644 index 00000000..07242c76 --- /dev/null +++ b/docs/source/configuration/access_line_profiles.rst @@ -0,0 +1,113 @@ +.. code-block:: json + + { "access-line-profiles": [] } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `access-line-profile-id` + - Mandatory access-line-profile identifier + - + * - `act-up` + - Actual Data Rate Upstream + - 0 + * - `act-down` + - Actual Data Rate Downstream + - 0 + * - `min-up` + - Minimum Data Rate Upstream + - 0 + * - `min-down` + - Minimum Data Rate Downstream + - 0 + * - `att-up` + - Attainable DataRate Upstream + - 0 + * - `att-down` + - Attainable DataRate Downstream + - 0 + * - `max-up` + - Maximum Data Rate Upstream + - 0 + * - `max-down` + - Maximum Data Rate Downstream + - 0 + * - `min-up-low` + - Min Data Rate Upstream in low power state + - 0 + * - `min-down-low` + - Min Data Rate Downstream in low power state + - 0 + * - `max-interl-delay-up` + - Max Interleaving Delay Upstream + - 0 + * - `act-interl-delay-up` + - Actual Interleaving Delay Upstream + - 0 + * - `max-interl-delay-down` + - Max Interleaving Delay Downstream + - 0 + * - `act-interl-delay-down` + - Actual Interleaving Delay Downstream + - 0 + * - `data-link-encaps` + - Data Link Encapsulation + - 0 + * - `dsl-type` + - DSL Type + - 0 + * - `pon-type` + - PON Access Type + - 0 + * - `etr-up` + - Expected Throughput (ETR) Upstream + - 0 + * - `etr-down` + - Expected Throughput (ETR) Downstream + - 0 + * - `attetr-up` + - Attainable Expected Throughput (ATTETR) Upstream + - 0 + * - `attetr-down` + - Attainable Expected Throughput (ATTETR) Downstream + - 0 + * - `gdr-up` + - Gamma Data Rate (GDR) Upstream + - 0 + * - `gdr-down` + - Gamma Data Rate (GDR) Downstream + - 0 + * - `attgdr-up` + - Attainable Gamma Data Rate (ATTGDR) Upstream + - 0 + * - `attgdr-down` + - Attainable Gamma Data Rate (ATTGDR) Downstream + - 0 + * - `ont-onu-avg-down` + - ONT/ONU Average Data Rate Downstream + - 0 + * - `ont-onu-peak-down` + - ONT/ONUPeak Data Rate Downstream + - 0 + * - `ont-onu-max-up` + - ONT/ONU Maximum Data Rate Upstream + - 0 + * - `ont-onu-ass-up` + - ONT/ONU Assured Data Rate Upstream + - 0 + * - `pon-max-up` + - PON Tree Maximum Data Rate Upstream + - 0 + * - `pon-max-down` + - PON Tree Maximum Data Rate Downstream + - 0 + +Attributes with value set to 0 will not be send. + +The values for ``rate-up``, ``rate-down`` and ``dsl-type`` defined in the +access-line or interface section have priority over those defined here. diff --git a/docs/source/configuration/bgp.rst b/docs/source/configuration/bgp.rst new file mode 100644 index 00000000..7c1ebf00 --- /dev/null +++ b/docs/source/configuration/bgp.rst @@ -0,0 +1,45 @@ +.. code-block:: json + + { "bgp": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `network-interface` + - BGP local interface (source-interface) + - first network interface + * - `local-ipv4-address` + - BGP local IPv4 address (source-address) + - network interface address + * - `local-as` + - BGP local AS + - 65000 + * - `peer-ipv4-address` + - BGP peer address + - + * - `peer-as` + - BGP peer AS + - local AS + * - `holdtime` + - BGP holdtime in seconds + - 90 + * - `id` + - BGP identifier + - 1.2.3.4 + * - `reconnect` + - BGP reconnect + - true + * - `start-traffic` + - BGP start global traffic after RAW update + - false + * - `teardown-time` + - BGP teardown time in seconds + - 5 + * - `raw-update-file` + - BGP RAW update file + - \ No newline at end of file diff --git a/docs/source/configuration/dhcp.rst b/docs/source/configuration/dhcp.rst new file mode 100644 index 00000000..f0702541 --- /dev/null +++ b/docs/source/configuration/dhcp.rst @@ -0,0 +1,36 @@ +.. code-block:: json + + { "dhcp": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `enable` + - This option allows to enable or disable DHCP + - false + * - `broadcast` + - DHCP broadcast flag + - false + * - `timeout` + - DHCP timeout in seconds + - 5 + * - `retry` + - DHCP retry + - 10 + * - `release-interval` + - DHCP release interval + - 1 + * - `release-retry` + - DHCP release retry + - 3 + * - `tos` + - IPv4 TOS for all DHCP control traffic + - 0 + * - `vlan-priority` + - VLAN PBIT for all DHCP control traffic + - 0 \ No newline at end of file diff --git a/docs/source/configuration/dhcpv6.rst b/docs/source/configuration/dhcpv6.rst new file mode 100644 index 00000000..29ac71d1 --- /dev/null +++ b/docs/source/configuration/dhcpv6.rst @@ -0,0 +1,24 @@ +.. code-block:: json + + { "dhcpv6": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `enable` + - This option allows to enable or disable DHCPv6 + - true + * - `rapid-commit` + - DHCPv6 rapid commit (2 way handshake) + - true + * - `timeout` + - DHCPv6 timeout in seconds + - 5 + * - `retry` + - DHCPv6 retry + - 10 \ No newline at end of file diff --git a/docs/source/configuration/igmp.rst b/docs/source/configuration/igmp.rst new file mode 100644 index 00000000..5252464f --- /dev/null +++ b/docs/source/configuration/igmp.rst @@ -0,0 +1,72 @@ +.. code-block:: json + + { "igmp": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `autostart` + - Automatically join after session is established + - true + * - `version` + - IGMP protocol version (1, 2 or 3) + - 3 + * - `combined-leave-join` + - Combine leave and join records within a single IGMPv3 report + - true + * - `start-delay` + - Delay between session established and initial IGMP join in seconds + - 1 + * - `group` + - Multicast group base address (e.g. 239.0.0.1) + - 0.0.0.0 (disabled) + * - `group-iter` + - Multicast group iterator + - 0.0.0.1 + * - `group-count` + - Multicast group count + - 1 + * - `source` + - Multicast source address (e.g. 1.1.1.1) + - 0.0.0.0 (ASM) + * - `zapping-interval` + - IGMP channel zapping interval in seconds + - 0 (disabled) + * - `zapping-count` + - Define the amount of channel changes before starting view duration + - 0 (disabled) + * - `view-duration` + - Define the view duration in seconds + - 0 (disabled) + * - `send-multicast-traffic` + - Generate multicast traffic + - false + * - `multicast-traffic-length` + - Multicast traffic IP length + - 76 + * - `multicast-traffic-tos` + - Multicast traffic TOS priority + - 0 + * - `network-interface` + - Multicast traffic source interface + - + +Per default join and leave requests are send using dedicated reports. +The option ``combined-leave-join`` allows the combination of leave and +join records within a single IGMPv3 report using multiple group records. +This option is applicable to IGMP version 3 only! + +If ``send-multicast-traffic`` is true, the BNG Blaster generates multicast +traffic on the network interface based on the specified group and source +attributes mentioned before. This traffic includes some special signatures +for faster processing and more detailed analysis. + +If group is set to 293.0.0.1 with group-iter of 0.0.0.2, source 1.1.1.1 +and group-count 3 the result are the following three groups (S.G) +1.1.1.1,239.0.0.1, 1.1.1.1,239.0.0.3 and 1.1.1.1,239.0.0.5. + diff --git a/docs/source/configuration/index.rst b/docs/source/configuration/index.rst new file mode 100644 index 00000000..9cdfecc3 --- /dev/null +++ b/docs/source/configuration/index.rst @@ -0,0 +1,109 @@ +.. _configuration: + +Configuration +============= + +Interfaces +---------- + +The BNG Blaster interfaces are explained detailed in the +:ref:`interfaces section `. + +.. include:: interfaces.rst + +Network Interfaces +~~~~~~~~~~~~~~~~~~ +.. include:: interfaces_network.rst + +Access Interfaces +~~~~~~~~~~~~~~~~~ +.. include:: interfaces_access.rst + +A10NSP Interfaces +~~~~~~~~~~~~~~~~~ +.. include:: interfaces_a10nsp.rst + +Sessions +-------- +.. include:: sessions.rst + +IPoE +---- +.. include:: ipoe.rst + +PPPoE +----- +.. include:: pppoe.rst + +PPP +--- +.. include:: ppp.rst + +PPP Authentication +~~~~~~~~~~~~~~~~~~ +.. include:: ppp_authentication.rst + +PPP LCP +~~~~~~~~~~~~~~~~~~ +.. include:: ppp_lcp.rst + +PPP IPCP (IPv4) +~~~~~~~~~~~~~~~ +.. include:: ppp_ipcp.rst + +PPP IP6CP (IPv6) +~~~~~~~~~~~~~~~~ +.. include:: ppp_ip6cp.rst + +DHCP +---- +.. include:: dhcp.rst + +DHCPv6 +------ +.. include:: dhcpv6.rst + +IGMP +---- +.. include:: igmp.rst + +L2TPv2 Server (LNS) +------------------- +.. include:: lns.rst + +Traffic +------- +.. include:: traffic.rst + +Traffic-Streams +--------------- +.. include:: streams.rst + +Session-Traffic +--------------- +.. include:: session_traffic.rst + +Access-Line +----------- +.. include:: access_line.rst + +Access-Line-Profiles +-------------------- +.. include:: access_line_profiles.rst + +ISIS +---- +.. include:: isis.rst + +ISIS External +~~~~~~~~~~~~~ +.. include:: isis_external.rst + + +ISIS External Connections +~~~~~~~~~~~~~~~~~~~~~~~~~ +.. include:: isis_external_connections.rst + +BGP +--- +.. include:: bgp.rst \ No newline at end of file diff --git a/docs/source/configuration/interfaces.rst b/docs/source/configuration/interfaces.rst new file mode 100644 index 00000000..a097529c --- /dev/null +++ b/docs/source/configuration/interfaces.rst @@ -0,0 +1,33 @@ +.. code-block:: json + + { "interfaces": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `tx-interval` + - TX ring polling interval in milliseconds + - 5.0 + * - `rx-interval` + - RX ring polling interval in milliseconds + - 5.0 + * - `qdisc-bypass` + - Bypass the kernel's qdisc layer + - true + * - `io-mode` + - IO mode + - packet_mmap_raw + * - `io-slots` + - IO slots (ring size) + - 1024 + * - `io-stream-max-ppi` + - IO traffic stream max packets per interval + - 32 + * - `capture-include-streams` + - Include traffic streams in capture + - true \ No newline at end of file diff --git a/docs/source/configuration/interfaces_a10nsp.rst b/docs/source/configuration/interfaces_a10nsp.rst new file mode 100644 index 00000000..b72ee2c7 --- /dev/null +++ b/docs/source/configuration/interfaces_a10nsp.rst @@ -0,0 +1,21 @@ +.. code-block:: json + + { "interfaces": { "a10nsp": [] } } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `interface` + - A10nSP interface name (e.g. eth0, ...) + - + * - `qinq` + - Set outer VLAN ethertype to QinQ (0x88a8) + - false + * - `mac` + - Optional set gateway interface address manually + - \ No newline at end of file diff --git a/docs/source/configuration/interfaces_access.rst b/docs/source/configuration/interfaces_access.rst new file mode 100644 index 00000000..49eb5678 --- /dev/null +++ b/docs/source/configuration/interfaces_access.rst @@ -0,0 +1,138 @@ +.. code-block:: json + + { "interfaces": { "access": [] } } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `interface` + - Access interface name (e.g. eth0, ...) + - + * - `network-interface` + - Select the corresponding network interface for this session + - + * - `type` + - Set access type (`pppoe` or `ipoe`) + - pppoe + * - `vlan-mode` + - Set VLAN mode `1:1` or `N:1` + - 1:1 + * - `qinq` + - Set outer VLAN ethertype to QinQ (0x88a8) + - false + * - `outer-vlan-min` + - Outer VLAN minimum value + - 0 (untagged) + * - `outer-vlan-max` + - Outer VLAN maximum value + - 0 (untagged) + * - `outer-vlan` + - Set outer-vlan-min/max equally + - + * - `inner-vlan-min` + - Inner VLAN minimum value + - 0 (untagged) + * - `inner-vlan-max` + - Inner VLAN maximum value + - 0 (untagged) + * - `inner-vlan` + - Set inner-vlan-min/max equally + - + * - `third-vlan` + - Add a fixed third VLAN (most inner VLAN) + - 0 (untagged) + * - `address` + - Static IPv4 base address (IPoE only) + - + * - `address-iter` + - Static IPv4 base address iterator (IPoE only) + - + * - `gateway` + - Static IPv4 gateway address (IPoE only) + - + * - `gateway-iter` + - Static IPv4 gateway address iterator (IPoE only) + - + * - `username` + - Overwrite the username from authentication section + - + * - `password` + - Overwrite the password from authentication section + - + * - `authentication-protocol` + - Overwrite the username from authentication section + - + * - `agent-circuit-id` + - Overwrite the agent-circuit-id from access-line section + - + * - `agent-remote-id` + - Overwrite the agent-remote-id from access-line section + - + * - `rate-up` + - Overwrite the rate-up from access-line section + - + * - `rate-down` + - Overwrite the rate-down from access-line section + - + * - `dsl-type` + - Overwrite the dsl-type from access-line section + - + * - `ipcp` + - De-/activate PPP IPCP + - + * - `ip6cp` + - De-/activate PPP IP6CP + - + * - `ipv4` + - De-/activate IPoE IPv4 + - + * - `ipv6` + - De-/activate IPoE IPv6 + - + * - `dhcp` + - De-/activate DHCP + - + * - `dhcpv6` + - De-/activate DHCPv6 + - + * - `igmp-autostart` + - Overwrite IGMP autostart + - + * - `igmp-version` + - Overwrite IGMP protocol version (1, 2 or 3) + - + * - `stream-group-id` + - Stream group identifier + - + * - `access-line-profile-id` + - Access-line-profile identifier + - + * - `cfm-cc` + - De-/activate EOAM CFM CC (IPoE only) + - false + * - `cfm-level` + - Set EOAM CFM maintenance domain level + - 0 + * - `cfm-ma-id` + - Set EOAM CFM maintenance association identifier + - 0 + * - `cfm-ma-name` + - Set EOAM CFM maintenance association short name + - + * - `i1-start` + - Iterator for usage in strings `{i1}` + - 1 + * - `i1-step` + - Iterator step per session + - 1 + * - `i2-start` + - Iterator for usage in strings `{i2}` + - 1 + * - `i2-step` + - Iterator step per session + - 1 \ No newline at end of file diff --git a/docs/source/configuration/interfaces_network.rst b/docs/source/configuration/interfaces_network.rst new file mode 100644 index 00000000..f89bc4fc --- /dev/null +++ b/docs/source/configuration/interfaces_network.rst @@ -0,0 +1,51 @@ +.. code-block:: json + + { "interfaces": { "network": [] } } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `interface` + - Network interface name (e.g. eth0, ...) + - + * - `address` + - Local network interface IPv4 address + - + * - `gateway` + - Gateway network interface IPv4 address + - + * - `address-ipv6` + - Local network interface IPv6 address (implicitly /64) + - + * - `gateway-ipv6` + - Gateway network interface IPv6 address (implicitly /64) + - + * - `vlan` + - Network interface VLAN + - 0 (untagged) + * - `gateway-mac` + - Optional set gateway MAC address manually + - + * - `gateway-resolve-wait` + - Sessions will not start until gateways are resolved + - true + * - `isis-instance-id` + - Assign interface to ISIS instance + - + * - `isis-level` + - ISIS interface level + - 3 + * - `isis-p2p` + - ISIS P2P interface + - true + * - `isis-l1-metric` + - ISIS level 1 interface metric + - 10 + * - `isis-l2-metric` + - ISIS level 2 interface metric + - 10 \ No newline at end of file diff --git a/docs/source/configuration/ipoe.rst b/docs/source/configuration/ipoe.rst new file mode 100644 index 00000000..b4961823 --- /dev/null +++ b/docs/source/configuration/ipoe.rst @@ -0,0 +1,24 @@ +.. code-block:: json + + { "ipoe": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `ipv4` + - Enable/disable IPv4 + - true (enabled) + * - `arp-timeout` + - Initial ARP resolve timeout/retry interval in seconds + - 1 + * - `arp-interval` + - Periodic ARP interval in seconds (0 means disabled) + - 300 + * - `ipv6` + - Enable/disable IPv6 + - true (enabled) \ No newline at end of file diff --git a/docs/source/configuration/isis.rst b/docs/source/configuration/isis.rst new file mode 100644 index 00000000..85341a4b --- /dev/null +++ b/docs/source/configuration/isis.rst @@ -0,0 +1,90 @@ +.. code-block:: json + + { "isis": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `instance-id` + - ISIS instance identifier + - + * - `level` + - ISIS level + - 3 + * - `overload` + - ISIS overload + - false + * - `protocol-ipv4` + - Enable/disable IPv4 + - true + * - `protocol-ipv6` + - Enable/disable IPv6 + - true + * - `level1-auth-key` + - ISIS level 1 authentication key + - + * - `level1-auth-type` + - ISIS level 1 authentication type (simple or md5) + - disabled + * - `level2-auth-key` + - ISIS level 2 authentication key + - + * - `level2-auth-type` + - ISIS level 2 authentication type (simple or md5) + - disabled + * - `hello-interval` + - ISIS hello interval in seconds + - 10 + * - `hello-padding` + - ISIS hello padding + - false + * - `holding-time` + - ISIS holding time in seconds + - 30 + * - `lsp-lifetime` + - ISIS LSP lifetime in seconds + - 65535 + * - `lsp-refresh-interval` + - ISIS LSP refresh interval in seconds + - 300 + * - `lsp-retry-interval` + - ISIS LSP retry interval in seconds + - 5 + * - `lsp-tx-interval` + - ISIS LSP TX interval in ms (time between LSP send windows) + - 10 + * - `lsp-tx-window-size` + - ISIS LSP TX window size (LSP send per window) + - 1 + * - `csnp-interval` + - ISIS CSNP interval in seconds + - 30 + * - `hostname` + - ISIS hostname + - bngblaster + * - `router-id` + - ISIS router identifier + - 10.10.10.10 + * - `system-id` + - ISIS system identifier + - 0100.1001.0010 + * - `area` + - ISIS area(s) + - 49.0001/24 + * - `sr-base` + - ISIS SR base + - + * - `sr-range` + - ISIS SR range + - + * - `sr-node-sid` + - ISIS SR node SID + - + * - `teardown-time` + - ISIS teardown time in seconds + - 5 \ No newline at end of file diff --git a/docs/source/configuration/isis_external.rst b/docs/source/configuration/isis_external.rst new file mode 100644 index 00000000..33d4efd5 --- /dev/null +++ b/docs/source/configuration/isis_external.rst @@ -0,0 +1,15 @@ +.. code-block:: json + + { "isis": { "external": {} } } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `mrt-file` + - ISIS MRT file + - \ No newline at end of file diff --git a/docs/source/configuration/isis_external_connections.rst b/docs/source/configuration/isis_external_connections.rst new file mode 100644 index 00000000..cd3ddea0 --- /dev/null +++ b/docs/source/configuration/isis_external_connections.rst @@ -0,0 +1,21 @@ +.. code-block:: json + + { "isis": { "external": { "connections": [] } } } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `system-id` + - ISIS system identifier + - + * - `l1-metric` + - ISIS level 1 interface metric + - 10 + * - `l2-metric` + - ISIS level 2 interface metric + - 10 \ No newline at end of file diff --git a/docs/source/configuration/lns.rst b/docs/source/configuration/lns.rst new file mode 100644 index 00000000..a9c4884f --- /dev/null +++ b/docs/source/configuration/lns.rst @@ -0,0 +1,53 @@ +.. code-block:: json + + { "l2tp-server": [] } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `name` + - Mandatory L2TP LNS server hostname (AVP 7) + - + * - `address` + - Mandatory L2TP server address + - + * - `secret` + - Tunnel secret + - + * - `receive-window-size` + - Control messages receive window size + - 4 + * - `max-retry` + - Control messages max retry + - 30 + * - `congestion-mode` + - Control messages congestion mode + - default + * - `data-control-priority` + - Set the priority bit in the L2TP header for all non-IP data packets (LCP, IPCP, ...) + - false + * - `data-length` + - Set length bit for all data packets + - false + * - `data-offset` + - Set offset bit with offset zero for all data packets + - false + * - `control-tos` + - L2TP control traffic (SCCRQ, ICRQ, ...) TOS priority + - 0 + * - `data-control-tos` + - Set the L2TP tunnel TOS priority (outer IPv4 header) for all non-IP data packets (LCP, IPCP, ...) + - 0 + +The BNG Blaster supports different congestion modes for the +reliable delivery of control messages. The ``default`` mode +is described in RFC2661 appendix A (Control Channel Slow Start and +Congestion Avoidance). The mode ``slow`` uses a fixed control window +size of 1 where ``aggressive`` sticks to max permitted based on peer +received window size. + diff --git a/docs/source/configuration/ppp.rst b/docs/source/configuration/ppp.rst new file mode 100644 index 00000000..b805c60c --- /dev/null +++ b/docs/source/configuration/ppp.rst @@ -0,0 +1,15 @@ +.. code-block:: json + + { "ppp": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `mru` + - Define the maximum receive unit proposed via PPP + - 1492 \ No newline at end of file diff --git a/docs/source/configuration/ppp_authentication.rst b/docs/source/configuration/ppp_authentication.rst new file mode 100644 index 00000000..96cddd39 --- /dev/null +++ b/docs/source/configuration/ppp_authentication.rst @@ -0,0 +1,27 @@ +.. code-block:: json + + { "ppp": { "authentication": {} } } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `username` + - Username + - user{session-global}@rtbrick.com + * - `password` + - Password + - test + * - `timeout` + - Authentication request timeout in seconds + - 5 + * - `retry` + - Authentication request max retry + - 30 + * - `protocol` + - This value can be set to `PAP` or `CHAP` to reject the other protocol + - allow PAP and CHAP \ No newline at end of file diff --git a/docs/source/configuration/ppp_ip6cp.rst b/docs/source/configuration/ppp_ip6cp.rst new file mode 100644 index 00000000..3e74537a --- /dev/null +++ b/docs/source/configuration/ppp_ip6cp.rst @@ -0,0 +1,21 @@ +.. code-block:: json + + { "ppp": { "ip6cp": {} } } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `enable` + - This option allows to enable or disable the IP6CP protocol + - true + * - `conf-request-timeout` + - IP6CP configuration request timeout in seconds + - 5 + * - `conf-request-retry` + - IP6CP configuration request max retry + - 10 \ No newline at end of file diff --git a/docs/source/configuration/ppp_ipcp.rst b/docs/source/configuration/ppp_ipcp.rst new file mode 100644 index 00000000..3c4cda6b --- /dev/null +++ b/docs/source/configuration/ppp_ipcp.rst @@ -0,0 +1,30 @@ +.. code-block:: json + + { "ppp": { "ipcp": {} } } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `enable` + - This option allows to enable or disable the IPCP protocol + - true + * - `request-ip` + - Include IP-Address with 0.0.0.0 in initial LCP configuration request + - true + * - `request-dns1` + - Request Primary DNS Server Address (option 129) + - true + * - `request-dns2` + - Request Secondary DNS Server Address (option 131) + - true + * - `conf-request-timeout` + - IPCP configuration request timeout in seconds + - 5 + * - `conf-request-retry` + - IPCP configuration request max retry + - 10 \ No newline at end of file diff --git a/docs/source/configuration/ppp_lcp.rst b/docs/source/configuration/ppp_lcp.rst new file mode 100644 index 00000000..6df2f837 --- /dev/null +++ b/docs/source/configuration/ppp_lcp.rst @@ -0,0 +1,33 @@ +.. code-block:: json + + { "ppp": { "lcp": {} } } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `conf-request-timeout` + - LCP configuration request timeout in seconds + - 5 + * - `conf-request-retry` + - LCP configuration request max retry + - 10 + * - `keepalive-interval` + - LCP echo request interval in seconds (0 means disabled) + - 30 + * - `keepalive-retry` + - PPP LCP echo request max retry + - 3 + * - `start-delay` + - PPP LCP initial request delay in milliseconds + - 0 + * - `ignore-vendor-specific` + - Ignore LCP vendor specific requests + - false + * - `connection-status-message` + - Accept LCP connection status messages + - false \ No newline at end of file diff --git a/docs/source/configuration/pppoe.rst b/docs/source/configuration/pppoe.rst new file mode 100644 index 00000000..60c50369 --- /dev/null +++ b/docs/source/configuration/pppoe.rst @@ -0,0 +1,33 @@ +.. code-block:: json + + { "pppoe": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `session-time` + - Max PPPoE session time in seconds + - 0 (infinity) + * - `reconnect` + - Automatically reconnect sessions if terminated + - false + * - `discovery-timeout` + - PPPoE discovery (PADI and PADR) timeout in seconds + - 5 + * - `discovery-retry` + - PPPoE discovery (PADI and PADR) max retry + - 10 + * - `service-name` + - PPPoE discovery service name + - + * - `host-uniq` + - PPPoE discovery host-uniq + - false + * - `vlan-priority` + - VLAN PBIT for all PPPoE/PPP control traffic + - 0 diff --git a/docs/source/configuration/session_traffic.rst b/docs/source/configuration/session_traffic.rst new file mode 100644 index 00000000..40264e2d --- /dev/null +++ b/docs/source/configuration/session_traffic.rst @@ -0,0 +1,24 @@ +.. code-block:: json + + { "session-traffic": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `autostart` + - Automatically start session traffic after session is established + - true + * - `ipv4-pps` + - Generate bidirectional IPv4 traffic between network interface and all session framed IPv4 addresses + - 0 (disabled) + * - `ipv6-pps` + - Generate bidirectional IPv6 traffic between network interface and all session framed IPv6 addresses + - 0 (disabled) + * - `ipv6pd-pps` + - Generate bidirectional Ipv6 traffic between network interface and all session delegated IPv6 addresses + - 0 (disabled) \ No newline at end of file diff --git a/docs/source/configuration/sessions.rst b/docs/source/configuration/sessions.rst new file mode 100644 index 00000000..29bf936a --- /dev/null +++ b/docs/source/configuration/sessions.rst @@ -0,0 +1,47 @@ +.. code-block:: json + + { "sessions": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `count` + - Sessions (PPPoE + IPoE) + - 1 + * - `max-outstanding` + - Max outstanding sessions + - 800 + * - `start-rate` + - Setup request rate in sessions per second + - 400 + * - `stop-rate` + - Teardown request rate in sessions per second + - 400 + * - `iterate-vlan-outer` + - Iterate on outer VLAN first + - false + * - `start-delay` + - Wait N seconds after all interface are resolved before starting sessions + - 0 + +Per default sessions are created by iteration over inner VLAN range first and +outer VLAN second. Which can be changed by ``iterate-vlan-outer`` to iterate +on outer VLAN first and inner VLAN second. + +Therefore the following configuration generates the sessions on VLAN (outer:inner) +1:3, 1:4, 2:3, 2:4 per default or alternative 1:3, 2:3, 1:4, 2:4 with +``iterate-vlan-outer`` enabled. + +.. code-block:: json + + { + "outer-vlan-min": 1, + "outer-vlan-max": 2, + "inner-vlan-min": 3, + "inner-vlan-max": 4 + } diff --git a/docs/source/configuration/streams.rst b/docs/source/configuration/streams.rst new file mode 100644 index 00000000..c5626d56 --- /dev/null +++ b/docs/source/configuration/streams.rst @@ -0,0 +1,110 @@ +.. code-block:: json + + { "streams": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `name` + - Mandatory stream name + - + * - `stream-group-id` + - Stream group identifier + - 0 (raw) + * - `type` + - Mandatory stream type (`ipv4`, `ipv6` or `ipv6pd`) + - + * - `direction` + - Mandatory stream direction (`upstream`, `downstream` or `both`) + - `both` + * - `priority` + - IPv4 TOS / IPv6 TC + - 0 + * - `vlan-priority` + - VLAN priority + - 0 + * - `length` + - Layer 3 (IP + payload) traffic length (76 - 9000) + - 128 + * - `pps` + - Stream traffic rate in packets per second + - 1 + * - `bps` + - Stream traffic rate in bits per second (layer 3) + - + * - `a10nsp-interface` + - Select the corresponding A10NSP interface for this stream + - + * - `network-interface` + - Select the corresponding network interface for this stream + - + * - `network-ipv4-address` + - Overwrite network interface IPv4 address + - + * - `network-ipv6-address` + - Overwrite network interface IPv6 address + - + * - `destination-ipv4-address` + - Overwrite the IPv4 destination address + - + * - `destination-ipv6-address` + - Overwrite the IPv6 destination address + - + * - `access-ipv4-source-address` + - Overwrite the access IPv4 source address (client) + - + * - `access-ipv6-source-address` + - Overwrite the access IPv6 source address (client) + - + * - `threaded` + - Run those streams in separate threads + - false + * - `thread-group` + - Assign this stream to thread group (1-255) + - 0 (thread per stream) + * - `max-packets` + - Send a burst of N packets and stop + - 0 (infinity) + * - `start-delay` + - Wait N seconds after session is established before start + - 0 + * - `tx-label1` + - MPLS send (TX) label (outer label) + - + * - `tx-label1-exp` + - EXP bits of first label (outer label) + - 0 + * - `tx-label1-ttl` + - TTL of first label (outer label) + - 255 + * - `tx-label2` + - MPLS send (TX) label (inner label) + - + * - `tx-label2-exp` + - EXP bits of first label (inner label) + - 0 + * - `tx-label2-ttl` + - TTL of first label (inner label) + - 255 + * - `rx-label1` + - Expected receive MPLS label (outer label) + - + * - `rx-label2` + - Expected receive MPLS label (inner label) + - + +For L2TP downstream traffic the IPv4 TOS is applied to the outer IPv4 +and inner IPv4 header. + +The ``pps`` option supports also float numbers like 0.1, or 2.5 PPS and has +priority over ``bps`` where second is only a helper to calculate the ``pps`` +based on given ``bps`` and ``length``. + +The options ``access-ipv4-source-address`` and ``access-ipv6-source-address`` +are used to test the BNG RPF functionality with traffic send from source addresses +different to those assigned to the client. diff --git a/docs/source/configuration/traffic.rst b/docs/source/configuration/traffic.rst new file mode 100644 index 00000000..81f72909 --- /dev/null +++ b/docs/source/configuration/traffic.rst @@ -0,0 +1,18 @@ +.. code-block:: json + + { "traffic": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `autostart` + - Automatically start traffic + - true + * - `stop-verified` + - Automatically stop traffic streams if verified + - false \ No newline at end of file diff --git a/docs/source/faq.rst b/docs/source/faq.rst new file mode 100644 index 00000000..42a6c634 --- /dev/null +++ b/docs/source/faq.rst @@ -0,0 +1,16 @@ +Frequently Asked Questions +========================== + +**Some session established on BNG are not established on BNG Blaster?** + +The BNG Blaster considers a session only as established if all configured +protocols are established. This could occur if the device under test (your BNG) +is configured for IPv4 only but the BNG Blaster is configured for IPv4 and IPv6. + +The idea here is to prevent that potential failures will be overseen. + +**DHCPv6 does not start for PPPoE sessions?** + +The BNG Blaster expects an ICMPv6 router-advertisement with other-config flag +before it starts sending DHCPv6 within a PPPoE session. + diff --git a/docs/images/bbl_arch.png b/docs/source/images/bbl_arch.png similarity index 100% rename from docs/images/bbl_arch.png rename to docs/source/images/bbl_arch.png diff --git a/docs/images/bbl_header.png b/docs/source/images/bbl_header.png similarity index 100% rename from docs/images/bbl_header.png rename to docs/source/images/bbl_header.png diff --git a/docs/images/bbl_interactive.png b/docs/source/images/bbl_interactive.png similarity index 100% rename from docs/images/bbl_interactive.png rename to docs/source/images/bbl_interactive.png diff --git a/docs/images/bbl_interfaces.png b/docs/source/images/bbl_interfaces.png similarity index 100% rename from docs/images/bbl_interfaces.png rename to docs/source/images/bbl_interfaces.png diff --git a/docs/images/bbl_isis.png b/docs/source/images/bbl_isis.png similarity index 100% rename from docs/images/bbl_isis.png rename to docs/source/images/bbl_isis.png diff --git a/docs/images/bbl_session_traffic.png b/docs/source/images/bbl_session_traffic.png similarity index 100% rename from docs/images/bbl_session_traffic.png rename to docs/source/images/bbl_session_traffic.png diff --git a/docs/images/bbl_streams.png b/docs/source/images/bbl_streams.png similarity index 100% rename from docs/images/bbl_streams.png rename to docs/source/images/bbl_streams.png diff --git a/docs/images/logo.png b/docs/source/images/logo.png similarity index 100% rename from docs/images/logo.png rename to docs/source/images/logo.png diff --git a/docs/images/pppoe-fsm.dot b/docs/source/images/pppoe-fsm.dot similarity index 100% rename from docs/images/pppoe-fsm.dot rename to docs/source/images/pppoe-fsm.dot diff --git a/docs/images/pppoe-fsm.svg b/docs/source/images/pppoe-fsm.svg similarity index 100% rename from docs/images/pppoe-fsm.svg rename to docs/source/images/pppoe-fsm.svg diff --git a/docs/source/images/quickstart1.png b/docs/source/images/quickstart1.png new file mode 100644 index 0000000000000000000000000000000000000000..423e5b2f68adcb1ba2ffddc6e7aea94eb596d012 GIT binary patch literal 308152 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

    U-}zhBJb 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%0D_&EEG)>4I; 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 qjE`_ and good presentation +from `DENOG13 `_ can be found on YouTube. + +.. image:: images/bbl_interactive.png + :alt: BNG Blaster Interactive + +Contents +-------- + +.. toctree:: + :maxdepth: 1 + + install + quickstart + interfaces + access/index + routing/index + streams + reports + configuration/index + api/index + troubleshooting + reference/index + faq + +License +------- + +BNG Blaster is licensed under the BSD 3-Clause License, which means that you are free to get and use it for +commercial and non-commercial purposes as long as you fulfill its conditions. + +See the `LICENSE `_ +file for more details. + +Copyright +--------- +.. |copy| unicode:: U+000A9 .. COPYRIGHT SIGN + +Copyright |copy| 2020-2022, RtBrick, Inc. + +Contact +------- + +bngblaster@rtbrick.com \ No newline at end of file diff --git a/docs/source/install.rst b/docs/source/install.rst new file mode 100644 index 00000000..d33708cc --- /dev/null +++ b/docs/source/install.rst @@ -0,0 +1,161 @@ +.. _install: + +Installation +============ + +The BNG Blaster should run on any modern linux distribution +but is primary tested on Ubuntu 18.04 LTS and Ubuntu 20.04 LTS. + +Install Ubuntu +-------------- + +Install dependencies: + +.. code-block:: none + + sudo apt install -y libssl1.1 libncurses5 libjansson4 + +Download and install debian package: https://github.com/rtbrick/bngblaster/releases + +.. code-block:: none + + sudo dpkg -i + +This command installs the BNG Blaster to `/usr/sbin/bngblaster`. + +Build from Sources +------------------ + +Dependencies +^^^^^^^^^^^^ + +The BNG Blaster has dependencies to the RtBrick +`libdict fork `_ +and the following standard dependencies: + +.. code-block:: none + + # libdict + wget https://github.com/rtbrick/libdict/releases/download/v1.0.1/libdict-debian.zip + sudo dpkg -i libdict_1.0.1_amd64.deb + sudo dpkg -i libdict-dev_1.0.1_amd64.deb + + # standard dependencies + sudo apt install -y cmake \ + libcunit1-dev \ + libncurses5-dev \ + libssl-dev \ + libjansson-dev + +Build +^^^^^ + +Per default cmake (`cmake .`) will build the BNG Blaster as release +version with optimization and without debug symbols. + +.. code-block:: none + + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release .. + make all + +Alternative it is also possible to build a debug +version for detailed troubleshooting using gdb. + +.. code-block:: none + + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Debug .. + make all + + +There are also CPack files generated which allows to easily generate a debian +package by just executing `cpack` from build directory. + +It is also recommended to provide the GIT commit details to be included in the +manually build version as shown below: + +.. code-block:: none + + cmake -DGIT_REF=`git rev-parse --abbrev-ref HEAD` -DGIT_SHA=`git rev-parse HEAD` . + +*Example:* + +.. code-block:: none + + $ bngblaster -v + GIT: + REF: dev + SHA: df453a5ee9dbf6440aefbfb9630fa0f06e326d44 + IO Modes: packet_mmap_raw (default), packet_mmap, raw + +Install +^^^^^^^ + +Then BNG Blaster can be installed using make install target. + +.. code-block:: none + + sudo make install + +This command installs the BNG Blaster to `/usr/sbin/bngblaster`. + +Build and Run Unit Tests +^^^^^^^^^^^^^^^^^^^^^^^^ + +Building and running unit tests requires CMocka to be installed: + +.. code-block:: none + + sudo apt install libcmocka-dev + +The option `BNGBLASTER_TESTS` enables to build unit tests. + +.. code-block:: none + + cmake -DCMAKE_BUILD_TYPE=Debug -DBNGBLASTER_TESTS=ON . + make all + make test + +*Example:* + +.. code-block:: none + + $ make test + Running tests... + Test project + Start 1: TestProtocols + 1/1 Test #1: TestProtocols .................... Passed 0.00 sec + + 100% tests passed, 0 tests failed out of 1 + + Total Test time (real) = 0.00 sec + +Running BNG Blaster +------------------- + +The BNG Blaster needs permissions to send raw packets and change network interface +settings. The easiest way to run the BNG Blaster is either as the root user or with +sudo: + +.. code-block:: none + + # As root + bngblaster -C config.json -I + + # As a normal user: + sudo bngblaster -C config.json -I + + +A third option is to set capabilities on the binary with in example `setcap` +as shown below: + +.. code-block:: none + + sudo setcap cap_net_raw,cap_net_admin,cap_dac_read_search+eip `which bngblaster` + + # As normal user: + bngblaster -C config.json -I + diff --git a/docs/source/interfaces.rst b/docs/source/interfaces.rst new file mode 100644 index 00000000..3a553016 --- /dev/null +++ b/docs/source/interfaces.rst @@ -0,0 +1,325 @@ +.. _interfaces: + +Interfaces +========== + +The BNG Blaster supports three types of interfaces. + +All interfaces are optional but obviously at least +one interface is required to start the BNG Blaster. + +Interface Settings +------------------ + +The following settings are applied to all interfaces. + +.. code-block:: json + + { + "interfaces": { + "tx-interval": 0.1, + "rx-interval": 0.1, + "io-slots": 2048, + } + } + + +.. include:: configuration/interfaces.rst + +The ``tx-interval`` and ``rx-interval`` should be set to at to at least ``1.0`` (1ms) +if more precise timestamps or high throughput is needed. This is recommended for IGMP +join/leave or QoS delay measurements. For higher packet rates (>1g) it might be needed to +increase the ``io-slots`` from the default value of ``1024`` to ``2048`` or more. + +The supported IO modes are listed with ``bngblaster -v`` but except +``packet_mmap_raw`` all other modes are currently considered as experimental. In +the default mode (``packet_mmap_raw``) all packets are received in a Packet MMAP +ring buffer and send directly trough RAW packet sockets. + +The interfaces used in BNG Blaster do not need IP addresses configured in the host +operating system but they need to be in up state. + +.. code-block:: none + + sudo ip link set dev up + +It is not possible to send packets larger than the interface MTU which is 1500 per default +but for PPPoE with multiple VLAN headers this might be not enough for large packets. +Therefore the interface MTU should be increased using the following commands. + +.. code-block:: none + + sudo ip link set mtu 9000 dev + + +This can be also archived via netplan using the following configuration for each BNG Blaster +interface. + +.. code-block:: yaml + + network: + version: 2 + renderer: networkd + ethernets: + eth1: + dhcp4: no + dhcp6: no + link-local: [] + mtu: 9000 + eth2: + dhcp4: no + dhcp6: no + link-local: [] + mtu: 9000 + + +.. note:: The number of interfaces is currently limited to 32! + + +Network Interfaces +------------------ + +.. _network-interface: + +The network interfaces are used for traffic and routing protocols. + +Those interfaces can communicate with the configured gateway only. +Meaning that all traffic sent from the network interface will be sent +to the learned MAC address of the configured gateway. + +The network interface behaves like a router accepting all traffic +sent to its own MAC address. This allows to send and receive traffic +for prefixes advertised via routing protocols or configured statically +on the connected device under test. + +The BNG Blaster will also respond to all ICMP echo requests sent to its +own MAC address. + +.. include:: configuration/interfaces_network.rst + +The BNG Blaster supports multiple network interfaces +as shown in the example below. + +.. code-block:: json + + { + "interfaces": { + "tx-interval": 1, + "rx-interval": 1, + "io-slots": 4096, + "network": [ + { + "interface": "eth2", + "address": "10.0.0.1", + "gateway": "10.0.0.2", + "address-ipv6": "fc66:1337:7331::1", + "gateway-ipv6": "fc66:1337:7331::2" + }, + { + "interface": "eth3", + "address": "10.0.1.1", + "gateway": "10.0.1.2", + "address-ipv6": "fc66:1337:7331:1::1", + "gateway-ipv6": "fc66:1337:7331:1::2" + } + ], + } + } + +Using multiple network interfaces requires to select which network interface +to be used otherwise one of the interface is selected automatically. Therefore +the configuration option ``network-interface`` is supported in different sections. + +Access Interfaces +----------------- + +.. _access-interface: + +The access interface are used to emulate PPPoE and IPoE clients. + +.. include:: configuration/interfaces_access.rst + +For all modes it is possible to configure between zero and three VLAN +tags on the access interface as shown below. + +.. code-block:: none + + [ethernet][outer-vlan][inner-vlan][third-vlan][pppoe]... + + +Untagged +~~~~~~~~ +With untagged only one session is possible. + +.. code-block:: json + + { + "access": { + "interface": "eth1", + "outer-vlan-min": 0, + "outer-vlan-max": 0, + "inner-vlan-min": 0, + "inner-vlan-max": 0 + } + } + +Single Tagged +~~~~~~~~~~~~~ +.. code-block:: json + + { + "access": { + "interface": "eth1", + "outer-vlan-min": 1, + "outer-vlan-max": 4049, + "inner-vlan-min": 0, + "inner-vlan-max": 0 + } + } + + +Double Tagged +~~~~~~~~~~~~~ +.. code-block:: json + + { + "access": { + "interface": "eth1", + "outer-vlan-min": 1, + "outer-vlan-max": 4049, + "inner-vlan-min": 7, + "inner-vlan-max": 7 + } + } + +Triple Tagged +~~~~~~~~~~~~~ +.. code-block:: json + + { + "access": { + "interface": "eth1", + "outer-vlan-min": 10, + "outer-vlan-max": 20, + "inner-vlan-min": 128, + "inner-vlan-max": 4000, + "third-vlan": 7 + } + } + +The BNG Blaster supports also multiple access interfaces +or VLAN ranges as shown in the example below. + +.. code-block:: json + + { + "access": [ + { + "interface": "eth1", + "type": "pppoe", + "username": "pta@rtbrick.com", + "outer-vlan-min": 1000, + "outer-vlan-max": 1999, + "inner-vlan-min": 7, + "inner-vlan-max": 7 + }, + { + "interface": "eth1", + "type": "pppoe", + "username": "l2tp@rtbrick.com", + "outer-vlan-min": 2000, + "outer-vlan-max": 2999, + "inner-vlan-min": 7, + "inner-vlan-max": 7 + }, + { + "interface": "eth3", + "type": "pppoe", + "username": "test@rtbrick.com", + "outer-vlan-min": 128, + "outer-vlan-max": 4000, + "inner-vlan-min": 7, + "inner-vlan-max": 7 + }, + { + "interface": "eth4", + "type": "ipoe", + "outer-vlan-min": 8, + "outer-vlan-max": 9, + "address": "200.0.0.1", + "address-iter": "0.0.0.4", + "gateway": "200.0.0.2", + "gateway-iter": "0.0.0.4" + } + ] + } + + +The configuration attributes for username, agent-remote-id and agent-circuit-id +support also some variable substitution. The variable ``{session-global}`` will +be replaced with a number starting from 1 and incremented for every new session. +where as the variable ``{session}`` is incremented per interface section. + +In VLAN mode ``N:1`` only one VLAN combination is supported per access interface section. +This means that only VLAN min or max is considered as VLAN identifier. + +.. code-block:: json + + { + "access": [ + { + "interface": "eth1", + "type": "pppoe", + "vlan-mode": "N:1", + "username": "test@rtbrick.com", + "outer-vlan-min": 7 + }, + { + "interface": "eth2", + "type": "pppoe", + "vlan-mode": "N:1", + "username": "test@rtbrick.com", + "outer-vlan-min": 2000, + "inner-vlan-min": 7, + }, + ] + } + +A10NSP Interfaces +----------------- + +.. _a10nsp-interface: + +The A10NSP interface emulates an layer two provider interface. The term A10 +refers to the end-to-end ADSL network reference model from TR-025. + +The A10NSP interface is required for :ref:`L2BSA ` tests. + +.. include:: configuration/interfaces_a10nsp.rst + +The BNG Blaster supports multiple A10NSP interfaces +as shown in the example below. + +.. code-block:: json + + { + "interfaces": { + "tx-interval": 1, + "rx-interval": 1, + "a10nsp": [ + { + "interface": "eth4", + "qinq": true, + "mac": "02:00:00:ff:ff:01" + }, + { + "interface": "eth5", + "qinq": false, + "mac": "02:00:00:ff:ff:02" + } + ], + } + } + +You can define multiple interfaces with the same MAC +address to emulate some static link aggregation (without LACP). diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst new file mode 100644 index 00000000..eccce091 --- /dev/null +++ b/docs/source/quickstart.rst @@ -0,0 +1,353 @@ +Quickstart Guide +================ + +In this guide, we’ll walk you through the BNG Blaster basics. All the +examples here work without having network devices to be tested. + +First you need to :ref:`install ` the BNG Blaster on your machine. + +In the next step, you create a virtual ethernet interface pair that can be +used by the BNG Blaster to send and received traffic. + +.. code-block:: none + + sudo ip link add veth1.1 type veth peer name veth1.2 + sudo ip link set veth1.1 up + sudo ip link set veth1.2 up + +PPPoE +----- + +Let's start with a simple PPPoE setup where BNG Blaster emulates the +client and server. On the first interface we use an :ref:`A10NSP interface ` +which includes a lightweight PPPoE server. The other interface is +configured as PPPoE client. + +The configured :ref:`session traffic ` generates +bidirectional traffic between client and server. There is also +one more bound :ref:`traffic stream ` configured. + +**pppoe.json:** + +.. code-block:: json + + { + "interfaces": { + "a10nsp": [ + { + "__comment__": "PPPoE Server", + "interface": "veth1.1" + } + ], + "access": [ + { + "__comment__": "PPPoE", + "interface": "veth1.2", + "type": "pppoe", + "outer-vlan-min": 1, + "outer-vlan-max": 4000, + "inner-vlan": 7, + "stream-group-id": 1 + } + ] + }, + "pppoe": { + "reconnect": true + }, + "dhcpv6": { + "enable": false + }, + "session-traffic": { + "ipv4-pps": 1 + }, + "streams": [ + { + "stream-group-id": 1, + "name": "S1", + "type": "ipv4", + "direction": "both", + "priority": 128, + "length": 256, + "pps": 1, + "a10nsp-interface": "veth1.1" + } + ] + } + +Now you can start the BNG Blaster with this configuration. + +.. code-block:: none + + $ sudo bngblaster -C pppoe.json + Mar 30 14:27:59.303904 Resolve network interfaces + Mar 30 14:27:59.303952 All network interfaces resolved + Mar 30 14:27:59.396765 ALL SESSIONS ESTABLISHED + +After pressing ``ctrl+c`` the test should be stopped and a detailed +report printed. + +Let's advance the test by enabling some features explained below. + +.. code-block:: none + + $ sudo bngblaster -C pppoe.json -c 1 -L test.log -l ip -J report.json -j sessions -j streams -P test.pcap -S run.sock -I + +* ``-C test.json`` loads the configuration file +* ``-c 1`` defines how many sessions to be emulated, you can increase the number to see what happens... +* ``-L test.log`` creates an optional logging file +* ``-l ip`` enables the IP address logging +* ``-J report.json`` generates a final JSON report at the end +* ``-j sessions`` include detailed results for every session in the JSON report +* ``-j streams`` include detailed results for every stream in the JSON report +* ``-P test.pcap`` generates a PCAP file +* ``-S run.sock`` opens the JSON RPC API socket +* ``-I`` start interactive courses user interface + +.. image:: images/quickstart1.png + :alt: BNG Blaster Interactive + +Now let's try to press ``F1`` to navigate through the different views. All supported +keyboard inputs are listed in the top left corner. After pressing ``F9`` the test +should be stopped. + +If the test is still running, you can open a second terminal. Then go to the same +directory from where you started the BNG Blaster and enter the following command. + +.. code-block:: none + + $ sudo bngblaster-cli run.sock session-info session-id 1 | jq . + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "session-info": { + "type": "pppoe", + "session-id": 1, + "session-state": "Established", + "interface": "veth1.2", + "outer-vlan": 1, + "inner-vlan": 7, + "mac": "02:00:00:00:00:01", + "username": "user1@rtbrick.com", + "reply-message": "BNG-Blaster-A10NSP", + "lcp-state": "Opened", + "ipcp-state": "Opened", + "ip6cp-state": "Opened", + "ipv4-address": "10.10.10.10", + "ipv4-dns1": "10.12.12.10", + "ipv4-dns2": "10.13.13.10", + "dhcpv6-state": "Init", + "tx-packets": 87, + "rx-packets": 80, + "rx-fragmented-packets": 0, + "session-traffic": { + "total-flows": 2, + "verified-flows": 1, + "first-seq-rx-access-ipv4": 1, + "first-seq-rx-access-ipv6": 0, + "first-seq-rx-access-ipv6pd": 0, + "first-seq-rx-network-ipv4": 1, + "first-seq-rx-network-ipv6": 0, + "first-seq-rx-network-ipv6pd": 0, + "access-tx-session-packets": 34, + "access-rx-session-packets": 34, + "access-rx-session-packets-loss": 0, + "network-tx-session-packets": 34, + "network-rx-session-packets": 34, + "network-rx-session-packets-loss": 0, + "access-tx-session-packets-ipv6": 0, + "access-rx-session-packets-ipv6": 0, + "access-rx-session-packets-ipv6-loss": 0, + "network-tx-session-packets-ipv6": 0, + "network-rx-session-packets-ipv6": 0, + "network-rx-session-packets-ipv6-loss": 0, + "access-tx-session-packets-ipv6pd": 0, + "access-rx-session-packets-ipv6pd": 0, + "access-rx-session-packets-ipv6pd-loss": 0, + "network-tx-session-packets-ipv6pd": 0, + "network-rx-session-packets-ipv6pd": 0, + "network-rx-session-packets-ipv6pd-loss": 0 + }, + "a10nsp": { + "interface": "veth1.1", + "s-vlan": 1, + "qinq-send": false, + "qinq-received": false, + "tx-packets": 46, + "rx-packets": 87 + } + } + } + +You can also try other :ref:`commands ` to get familiar with the API. + +After the test has stopped, you can also check the final JSON report (``jq . report.json``), +log, and PCAP files. + +ISIS +---- + +In the following example, we create two :ref:`ISIS ` nodes (R1 and R2) with an emulated +ISIS topology attached to R1 (`test.mrt``). + +**isis.json:** + +.. code-block:: json + + { + "interfaces": { + "network": [ + { + "interface": "veth1.1", + "address": "10.0.0.1/24", + "gateway": "10.0.0.2", + "address-ipv6": "fc66:1337:7331::1/64", + "gateway-ipv6": "fc66:1337:7331::2", + "isis-instance-id": 1, + "isis-level": 1 + }, + { + "interface": "veth1.2", + "address": "10.0.0.2/24", + "gateway": "10.0.0.1", + "address-ipv6": "fc66:1337:7331::2/64", + "gateway-ipv6": "fc66:1337:7331::1", + "isis-instance-id": 2, + "isis-level": 1 + } + ] + + }, + "isis": [ + { + "instance-id": 1, + "area": [ + "49.0001/24", + "49.0002/24" + ], + "system-id": "1921.6800.1001", + "router-id": "192.168.1.1", + "hostname": "R1", + "sr-base": 1000, + "sr-range": 100, + "sr-node-sid": 1, + "level1-auth-key": "secret123", + "level1-auth-type": "md5", + "external": { + "mrt-file": "test.mrt", + "connections": [ + { + "system-id": "1921.6800.0000.00", + "l1-metric": 1000, + "l2-metric": 2000 + } + ] + } + }, + { + "instance-id": 2, + "area": [ + "49.0001/24", + "49.0002/24" + ], + "system-id": "1921.6800.1002", + "router-id": "192.168.1.2", + "hostname": "R2", + "sr-base": 1000, + "sr-range": 100, + "sr-node-sid": 2, + "level1-auth-key": "secret123", + "level1-auth-type": "md5" + } + ], + "streams": [ + { + "name": "RAW1", + "type": "ipv4", + "direction": "downstream", + "priority": 128, + "destination-ipv4-address": "192.168.1.2", + "length": 256, + "pps": 1, + "network-interface": "veth1.1" + } + ] + } + +Now use the included tool ``lspgen`` to generate the attached ISIS topology. + +.. code-block:: none + + $ lspgen -a 49.0001/24 -K secret123 -T md5 -C 1921.6800.1001 -m test.mrt + Mar 30 14:54:19.647569 Add context for instance default, protocol isis, topology unicast + Mar 30 14:54:19.647630 Add connector to 0x192168001001 + Mar 30 14:54:19.647633 LSP generation parameters + Mar 30 14:54:19.647639 Area 49.0001/24 + Mar 30 14:54:19.647642 Level 1, sequence 0x1, lsp-lifetime 65535 + Mar 30 14:54:19.647645 Authentication-key secret123, Authentication-type md5 + Mar 30 14:54:19.647648 IPv4 Node Base Prefix 192.168.0.0/32 + Mar 30 14:54:19.647651 IPv4 Link Base Prefix 172.16.0.0/31 + Mar 30 14:54:19.647654 IPv4 External Base Prefix 10.0.0.0/28 + Mar 30 14:54:19.647657 IPv6 Node Base Prefix fc00::c0a8:0/128 + Mar 30 14:54:19.647660 IPv6 Link Base Prefix fc00::ac10:0/127 + Mar 30 14:54:19.647669 IPv6 External Base Prefix fc00::a00:0/124 + Mar 30 14:54:19.647672 SRGB base 10000, range 2000 + Mar 30 14:54:19.647678 Generating a graph of 10 nodes and 20 links + Mar 30 14:54:19.647813 Root node 1921.6800.0000.00 + +Finally, you can start the BNG Blaster. + +.. code-block:: none + + $ sudo bngblaster -C veth1-isis.json -l isis -P test.pcap -S run.sock + Mar 30 14:56:11.981279 Init IS-IS instance 1 + Mar 30 14:56:11.981314 Load ISIS MRT file test.mrt + Mar 30 14:56:11.981335 Init IS-IS instance 2 + Mar 30 14:56:12.031917 Add network interface veth1.1 to IS-IS instance 1 + Mar 30 14:56:12.087877 Add network interface veth1.2 to IS-IS instance 2 + Mar 30 14:56:12.087971 opened pcap-file test.pcap + Mar 30 14:56:12.088013 Opened control socket run.sock + Mar 30 14:56:13.088035 Resolve network interfaces + Mar 30 14:56:13.088050 All network interfaces resolved + Mar 30 14:56:22.093906 ISIS L1 adjacency UP on interface veth1.2 + Mar 30 14:56:22.093964 ISIS L1 adjacency UP on interface veth1.1 + +If the test is still running, you can open a second terminal, go to the same directory +from where you started the BNG Blaster and enter the following command. + +.. code-block:: none + + $ sudo bngblaster-cli run.sock isis-adjacencies + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "isis-adjacencies": [ + { + "interface": "veth1.1", + "type": "P2P", + "level": "L1", + "instance-id": 1, + "adjacency-state": "Up", + "peer": { + "system-id": "1921.6800.1002" + } + }, + { + "interface": "veth1.2", + "type": "P2P", + "level": "L1", + "instance-id": 2, + "adjacency-state": "Up", + "peer": { + "system-id": "1921.6800.1001" + } + } + ] + } + +You can also try other :ref:`commands ` to get familiar with the API. \ No newline at end of file diff --git a/docs/source/reference/architecture.rst b/docs/source/reference/architecture.rst new file mode 100644 index 00000000..26b87ce3 --- /dev/null +++ b/docs/source/reference/architecture.rst @@ -0,0 +1,52 @@ +Architecture +------------ + +The BNG Blaster has been completely built from scratch in **C**. This includes user-space implementations +of the entire protocol stack. Its core is based on a very simple event loop that serves timers and +signals. The timers have been built using a lightweight constant time (*O(1)*) library. The timer library +was built to start, restart and delete the protocol session FSM timers quickly and at scale. + +The BNG Blaster expects a Linux kernel network interface which is up, but not configured with any IP addresses +or VLAN as it expects to receive and transmit RAW ethernet packets. + +The BNG Blaster does I/O using high-speed polling timers with a mix of Linux +`RAW Packet Sockets `_ and +`Packet MMAP `_. + +The second one is a so-called PACKET_RX_RING/PACKET_TX_RING abstraction where a user-space program gets a fast +lane into reading and writing to kernel interfaces using a shared ring buffer. The shared ring buffer is a +memory-mapped “window” shared between kernel and userspace. This low overhead abstraction allows to transmit +and receive traffic without doing expensive system calls. Sending and transmitting traffic via Packet MMAP is +as easy as copying a packet into a buffer and setting a flag. + +.. image:: ../images/bbl_arch.png + :alt: BNG Blaster Architecture + +The BNG Blaster supports many configurable I/O modes listed with ``bngblaster -v`` but except for the default +mode ``packet_mmap_raw`` all other modes are currently considered experimental. In the default mode, all +packets are received in a Packet MMAP ring buffer and sent through RAW packet sockets. This combination +was the most efficient in our benchmark tests. + +BNG Blaster's primary design goal is to simulate thousands of subscriber CPE’s with a small hardware resource +footprint. Simple to use and easy to integrate into our robot test automation infrastructure. This allows for +simulation of massive PPPoE or IPoE (DHCP) subscribers including IPTV, traffic verification, and convergence +testing from a single medium scale virtual machine or to run from a laptop. + +The BNG Blaster provides three types of interfaces. The first interface is called the access interface which +emulates the PPPoE or IPoE sessions. The second interface-type is called network interface. This is used for +emulating the core-facing side of the internet with optional routing protocols. The last type is called a10nsp +interface which emulates an layer two provider interface. The term A10 refers to the end-to-end ADSL network +reference model from TR-025. + +.. image:: ../images/bbl_interfaces.png + :alt: BNG Blaster Interfaces + +This allows for verification of IP reachability by sending bidirectional traffic between all sessions +on the access interface and the network interface. The network interface is also used to inject downstream +multicast test traffic for IPTV tests. It is also possible to send RAW traffic streams between network +interfaces without any access interface defined for non-BNG testing. + +One popular example for non-BNG tests with the BNG Blaster is the verification of a BGP full-table by injecting +around 1M prefixes and setting up traffic streams for all prefixes with at least 1 PPS (1M PPS). +The BNG Blaster is able to verify and analyze every single flow with detailed per-flow statistics +(receive rate, loss, latency, …). \ No newline at end of file diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst new file mode 100644 index 00000000..ae08285e --- /dev/null +++ b/docs/source/reference/index.rst @@ -0,0 +1,8 @@ +Reference +========= + +.. toctree:: + :maxdepth: 1 + + architecture.rst + traffic.rst diff --git a/docs/source/reference/traffic.rst b/docs/source/reference/traffic.rst new file mode 100644 index 00000000..bbad0fa6 --- /dev/null +++ b/docs/source/reference/traffic.rst @@ -0,0 +1,139 @@ +BNG Blaster Traffic +------------------- + +.. _bbl_header: + +Blaster Header and Fast Decode Signature +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The 48 Byte fixed size BNG Blaster Header is added to all data packets +for traffic validation and fast decoding. The header is expected on the +last 48 bytes of the packet. + +The type is set to 1 for all unicast session traffic and 2 for +IPv4 multicast traffic. + +Unicast Session Traffic +^^^^^^^^^^^^^^^^^^^^^^^ + +The 64 bit session key is used for all traffic from access (upstream) +and to access (downstream) interfaces to identify the corresponding +session which has send or should receive the packet. + +.. code-block:: none + + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | BNG Blaster Magic Sequence | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Sub-Type | Direction | TX TOS | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Session Identifier | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Session Access Interface Index | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Session Outer VLAN | Session Inner VLAN | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Flow Identifier | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Flow Sequence Number | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Nanosecond Send Timestamp | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +.. image:: ../images/bbl_header.png + :alt: BNG Blaster Header + +Multicast Traffic +^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | BNG Blaster Magic Sequence | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Sub-Type | Direction | TX TOS | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Group | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Flow Identifier | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Flow Sequence Number | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Nanosecond Send Timestamp | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +.. note:: + All attributes except IP addresses in the Blaster Header are + stored in host byte order for faster processing + (LE or BE depending on test system). + +BNG Blaster Magic Sequence +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The 64 bit magic sequence is the word ``RtBrick!`` decoded as ASCII: + +.. code-block:: none + + 0x5274427269636b21 + +The magic number allows to check for it on a given offset and process +only blaster header instead of decoding the whole packet for faster +packet processing. + +Flow Identifier +^^^^^^^^^^^^^^^ + +The 64 bit flow identifier is a global unique number which identifies +the flow. + +Flow Sequence Number +^^^^^^^^^^^^^^^^^^^^ + +The 64 bit flow sequence number is sequential number starting with 1 +and incremented per packet primary used to identity packet loss. + +This number 0 means that sequencing is disabled. + +Nanosecond Send Timestamps +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The 64 bit nanoseconds send timestamp is used for optional latency and +jitter calculations. + +.. code-block:: none + + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Seconds | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Nano Seconds | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +The timestamp 0 means that timestamps are disabled. + +Wireshark Plugin +~~~~~~~~~~~~~~~~ +**Wireshark BNG Blaster Header Dissector** + +Download the LUA dissector script +`bbl_header.lua `_ +and start wireshark as shown below from the directory where the script is placed. + +.. code-block:: none + + $ wireshark -X lua_script:bbl_header.lua + diff --git a/docs/source/reports.rst b/docs/source/reports.rst new file mode 100644 index 00000000..7e9b72e6 --- /dev/null +++ b/docs/source/reports.rst @@ -0,0 +1,265 @@ +Reports +======= + +The BNG Blaster is able to generate detailed result reports +at the end of of the test execution. + +Standard Output Reports +----------------------- + +.. code-block:: none + + ____ __ ____ _ __ ,/ + / __ \ / /_ / __ ) _____ (_)_____ / /__ ,'/ + / /_/ // __// __ |/ ___// // ___// //_/ ,' / + / _, _// /_ / /_/ // / / // /__ / ,< ,' /_____, + /_/ |_| \__//_____//_/ /_/ \___//_/|_| .'____ ,' + ____ _ _ ______ ____ _ _ / ,' + / __ ) / | / // ____/ / __ ) / /____ _ _____ / /_ ___ ____ / ,' + / __ |/ |/ // / __ / __ |/ // __ `// ___// __// _ \ / ___/ /,' + / /_/ // /| // /_/ / / /_/ // // /_/ /(__ )/ /_ / __// / / + /_____//_/ |_/ \____/ /_____//_/ \__,_//____/ \__/ \___//_/ + + Report: + + Sessions PPPoE: 500 IPoE: 0 + Sessions established: 500/500 + DHCPv6 sessions established: 500 + Setup Time: 396 ms + Setup Rate: 1262.63 CPS (MIN: 1262.63 AVG: 1262.63 MAX: 1262.63) + Flapped: 0 + + Network Interface ( eth2 ): + TX: 25503 packets + RX: 24254 packets + TX Session: 8500 packets + RX Session: 8248 packets (0 loss) + TX Session IPv6: 8500 packets + RX Session IPv6: 8000 packets (0 loss) + TX Session IPv6PD: 8500 packets + RX Session IPv6PD: 8000 packets (0 loss) + TX Multicast: 0 packets + RX Drop Unknown: 1 packets + TX Encode Error: 0 + RX Decode Error: 0 packets + TX Send Failed: 0 + TX No Buffer: 0 + TX Poll Kernel: 0 + RX Poll Kernel: 3932 + + Access Interface ( eth1 ): + TX: 33250 packets + RX: 34047 packets + TX Session: 8500 packets + RX Session: 8248 packets (0 loss, 0 wrong session) + TX Session IPv6: 8500 packets + RX Session IPv6: 8000 packets (0 loss, 0 wrong session) + TX Session IPv6PD: 8500 packets + RX Session IPv6PD: 8000 packets (0 loss, 0 wrong session) + RX Multicast: 0 packets (0 loss) + RX Drop Unknown: 1 packets + TX Encode Error: 33250 packets + RX Decode Error: 0 packets + TX Send Failed: 0 + TX No Buffer: 0 + TX Poll Kernel: 0 + RX Poll Kernel: 3932 + + Access Interface Protocol Packet Stats: + ARP TX: 0 RX: 0 + PADI TX: 500 RX: 0 + PADO TX: 0 RX: 500 + PADR TX: 500 RX: 0 + PADS TX: 0 RX: 500 + PADT TX: 1 RX: 499 + LCP TX: 2249 RX: 2249 + PAP TX: 250 RX: 250 + CHAP TX: 250 RX: 500 + IPCP TX: 1500 RX: 1500 + IP6CP TX: 1500 RX: 1500 + IGMP TX: 0 RX: 1298 + ICMP TX: 0 RX: 0 + ICMPv6 TX: 500 RX: 500 + DHCPv6 TX: 500 RX: 500 + + Access Interface Protocol Timeout Stats: + LCP Echo Request: 0 + LCP Request: 0 + IPCP Request: 0 + IP6CP Request: 0 + PAP: 0 + CHAP: 0 + ICMPv6 RS: 0 + DHCPv6 Request: 0 + + Session Traffic: + Config: + IPv4 PPS: 1 + IPv6 PPS: 1 + IPv6PD PPS: 1 + Verified Traffic Flows: 3000/3000 + Access IPv4: 500 + Access IPv6: 500 + Access IPv6PD: 500 + Network IPv4: 500 + Network IPv6: 500 + Network IPv6PD: 500 + First Sequence Number Received: + Access IPv4 MIN: 1 ( 1.000s) MAX: 2 ( 2.000s) + Access IPv6 MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) + Access IPv6PD MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) + Network IPv4 MIN: 1 ( 1.000s) MAX: 2 ( 2.000s) + Network IPv6 MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) + Network IPv6PD MIN: 2 ( 2.000s) MAX: 2 ( 2.000s) + + +JSON Reports +------------ + +A detailed JSON report is generated if enabled using the optional +argument ``-J `` as shown in the example below. + +.. code-block:: json + + { + "report": { + "sessions": 500, + "sessions-pppoe": 500, + "sessions-ipoe": 0, + "sessions-established": 500, + "sessions-flapped": 0, + "setup-time-ms": 396, + "setup-rate-cps": 1263, + "setup-rate-cps-min": 1263, + "setup-rate-cps-avg": 1263, + "setup-rate-cps-max": 1263, + "dhcpv6-sessions-established": 500, + "network-interfaces": [ + { + "name": "eth2", + "tx-packets": 25503, + "rx-packets": 24254, + "tx-session-packets": 8500, + "rx-session-packets": 8248, + "rx-session-packets-loss": 0, + "tx-session-packets-avg-pps-max": 500, + "rx-session-packets-avg-pps-max": 500, + "tx-session-packets-ipv6": 8500, + "rx-session-packets-ipv6": 8000, + "rx-session-packets-ipv6-loss": 0, + "tx-session-packets-avg-pps-max-ipv6": 500, + "rx-session-packets-avg-pps-max-ipv6": 500, + "tx-session-packets-ipv6pd": 8500, + "rx-session-packets-ipv6pd": 8000, + "rx-session-packets-ipv6pd-loss": 0, + "tx-session-packets-avg-pps-max-ipv6pd": 500, + "rx-session-packets-avg-pps-max-ipv6pd": 500, + "tx-multicast-packets": 0 + } + ], + "access-interfaces": [ + { + "name": "eth1", + "tx-packets": 33250, + "rx-packets": 34047, + "tx-session-packets": 8500, + "rx-session-packets": 8248, + "rx-session-packets-loss": 0, + "rx-session-packets-wrong-session": 0, + "tx-session-packets-avg-pps-max": 500, + "rx-session-packets-avg-pps-max": 500, + "tx-session-packets-ipv6": 8500, + "rx-session-packets-ipv6": 8000, + "rx-session-packets-ipv6-loss": 0, + "rx-session-packets-ipv6-wrong-session": 0, + "tx-session-packets-avg-pps-max-ipv6": 500, + "rx-session-packets-avg-pps-max-ipv6": 500, + "tx-session-packets-ipv6pd": 8500, + "rx-session-packets-ipv6pd": 8000, + "rx-session-packets-ipv6pd-loss": 0, + "rx-session-packets-ipv6pd-wrong-session": 0, + "tx-session-packets-avg-pps-max-ipv6pd": 500, + "rx-session-packets-avg-pps-max-ipv6pd": 500, + "rx-multicast-packets": 0, + "rx-multicast-packets-loss": 0, + "protocol-stats": { + "arp-tx": 0, + "arp-rx": 0, + "padi-tx": 500, + "pado-rx": 500, + "padr-tx": 500, + "pads-rx": 500, + "padt-tx": 1, + "padt-rx": 499, + "lcp-tx": 2249, + "lcp-rx": 2249, + "pap-tx": 250, + "pap-rx": 250, + "chap-tx": 250, + "chap-rx": 500, + "ipcp-tx": 1500, + "ipcp-rx": 1500, + "ip6cp-tx": 1500, + "ip6cp-rx": 1500, + "igmp-tx": 0, + "igmp-rx": 1298, + "icmp-tx": 0, + "icmp-rx": 0, + "icmpv6-tx": 500, + "icmpv6-rx": 500, + "dhcpv6-tx": 500, + "dhcpv6-rx": 500, + "lcp-echo-timeout": 0, + "lcp-request-timeout": 0, + "ipcp-request-timeout": 0, + "ip6cp-request-timeout": 0, + "pap-timeout": 0, + "chap-timeout": 0, + "icmpv6-rs-timeout": 0, + "dhcpv6-timeout": 0 + } + ], + "session-traffic": { + "config-ipv4-pps": 1, + "config-ipv6-pps": 1, + "config-ipv6pd-pps": 1, + "total-flows": 3000, + "verified-flows": 3000, + "verified-flows-access-ipv4": 500, + "verified-flows-access-ipv6": 500, + "verified-flows-access-ipv6pd": 500, + "verified-flows-network-ipv4": 500, + "verified-flows-network-ipv6": 500, + "verified-flows-network-ipv6pd": 500, + "first-seq-rx-access-ipv4-min": 1, + "first-seq-rx-access-ipv4-max": 2, + "first-seq-rx-access-ipv6-min": 2, + "first-seq-rx-access-ipv6-max": 2, + "first-seq-rx-access-ipv6pd-min": 2, + "first-seq-rx-access-ipv6pd-max": 2, + "first-seq-rx-network-ipv4-min": 1, + "first-seq-rx-network-ipv4-max": 2, + "first-seq-rx-network-ipv6-min": 2, + "first-seq-rx-network-ipv6-max": 2, + "first-seq-rx-network-ipv6pd-min": 2, + "first-seq-rx-network-ipv6pd-max": 2 + } + } + } + +The optional argument ``-j sessions`` allows to include per session statistics +in the report file. Similar with ``-j streams`` which allows to include per stream +statistics. Both options could be also combined. + +Those extensive JSON reports could be easily verified with simple python scripts to +extract the desired results. + +.. code-block:: python + + #!/usr/bin/env python3 + import json + + # Open JSON report ... + with open('report.json') as f: + data = json.load(f) + # Analyze data ... \ No newline at end of file diff --git a/docs/source/routing/bgp.rst b/docs/source/routing/bgp.rst new file mode 100644 index 00000000..49f09b17 --- /dev/null +++ b/docs/source/routing/bgp.rst @@ -0,0 +1,184 @@ +.. _bgp: + +BGP +--- + +The Border Gateway Protocol (BGP) is a standardized exterior gateway protocol +designed to exchange routing and reachability information among autonomous systems +(AS) on the internet. BGP is classified as a path-vector routing protocol, and it +makes routing decisions based on paths, network policies, or rule-sets configured +by a network operator. + +Configuration +~~~~~~~~~~~~~ + +Following an example BGP configuration with one session. + +.. code-block:: json + + { + "interfaces": { + "network": [ + { + "interface": "eth1", + "address": "10.0.1.2/24", + "gateway": "10.0.1.1" + } + ] + }, + "bgp": [ + { + "local-ipv4-address": "10.0.1.2", + "peer-ipv4-address": "10.0.1.1", + "raw-update-file": "test.bgp", + "local-as": 65001, + "peer-as": 65001 + } + ] + } + +.. include:: ../configuration/bgp.rst + + +BGP Sessions +~~~~~~~~~~~~ + +Every BGP session is opened with the capabilities for the following +address families: + ++ IPv4 unicast ++ IPv4 labelled unicast ++ IPv6 unicast ++ IPv6 labelled unicast + +Limitations +~~~~~~~~~~~ + +BGP authentication is currently not supported but already +planned as enhancement in one of the next releases. + +RAW Update Files +~~~~~~~~~~~~~~~~ + +The BNG Blaster is able to inject BGP messages from a pre-compiled +RAW update file into the defined sessions. A RAW update file is not +more than a pre-compiled binary stream of BGP messages, typically +but not limited to update messages. + +.. code-block:: none + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + + + + | | + + + + | Marker | + + + + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Length | Type | ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++++ + . + . + . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + + + + | | + + + + | Marker | + + + + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Length | Type | ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++++ + +Those files can be created using the included BGP RAW update generator +script ``bgpupdate`` or manually using libraries like scapy or converters +from PCAP or MRT files. + +The configured ``raw-update-file`` under the BGP session is loaded +during Blaster startup phase and send as soon as the session is +established. + +The ``bgp-raw-update`` command allows to send further updates during +the session lifetime. + +``$ sudo bngblaster-cli run.sock bgp-raw-update file update1.bgp`` + +This allows in example to load a full table after session has +started and manually trigger a series of changes using incremental +updates files. + +All BGP RAW update files are loaded once and can than be used by +multiple sessions. Meaning if two or more sessions reference the +same file identified by file name, this file is loaded once into +memory and used by multiple sessions. + +Therefore for incremental updates, it may makes sense to pre-load +via ``bgp-raw-update-files`` configuration. + +.. code-block:: json + + { + "bgp": [ + { + "local-ipv4-address": "10.0.1.2", + "peer-ipv4-address": "10.0.1.1", + "raw-update-file": "start.bgp", + "local-as": 65001, + "peer-as": 65001 + } + ], + "bgp-raw-update-files": [ + "update1.bgp", + "update2.bgp" + ] + } + +Incremental updates not listed here will be loaded dynamically as soon +as referenced by first session. + +BGP RAW Update Generator +~~~~~~~~~~~~~~~~~~~~~~~~ + +The BGP RAW update generator is a simple tool to generate BGP RAW update +streams for use with the BNG Blaster. + +.. code-block:: none + + $ bgpupdate --help + usage: bgpupdate [-h] [-a ASN] -n ADDRESS [-N N] -p PREFIX [-P N] [-m LABEL] + [-M N] [-l LOCAL_PREF] [-f FILE] [-w] [--end-of-rib] + [--append] [--pcap FILE] [--log-level {warning,info,debug}] + + optional arguments: + -h, --help show this help message and exit + -a ASN, --asn ASN autonomous system number + -n ADDRESS, --next-hop-base ADDRESS + next-hop base address (IPv4 or IPv6) + -N N, --next-hop-num N + next-hop count + -p PREFIX, --prefix-base PREFIX + prefix base network (IPv4 or IPv6) + -P N, --prefix-num N prefix count + -m LABEL, --label-base LABEL + label base + -M N, --label-num N label count + -l LOCAL_PREF, --local-pref LOCAL_PREF + local preference + -f FILE, --file FILE output file + -w, --withdraw withdraw prefixes + --end-of-rib add end-of-rib message + --append append to file if exist + --pcap FILE write BGP updates to PCAP file + --log-level {warning,info,debug} + logging Level + + +The python BGP RAW update generator is a python script which uses +scapy to build BGP messages. Therefore this tool can be easily +modified, extend or used as blueprint for your own tools to generate +valid BGP update streams. diff --git a/docs/source/routing/index.rst b/docs/source/routing/index.rst new file mode 100644 index 00000000..bfc7e839 --- /dev/null +++ b/docs/source/routing/index.rst @@ -0,0 +1,13 @@ +Routing Protocols +================= + +There are various routing protocols supported like ISIS and BGP. +So you can use the BNG Blaster for end-to-end BNG and non-BNG +router testing. + +.. toctree:: + :maxdepth: 1 + + isis.rst + bgp.rst + mpls.rst diff --git a/docs/source/routing/isis.rst b/docs/source/routing/isis.rst new file mode 100644 index 00000000..0ce11ac9 --- /dev/null +++ b/docs/source/routing/isis.rst @@ -0,0 +1,359 @@ +.. _isis: + +ISIS +---- + +Intermediate System to Intermediate System (ISIS, also written IS-IS) +is a routing protocol designed to move information efficiently within +a network. + +The ISIS protocol is defined in ISO/IEC 10589:2002 as an international +standard within the Open Systems Interconnection (OSI) reference design. +The Internet Engineering Task Force (IETF) republished ISIS in RFC 1142, +but that RFC was later marked as historic by RFC 7142 because it republished +a draft rather than a final version of the ISO standard, causing confusion. + +ISIS has been called the de facto standard for large service provider +network backbones. + +The BNG Blaster is able to emulate multiple ISIS instances. An ISIS instance +is a virtual ISIS node with one or more network interfaces attached. Such a +node behaves like a "real router" including database synchronization and +flooding. Every instance generates a ``self`` originated LSP describing the +node itself. + +Configuration +~~~~~~~~~~~~~ + +Following an example ISIS configuration with one instance +attached to two network interfaces. + +.. code-block:: json + + { + "interfaces": { + "network": [ + { + "interface": "eth1", + "address": "10.0.1.2/24", + "gateway": "10.0.1.1", + "address-ipv6": "fc66:1337:7331:1::2/64", + "gateway-ipv6": "fc66:1337:7331:1::1", + "isis-instance-id": 1, + "isis-level": 1, + "isis-l1-metric": 100, + }, + { + "interface": "eth2", + "address": "10.0.2.2/24", + "gateway": "10.0.2.1", + "address-ipv6": "fc66:1337:7331:2::2/64", + "gateway-ipv6": "fc66:1337:7331:2::1", + "isis-instance-id": 1 + } + ] + }, + "isis": [ + { + "instance-id": 1, + "system-id": "0100.1001.0010", + "router-id": "10.10.10.10", + "hostname": "R1", + "area": [ + "49.0001/24", + "49.0002/24" + ], + "hello-padding": true, + "lsp-lifetime": 65535, + "level1-auth-key": "secret", + "level1-auth-type": "md5", + "sr-base": 2000, + "sr-range": 3600 + } + ] + } + +.. include:: ../configuration/isis.rst + +The support for multiple instances allows different use cases. One example might +be to create two instances connected to the device or network under test. Now +inject a LSP on one instance and check if learned over the tested network on +the other instance. + +Every ISIS instance can be also connected to an emulated link state graph loaded +by MRT files as shown in the example below. + +.. image:: ../images/bbl_isis.png + :alt: ISIS + +.. code-block:: json + + { + "isis": [ + { + "instance-id": 1, + "system-id": "0100.1001.0011", + "router-id": "10.10.10.11", + "hostname": "B1", + "external": { + "mrt-file": "test.mrt", + "connections": [ + { + "system-id": "0000.0000.0001", + "l1-metric": 1000, + "l2-metric": 2000 + } + ] + } + }, + { + "instance-id": 1, + "system-id": "0100.1001.0011", + "router-id": "10.10.10.12", + "hostname": "B2" + } + ] + } + +.. include:: ../configuration/isis_external.rst + +The The node ``N1`` in this example also needs to advertise the +reachability to the node ``B1``. + +.. include:: ../configuration/isis_external_connections.rst + + +Adjacencies +~~~~~~~~~~~ + +The BNG Blaster supports P2P adjacencies with 3-way-handshake only. + +``$ sudo bngblaster-cli run.sock isis-adjacencies`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "isis-adjacencies": [ + { + "interface": "eth1", + "type": "P2P", + "level": "L1", + "instance-id": 2, + "adjacency-state": "Up", + "peer": { + "system-id": "0100.1001.0022" + } + }, + { + "interface": "eth2", + "type": "P2P", + "level": "L1", + "instance-id": 1, + "adjacency-state": "Up", + "peer": { + "system-id": "0100.1001.0021" + } + } + ] + } + +Database +~~~~~~~~ + +The BNG Blaster distinguishes between three different source types of +LSP entries in the ISIS database. + +The type ``self`` is used for the self originated LSP describing the own +BNG Blaster ISIS instance. LSP entries of type ``adjacency`` are learned +via ISIS adjacencies. The type ``external`` is used for those LSP entries +learned via MRT files or injected via ``isis-lsp-update`` command. + +``$ sudo bngblaster-cli run.sock isis-database instance 1 level 1`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "isis-database": [ + { + "id": "0000.0000.0001.00-00", + "seq": 1, + "lifetime": 65535, + "lifetime-remaining": 65529, + "source-type": "external" + }, + { + "id": "0100.1001.0011.00-00", + "seq": 2, + "lifetime": 65535, + "lifetime-remaining": 65507, + "source-type": "self" + }, + { + "id": "0100.1001.0021.00-00", + "seq": 2, + "lifetime": 65524, + "lifetime-remaining": 65506, + "source-type": "adjacency", + "source-system-id": "0100.1001.0021" + }, + { + "id": "0100.1001.0022.00-00", + "seq": 2, + "lifetime": 65524, + "lifetime-remaining": 65506, + "source-type": "adjacency", + "source-system-id": "0100.1001.0021" + } + ] + } + +The BNG Blaster automatically purges all LSP's of type +``self`` and ``external`` during teardown. This is done by +generating LSP's with a newer sequence numbers and lifetime +of 30 seconds only. This lifetime is enough to flood the purge +LSP over te whole network under test. + +Flooding +~~~~~~~~ + +The BNG Blaster floods LSP's received to all other active +adjacencies of the ISIS instance except to those with peer +system-id equal to the source system-id of the LSP. + +Limitations +~~~~~~~~~~~ + +Currently only ISIS P2P links are supported. There is also +no support for route leaking between levels. + +MRT Files +~~~~~~~~~ + +The BNG Blaster is able to load LSP's from a MRT file as defined in +[RFC6396](https://datatracker.ietf.org/doc/html/rfc6396). + +.. code-block:: none + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Subtype | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Message... (variable) + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +The message field contains the complete ISIS LSP PDU including +the ISIS common header starting with ``0x83``. + +Those files can be loaded at startup via configuration option +``"isis": { "external": { "mrt-file": "" } }`` or alternative +via ``isis-load-mrt`` command. + +``$ sudo bngblaster-cli run.sock isis-load-mrt file test.mrt instance 1`` + +LSP Update Command +~~~~~~~~~~~~~~~~~~ + +It is also possible to inject external LSP's using the ``isis-lsp-update`` +command. + +The command expects a list of hex encoded PDU's including +the ISIS common header starting with ``0x83``, + +``$ cat command.json | jq .`` + +.. code-block:: json + + { + "command": "isis-lsp-update", + "arguments": { + "instance": 1, + "pdu": [ + "831b0100120100000021ffff010203040506000000000003c0d103010403490001", + "831b0100120100000021ffff010203040506000100000003bad603010403490001" + ] + } + } + +LSPGEN +~~~~~~ + +The BNG Blaster includes a tool called ```lspgen`` which is able to generate +link state packets and topologies for export as MRT and PCAP files or directly +injected via BNG Blaster LSP update command. + +LSP Update via Scapy +~~~~~~~~~~~~~~~~~~~~ + +The following example shows how to generate LSP's via Scapy +and inject them using the ``isis-lsp-update`` command. + +.. code-block:: python + + import sys + import socket + import os + import json + + from scapy.contrib.isis import * + + def error(*args, **kwargs): + """print error and exit""" + print(*args, file=sys.stderr, **kwargs) + sys.exit(1) + + + def execute_command(socket_path, request): + if os.path.exists(socket_path): + client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + client.connect(socket_path) + client.send(json.dumps(request).encode('utf-8')) + data = "" + while True: + junk = client.recv(1024) + if junk: + data += junk.decode('utf-8') + else: + break + print(json.dumps(json.loads(data), indent=4)) + except Exception as e: + error(e) + finally: + client.close() + else: + error("socket %s not found" % socket_path) + + + def main(): + """main function""" + socket_path = sys.argv[1] + + command = { + "command": "isis-lsp-update", + "arguments": { + "instance": 1, + "pdu": [] + } + } + + tlvs = ISIS_AreaTlv(areas=ISIS_AreaEntry(areaid='49.0001')) + pdu = ISIS_CommonHdr()/ISIS_L1_LSP(lifetime=65535, lspid='0102.0304.0506.00-00', seqnum=3, tlvs=tlvs) + command["arguments"]["pdu"].append(pdu.build().hex()) + + pdu = ISIS_CommonHdr()/ISIS_L1_LSP(lifetime=65535, lspid='0102.0304.0506.00-01', seqnum=3, tlvs=tlvs) + command["arguments"]["pdu"].append(pdu.build().hex()) + + execute_command(socket_path, command) + + + if __name__ == "__main__": + main() diff --git a/docs/source/routing/mpls.rst b/docs/source/routing/mpls.rst new file mode 100644 index 00000000..6e2c9a7d --- /dev/null +++ b/docs/source/routing/mpls.rst @@ -0,0 +1,3 @@ +MPLS +---- + diff --git a/docs/source/streams.rst b/docs/source/streams.rst new file mode 100644 index 00000000..b4f5c1b7 --- /dev/null +++ b/docs/source/streams.rst @@ -0,0 +1,350 @@ +.. _streams: + +Traffic Streams +=============== + +Traffic streams allow doing various forwarding verification +and QoS tests using BNG Blaster. + +.. image:: images/bbl_streams.png + :alt: Interactive Streams + +Traffic streams are be divided in bounded and raw streams. +The first one is bound to an access configuration and derives +addresses dynamically from the sessions. + +A raw stream is supported on :ref:`network interfaces ` only. + +Configuration +~~~~~~~~~~~~~ + +Following a simple PPPoE example with streams. + +.. code-block:: json + + { + "interfaces": { + "network": { + "interface": "eth2", + "address": "10.0.0.1/24", + "gateway": "10.0.0.2", + "address-ipv6": "fc66:1337:7331::1/64", + "gateway-ipv6": "fc66:1337:7331::2" + }, + "access": [ + { + "interface": "eth1", + "outer-vlan-min": 1001, + "outer-vlan-max": 2000, + "inner-vlan-min": 7, + "inner-vlan-max": 7, + "type": "pppoe", + "stream-group-id": 1 + }, + { + "interface": "eth1", + "outer-vlan-min": 2001, + "outer-vlan-max": 4000, + "inner-vlan": 7, + "type": "pppoe", + "stream-group-id": 2 + } + ] + }, + "streams": [ + { + "name": "BestEffort", + "stream-group-id": 1, + "type": "ipv4", + "direction": "both", + "pps": 1000 + }, + { + "name": "Voice", + "stream-group-id": 1, + "type": "ipv4", + "direction": "downstream", + "priority": 128, + "vlan-priority": 2, + "network-ipv4-address": "10.0.0.10", + "pps": 100 + }, + { + "name": "BestEffort", + "stream-group-id": 2, + "type": "ipv4", + "direction": "both", + "pps": 1 + } + ] + } + +.. include:: configuration/streams.rst + +Stream Configuration File +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The command line argument ``-T `` allows to include +streams defined from a separate file. The format is equal to +streams defined in the actual configuration file. Such stream +configuration files could be generated by scripts and +easily merged with the base configuration. + +.. code-block:: json + + { + "streams": [] + } + +Stream Commands +~~~~~~~~~~~~~~~ + +The ``session-streams`` command returns detailed stream statistics per session. + +``$ sudo bngblaster-cli run.sock session-streams session-id 1`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "session-streams": { + "session-id": 1, + "rx-packets": 59670, + "tx-packets": 54610, + "rx-accounting-packets": 59655, + "tx-accounting-packets": 54594, + "rx-pps": 1100, + "tx-pps": 1000, + "rx-bps-l2": 9028800, + "tx-bps-l2": 8240000, + "rx-mbps-l2": 9.0288, + "tx-mbps-l2": 8.24, + "streams": [ + { + "name": "BestEffort", + "direction": "upstream", + "flow-id": 1, + "rx-first-seq": 362, + "rx-last-seq": 54593, + "rx-tos-tc": 0, + "rx-outer-vlan-pbit": 0, + "rx-inner-vlan-pbit": 0, + "rx-len": 1014, + "tx-len": 1030, + "rx-packets": 54232, + "tx-packets": 54594, + "rx-loss": 0, + "rx-delay-nsec-min": 37650, + "rx-delay-nsec-max": 98595049, + "rx-pps": 1000, + "tx-pps": 1000, + "tx-bps-l2": 8240000, + "rx-bps-l2": 8112000, + "rx-bps-l3": 8000000, + "tx-mbps-l2": 8.24, + "rx-mbps-l2": 8.112, + "rx-mbps-l3": 8.0 + }, + { + "name": "BestEffort", + "direction": "downstream", + "flow-id": 2, + "rx-first-seq": 362, + "rx-last-seq": 54593, + "rx-tos-tc": 0, + "rx-outer-vlan-pbit": 0, + "rx-inner-vlan-pbit": 0, + "rx-len": 1026, + "tx-len": 1014, + "rx-packets": 54232, + "tx-packets": 54594, + "rx-loss": 0, + "rx-delay-nsec-min": 43550, + "rx-delay-nsec-max": 98903960, + "rx-pps": 1000, + "tx-pps": 1000, + "tx-bps-l2": 8112000, + "rx-bps-l2": 8208000, + "rx-bps-l3": 8000000, + "tx-mbps-l2": 8.112, + "rx-mbps-l2": 8.208, + "rx-mbps-l3": 8.0 + }, + { + "name": "Voice", + "direction": "downstream", + "flow-id": 3, + "rx-first-seq": 37, + "rx-last-seq": 5458, + "rx-tos-tc": 128, + "rx-outer-vlan-pbit": 0, + "rx-inner-vlan-pbit": 0, + "rx-len": 1026, + "tx-len": 1014, + "rx-packets": 5422, + "tx-packets": 5458, + "rx-loss": 0, + "rx-delay-nsec-min": 41700, + "rx-delay-nsec-max": 96548542, + "rx-pps": 100, + "tx-pps": 100, + "tx-bps-l2": 811200, + "rx-bps-l2": 820800, + "rx-bps-l3": 800000, + "tx-mbps-l2": 0.8112, + "rx-mbps-l2": 0.8208, + "rx-mbps-l3": 0.8 + } + ] + } + } + +The ``rx-outer-vlan-pbit`` might be wrong depending on network interface driver and +optional VLAN offloading. + +The measured ``rx-delay-nsec-min/max`` shows the minimum and maximum calculated delay +in nanosecond. The delay is calculated by subtracting the send and receive timestamp. +The send timestamp is stored in the BBL header (see section Traffic). This calculated +result depends also on the actual test environment, configured rx-interval and host IO +delay. + +Traffic streams will start as soon as the session is established using the rate as configured +starting with sequence number 1 for each flow. The attribute ``rx-first-seq`` stores the first +sequence number received. Assuming the first sequence number received for given flow is 1000 +combined with a rate of 1000 PPS would mean that it took around 1 second until forwarding is +working. After first packet is received for a given flow, for every further packet it checks +if there is a gap between last and new sequence number which is than reported as loss. + +The ``rx/tx-accounting-packets`` are all packets which should be counted in the session volume +accounting of the BNG, meaning session rx/tx packets excluding control traffic. + +Each flow can be queried separately using jsonpath expression with name and direction or flow-id. + +.. code-block:: none + + $ sudo bngblaster-cli run.sock session-streams session-id 1 | jq '."session-streams".streams[] | select(.name == "BE" and .direction == "downstream" )' + +.. code-block:: json + + { + "name": "BE", + "direction": "downstream", + "flow-id": 2, + "rx-first-seq": 33, + "rx-last-seq": 27040, + "rx-tos-tc": 213, + "rx-outer-vlan-pbit": 0, + "rx-inner-vlan-pbit": 0, + "rx-len": 126, + "tx-len": 114, + "rx-packets": 27008, + "tx-packets": 27040, + "rx-loss": 0, + "rx-delay-nsec-min": 50450, + "rx-delay-nsec-max": 10561572, + "rx-pps": 99, + "tx-pps": 99, + "tx-bps-l2": 90288, + "rx-bps-l2": 99792, + "rx-bps-l3": 79200, + "tx-mbps-l2": 0.090288, + "rx-mbps-l2": 0.099792, + "rx-mbps-l3": 0.0792 + } + +RAW Streams +~~~~~~~~~~~ + +Streams with default ``stream-group-id`` set to zero are considered as raw streams not +bound to any session which is supported in downstream only. For those streams the +destination address must be explicitly set. + +RAW streams can be used for traffic between two or network interfaces but also to send traffic +from network to access interfaces. + +.. code-block:: json + + { + "streams": [ + { + "name": "RAW", + "type": "ipv4", + "direction": "downstream", + "priority": 128, + "network-ipv4-address": "10.0.0.20", + "destination-ipv4-address": "1.1.1.1", + "length": 256, + "pps": 1 + } + ] + } + + +If ``destination-ipv4-address`` is set to a multicast IP address (224.0.0.0 - 239.255.255.255), +the BNG Blaster will set the the destination MAC address to the corresponding +multicast MAC address automatically. For unicast traffic the network gateway MAC address is used. + +Threaded Streams +~~~~~~~~~~~~~~~~ + +With threading enabled, those streams will be started per default in a dedicated thread per flow. +This means one thread per session and stream direction. A threaded, bidirectional stream assigned +to 10 sessions will therefore run in 20 threads. It is also possible to assign multiple +steams to a single thread using thread groups. + +In most environments we see between 200.000 and 300.000 PPS single threaded is working. Depending +on actual setup this can be also much more. With threaded streams we are also able to scale up to +10 million PPS depending on actual configuration and setup. This allows to start 1 million flows +with 1 PPS per flow over 4 threads in example to verify all prefixes of a BGP full table. + +The BNG Blaster is currently tested for up to 1 million flows which is not a hard limitation but +everything above should be considered as experimental. + +.. code-block:: json + + { + "streams": [ + { + "name": "RAW1", + "type": "ipv4", + "direction": "downstream", + "priority": 128, + "destination-ipv4-address": "10.0.0.1", + "length": 256, + "pps": 100000, + "network-interface": "eth1", + "threaded": true, + "thread-group": 1 + }, + { + "name": "RAW2", + "type": "ipv4", + "direction": "downstream", + "priority": 128, + "destination-ipv4-address": "10.0.0.1", + "length": 256, + "pps": 100000, + "network-interface": "etg1", + "threaded": true, + "thread-group": 2 + } + ] + } + +Start/Stop Session Stream Traffic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Session stream traffic can be started/stopped dynamically +using the commands ``stream-traffic-enabled`` and ``stream-traffic-disabled``. + +``$ sudo bngblaster-cli run.sock stream-traffic-disabled session-id 1`` + +Those commands start/stop the traffic for all sessions if invoked without +session identifier. + +``$ sudo bngblaster-cli run.sock stream-traffic-disabled`` + +Alternatively all session and stream traffic (including RAW streams) +can be started or stopped globally using the ``traffic-start`` and +``traffic-stop`` commands. diff --git a/docs/source/troubleshooting.rst b/docs/source/troubleshooting.rst new file mode 100644 index 00000000..2979ad80 --- /dev/null +++ b/docs/source/troubleshooting.rst @@ -0,0 +1,48 @@ +Troubleshooting +=============== + +Logging +------- + +The BNG Blaster is able to log events to the standard output +or logging window of the interactive courses interface. Those +events could be also logged to files using the argument +``-L ``. + +Per default only events classified as `info` or `error` are logged. +The following list shows all supported logging options. + +* ``debug``: debug events +* ``error``: error events +* ``igmp``: igmp events with join and leave time +* ``io``: interface input/output events +* ``pppoe``: pppoe events +* ``info``: informational events (enabled per default) +* ``pcap``: PCAP related events +* ``timer``: timer events +* ``timer-detail``: detailed timer events +* ``ip``: log learned IP addresses +* ``loss``: log traffic loss with sequence number +* ``l2tp``: log L2TP (LNS) events +* ``dhcp``: log DHCP events +* ``isis``: log ISIS events +* ``bgp``: log BGP events +* ``tcp``: log TCP events + +.. code-block:: none + + $ sudo bngblaster -C test.json -L test.log -l ip -l isis -l bgp + + +PCAP +---- + +You can start the BNG Blaster with the argument ``-P `` +to capture all traffic send and received by the BNG Blaster +into a single PCAP file. This file includes all traffic from all +interfaces in use with proper meta header to filter by interface +names. + +This helps to verify if traffic is received or how it has received. +Some network interfaces drop the most outer VLAN which can be easily +verified using the capture file. \ No newline at end of file diff --git a/docs/streams.md b/docs/streams.md deleted file mode 100644 index 1fb1c992..00000000 --- a/docs/streams.md +++ /dev/null @@ -1,368 +0,0 @@ -# Traffic Streams - -Traffic streams allow to do various forwarding verification -and QoS tests using BNG Blaster. - -![BBL Interactive Streams](images/bbl_streams.png "BNG Blaster") - -## Configuration - -Following a simple example using streams as described in the -[configuration section](config). - -```json -{ - "interfaces": { - "tx-interval": 0.1, - "rx-interval": 0.1, - "io-slots": 2048, - "network": { - "interface": "eth2", - "address": "10.0.0.1", - "gateway": "10.0.0.2", - "address-ipv6": "fc66:1337:7331::1", - "gateway-ipv6": "fc66:1337:7331::2" - }, - "access": [ - { - "interface": "eth1", - "outer-vlan-min": 1000, - "outer-vlan-max": 1000, - "inner-vlan-min": 7, - "inner-vlan-max": 7, - "stream-group-id": 1 - }, - { - "interface": "eth1", - "outer-vlan-min": 1001, - "outer-vlan-max": 4000, - "inner-vlan-min": 7, - "inner-vlan-max": 7, - "stream-group-id": 2 - } - ] - }, - "sessions": { - "count": 100 - }, - "pppoe": { - "host-uniq": true, - "vlan-priority": 6 - }, - "ppp": { - "mru": 1492, - "authentication": { - "username": "user{session-global}@rtbrick.com", - "password": "test", - "timeout": 5, - "retry": 30 - }, - "ipcp": { - "enable": true - }, - "ip6cp": { - "enable": true - } - }, - "dhcpv6": { - "enable": true, - "rapid-commit": true - }, - "access-line": { - "agent-remote-id": "DEU.RTBRICK.{session-global}", - "agent-circuit-id": "0.0.0.0/0.0.0.0 eth 0:{session-global}", - "rate-up": 1024, - "rate-down": 16384, - "dsl-type": 5 - }, - "streams": [ - { - "name": "BestEffort", - "stream-group-id": 1, - "type": "ipv4", - "direction": "both", - "length": 1000, - "pps": 1000 - }, - { - "name": "Voice", - "stream-group-id": 1, - "type": "ipv4", - "direction": "downstream", - "priority": 128, - "vlan-priority": 2, - "network-ipv4-address": "10.0.0.10", - "length": 1000, - "pps": 100 - }, - { - "name": "BestEffort", - "stream-group-id": 2, - "type": "ipv4", - "direction": "both", - "length": 1000, - "pps": 1 - } - ] -} -``` - -## Stream Configuration File - -The command line argument `-T ` allows to include -streams defined from a separate file. The format is equal to -streams defined in the actual configuration file. Such stream -configuration files could be generated by scripts and -easily merged with the base configuration. - -```json -{ - "streams": [] -} -``` - -## Check Session Stream Information - -The `session-streams` command returns detailed stream statistics per session. - -`$ sudo bngblaster-cli run.sock session-streams session-id 1` - -```json -{ - "status": "ok", - "code": 200, - "session-streams": { - "session-id": 1, - "rx-packets": 59670, - "tx-packets": 54610, - "rx-accounting-packets": 59655, - "tx-accounting-packets": 54594, - "rx-pps": 1100, - "tx-pps": 1000, - "rx-bps-l2": 9028800, - "tx-bps-l2": 8240000, - "rx-mbps-l2": 9.0288, - "tx-mbps-l2": 8.24, - "streams": [ - { - "name": "BestEffort", - "direction": "upstream", - "flow-id": 1, - "rx-first-seq": 362, - "rx-last-seq": 54593, - "rx-tos-tc": 0, - "rx-outer-vlan-pbit": 0, - "rx-inner-vlan-pbit": 0, - "rx-len": 1014, - "tx-len": 1030, - "rx-packets": 54232, - "tx-packets": 54594, - "rx-loss": 0, - "rx-delay-nsec-min": 37650, - "rx-delay-nsec-max": 98595049, - "rx-pps": 1000, - "tx-pps": 1000, - "tx-bps-l2": 8240000, - "rx-bps-l2": 8112000, - "rx-bps-l3": 8000000, - "tx-mbps-l2": 8.24, - "rx-mbps-l2": 8.112, - "rx-mbps-l3": 8.0 - }, - { - "name": "BestEffort", - "direction": "downstream", - "flow-id": 2, - "rx-first-seq": 362, - "rx-last-seq": 54593, - "rx-tos-tc": 0, - "rx-outer-vlan-pbit": 0, - "rx-inner-vlan-pbit": 0, - "rx-len": 1026, - "tx-len": 1014, - "rx-packets": 54232, - "tx-packets": 54594, - "rx-loss": 0, - "rx-delay-nsec-min": 43550, - "rx-delay-nsec-max": 98903960, - "rx-pps": 1000, - "tx-pps": 1000, - "tx-bps-l2": 8112000, - "rx-bps-l2": 8208000, - "rx-bps-l3": 8000000, - "tx-mbps-l2": 8.112, - "rx-mbps-l2": 8.208, - "rx-mbps-l3": 8.0 - }, - { - "name": "Voice", - "direction": "downstream", - "flow-id": 3, - "rx-first-seq": 37, - "rx-last-seq": 5458, - "rx-tos-tc": 128, - "rx-outer-vlan-pbit": 0, - "rx-inner-vlan-pbit": 0, - "rx-len": 1026, - "tx-len": 1014, - "rx-packets": 5422, - "tx-packets": 5458, - "rx-loss": 0, - "rx-delay-nsec-min": 41700, - "rx-delay-nsec-max": 96548542, - "rx-pps": 100, - "tx-pps": 100, - "tx-bps-l2": 811200, - "rx-bps-l2": 820800, - "rx-bps-l3": 800000, - "tx-mbps-l2": 0.8112, - "rx-mbps-l2": 0.8208, - "rx-mbps-l3": 0.8 - } - ] - } -} -``` - -The `rx-outer-vlan-pbit` might be wrong depending on network interface driver and -optional VLAN offloading. - -The measured `rx-delay-nsec-min/max` shows the minimum and maximum calculated delay -in nanosecond. The delay is calculated by subtracting the send and receive timestamp. -The send timestamp is stored in the BBL header (see section Traffic). This calculated -result depends also on the actual test environment, configured rx-interval and host IO -delay. - -Traffic streams will start as soon as the session is established using the rate as configured -starting with sequence number 1 for each flow. The attribute `rx-first-seq` stores the first -sequence number received. Assuming the first sequence number received for given flow is 1000 -combined with a rate of 1000 PPS would mean that it took around 1 second until forwarding is -working. After first packet is received for a given flow, for every further packet it checks -if there is a gap between last and new sequence number which is than reported as loss. - -The `rx/tx-accounting-packets` are all packets which should be counted in the session volume -accounting of the BNG, meaning session rx/tx packets excluding control traffic. - -Each flow can be queried separately using jsonpath expression with name and direction or flow-id. - -`$ sudo bngblaster-cli run.sock session-streams session-id 1 | jq '."session-streams".streams[] | select(.name == "BE" and .direction == "downstream" )'` - -```json -{ - "name": "BE", - "direction": "downstream", - "flow-id": 2, - "rx-first-seq": 33, - "rx-last-seq": 27040, - "rx-tos-tc": 213, - "rx-outer-vlan-pbit": 0, - "rx-inner-vlan-pbit": 0, - "rx-len": 126, - "tx-len": 114, - "rx-packets": 27008, - "tx-packets": 27040, - "rx-loss": 0, - "rx-delay-nsec-min": 50450, - "rx-delay-nsec-max": 10561572, - "rx-pps": 99, - "tx-pps": 99, - "tx-bps-l2": 90288, - "rx-bps-l2": 99792, - "rx-bps-l3": 79200, - "tx-mbps-l2": 0.090288, - "rx-mbps-l2": 0.099792, - "rx-mbps-l3": 0.0792 -} -``` - -## RAW Streams - -Streams with default `stream-group-id` set to zero are considered as raw streams not -bound to any session which is supported in downstream only. For those streams the -destination address must be explicitly set. - -RAW streams can be used for traffic between two or network interfaces but also to send traffic -from network to access interfaces. - -```json -{ - "streams": [ - { - "name": "RAW", - "type": "ipv4", - "direction": "downstream", - "priority": 128, - "network-ipv4-address": "10.0.0.20", - "destination-ipv4-address": "1.1.1.1", - "length": 256, - "pps": 1 - } - ] -} -``` - -If `destination-ipv4-address` is set to a multicast IP address (224.0.0.0 - 239.255.255.255), -the BNG Blaster will set the the destination MAC address to the corresponding -multicast MAC address automatically. For unicast traffic the network gateway MAC address is used. - -## Threaded Streams - -With threading enabled, those streams will be started per default in a dedicated thread per flow. -This means one thread per session and stream direction. A threaded, bidirectional stream assigned -to 10 sessions will therefore run in 20 threads. It is also possible to assign multiple -steams to a single thread using thread groups. - -In most environments we see between 200.000 and 300.000 PPS single threaded is working. Depending -on actual setup this can be also much more. With threaded streams we are also able to scale up to -10 million PPS depending on actual configuration and setup. This allows to start 1 million flows -with 1 PPS per flow over 4 threads in example to verify all prefixes of a BGP full table. - -The BNG Blaster is currently tested for up to 1 million flows which is not a hard limitation but -everything above should be considered as experimental. - -```json -{ - "streams": [ - { - "name": "RAW1", - "type": "ipv4", - "direction": "downstream", - "priority": 128, - "destination-ipv4-address": "10.0.0.1", - "length": 256, - "pps": 100000, - "network-interface": "eth1", - "threaded": true, - "thread-group": 1 - }, - { - "name": "RAW2", - "type": "ipv4", - "direction": "downstream", - "priority": 128, - "destination-ipv4-address": "10.0.0.1", - "length": 256, - "pps": 100000, - "network-interface": "etg1", - "threaded": true, - "thread-group": 2 - } - ] -} -``` - -## Start/Stop Session Stream Traffic - -Session stream traffic can be started/stopped dynamically -using the commands `stream-traffic-enabled` and `stream-traffic-disabled`. - -`$ sudo bngblaster-cli run.sock stream-traffic-disabled session-id 1` - -Those commands start/stop the traffic for all sessions if invoked without -session identifier. - -`$ sudo bngblaster-cli run.sock stream-traffic-disabled` - -Alternatively all session and stream traffic (including RAW streams) -can be started or stopped globally using the `traffic-start` and -`traffic-stop` commands. diff --git a/docs/traffic.md b/docs/traffic.md deleted file mode 100644 index cd47a3b7..00000000 --- a/docs/traffic.md +++ /dev/null @@ -1,122 +0,0 @@ -# Traffic - -The BNG Blaster is able to emulate bidirectional unicast -session traffic for all addresses assigned to a session -(IPv4, IPv6 and IPv6PD). - -![BNG Blaster Session Traffic](images/bbl_session_traffic.png) - -There is also support to generate IPv4 multicast traffic. - -## Blaster Header and Fast Decode Signature - -The 48 Byte fixed size BNG Blaster Header is added to all data packets -for traffic validation and fast decoding. The header is expected on the -last 48 bytes of the packet. - -The type is set to 1 for all unicast session traffic and 2 for -IPv4 multicast traffic. - -### Unicast Session Traffic - -The 64 bit session key is used for all traffic from access (upstream) -and to access (downstream) interfaces to identify the corresponding -session which has send or should receive the packet. - -```text - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| BNG Blaster Magic Sequence | -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Type | Sub-Type | Direction | TX TOS | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Session Identifier | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Session Access Interface Index | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Session Outer VLAN | Session Inner VLAN | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Flow Identifier | -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Flow Sequence Number | -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Nanosecond Send Timestamp | -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -``` - -![BNG Blaster Header](images/bbl_header.png) - -### Multicast Traffic - -```text - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| BNG Blaster Magic Sequence | -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Type | Sub-Type | Direction | TX TOS | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Reserved | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Source | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Group | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Flow Identifier | -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Flow Sequence Number | -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Nanosecond Send Timestamp | -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -``` - -NOTE: All attributes except IP addresses in the Blaster Header are -stored in host byte order for faster processing -(LE or BE depending on test system). - -### BNG Blaster Magic Sequence - -The 64 bit magic sequence is the word `RtBrick!` decoded as ASCII: - -```text -0x5274427269636b21 -``` - -The magic number allows to check for it on a given offset and process -only blaster header instead of decoding the whole packet for faster -packet processing. - -### Flow Identifier - -The 64 bit flow identifier is a global unique number which identifies -the flow. - -### Flow Sequence Number - -The 64 bit flow sequence number is sequential number starting with 1 -and incremented per packet primary used to identity packet loss. - -This number 0 means that sequencing is disabled. - -### Nanosecond Send Timestamps - -The 64 bit nanoseconds send timestamp is used for optional latency and -jitter calculations. - -```text - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Seconds | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Nano Seconds | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -``` - -The timestamp 0 means that timestamps are disabled.