diff --git a/README.md b/README.md index 770a5d83..d9a94cd4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ![Build](https://github.com/rtbrick/bngblaster/workflows/Build/badge.svg?branch=main) The BNG Blaster is a test tool to simulate thousands of PPPoE or IPoE subscribers including IPTV, -traffic verification and convergence testing capabilities. +L2TPv2, traffic verification and convergence testing capabilities. A short introduction can be found on [YouTube](https://youtu.be/EHJ70p0_Sw0 "BNG Blaster") or checkout the [documentation](https://rtbrick.github.io/bngblaster/) for details. diff --git a/docs/ctrl.md b/docs/ctrl.md index 9a105d5b..8a89c737 100644 --- a/docs/ctrl.md +++ b/docs/ctrl.md @@ -110,6 +110,7 @@ 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-enabled` | Enable session traffic for all sessions `session-traffic-disabled` | Disable session traffic for all sessions `multicast-traffic-start` | Start sending multicast traffic from network interface diff --git a/docs/intro.md b/docs/intro.md index 942bf1a2..b828798d 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -9,7 +9,7 @@ targeted for max scaling with small resource footprint, simple to use and easy t our test automation infrastructure. The BNG Blaster is able to simulate more than hundred thousand PPPoE subscribers including IPTV, -traffic verification and convergence testing capabilities. +L2TPv2, traffic verification and convergence testing capabilities. * *High Scaling:* > 100K sessions * *Low CPU and Memory Footprint:* < 100MB memory for 16K sessions diff --git a/docs/l2tp.md b/docs/l2tp.md index 9195adaf..456d79b8 100644 --- a/docs/l2tp.md +++ b/docs/l2tp.md @@ -281,8 +281,8 @@ Following an example with 30 L2TP LNS servers. "control-packets-rx-out-of-order": 0, "control-packets-tx": 102, "control-packets-tx-retry": 0, - "control-data-rx": 1406, - "control-data-tx": 206 + "data-packets-rx": 1406, + "data-packets-tx": 206 } ] } @@ -311,7 +311,11 @@ The `l2tp-sessions` command returns all L2TP sessions. "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" + "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 } ] } diff --git a/docs/li.md b/docs/li.md index 891344d2..f54a5746 100644 --- a/docs/li.md +++ b/docs/li.md @@ -52,7 +52,12 @@ The received flows can be queried using the control socket. "packets-rx-ipv4": 0, "packets-rx-ipv4-tcp": 0, "packets-rx-ipv4-udp": 0, - "packets-rx-ipv4-host-internal": 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", @@ -68,11 +73,19 @@ The received flows can be queried using the control socket. "packets-rx-ipv4": 820, "packets-rx-ipv4-tcp": 0, "packets-rx-ipv4-udp": 0, - "packets-rx-ipv4-host-internal": 820 + "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. \ No newline at end of file +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/reports.md b/docs/reports.md index 8036a1a4..1b9fca4f 100644 --- a/docs/reports.md +++ b/docs/reports.md @@ -325,6 +325,28 @@ JSON: } ``` +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 diff --git a/src/bbl_config.c b/src/bbl_config.c index d4758200..bc1d30bb 100644 --- a/src/bbl_config.c +++ b/src/bbl_config.c @@ -746,7 +746,7 @@ json_parse_config (json_t *root, bbl_ctx_s *ctx) { l2tp_server->data_offset = json_boolean_value(value); } } - } else if (json_is_object(sub)) { + } else if (json_is_object(section)) { fprintf(stderr, "JSON config error: List expected in L2TP server configuration but dictionary found\n"); } diff --git a/src/bbl_ctrl.c b/src/bbl_ctrl.c index 47eca05c..6cd35c27 100644 --- a/src/bbl_ctrl.c +++ b/src/bbl_ctrl.c @@ -96,6 +96,22 @@ bbl_ctrl_multicast_traffic_stop(int fd, bbl_ctx_s *ctx, session_key_t *key __att return bbl_ctrl_status(fd, "ok", 200, NULL); } +ssize_t +bbl_ctrl_session_traffic_stats(int fd, bbl_ctx_s *ctx, session_key_t *key __attribute__((unused)), json_t* arguments __attribute__((unused))) { + ssize_t result = 0; + json_t *root = json_pack("{ss si s{si si}}", + "status", "ok", + "code", 200, + "session-traffic", + "total-flows", ctx->stats.session_traffic_flows, + "verified-flows", ctx->stats.session_traffic_flows_verified); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } + return result; +} + ssize_t bbl_ctrl_session_traffic(int fd, bbl_ctx_s *ctx, session_key_t *key, bool status) { struct dict_itor *itor; @@ -768,8 +784,8 @@ bbl_ctrl_l2tp_tunnels(int fd, bbl_ctx_s *ctx, session_key_t *key __attribute__(( "control-packets-rx-out-of-order", l2tp_tunnel->stats.control_rx_ooo, "control-packets-tx", l2tp_tunnel->stats.control_tx, "control-packets-tx-retry", l2tp_tunnel->stats.control_retry, - "control-data-rx", l2tp_tunnel->stats.data_rx, - "control-data-tx", l2tp_tunnel->stats.data_tx); + "data-packets-rx", l2tp_tunnel->stats.data_rx, + "data-packets-tx", l2tp_tunnel->stats.data_tx); json_array_append(tunnels, tunnel); } l2tp_server = l2tp_server->next; @@ -791,7 +807,7 @@ bbl_ctrl_l2tp_tunnels(int fd, bbl_ctx_s *ctx, session_key_t *key __attribute__(( json_t * l2tp_session_json(bbl_l2tp_session_t *l2tp_session) { - return json_pack("{ss si si si si ss ss ss ss si si ss ss}", + return json_pack("{ss si si si si ss ss ss ss si si ss ss si si si si}", "state", l2tp_session_state_string(l2tp_session->state), "tunnel-id", l2tp_session->key.tunnel_id, "session-id", l2tp_session->key.session_id, @@ -804,7 +820,11 @@ l2tp_session_json(bbl_l2tp_session_t *l2tp_session) { "peer-tx-bps", l2tp_session->peer_tx_bps, "peer-rx-bps", l2tp_session->peer_rx_bps, "peer-ari", string_or_na(l2tp_session->peer_ari), - "peer-aci", string_or_na(l2tp_session->peer_aci)); + "peer-aci", string_or_na(l2tp_session->peer_aci), + "data-packets-rx", l2tp_session->stats.data_rx, + "data-packets-tx", l2tp_session->stats.data_tx, + "data-ipv4-packets-rx", l2tp_session->stats.data_ipv4_rx, + "data-ipv4-packets-tx", l2tp_session->stats.data_ipv4_tx); } ssize_t @@ -940,6 +960,7 @@ struct action actions[] = { {"session-counters", bbl_ctrl_session_counters}, {"session-info", bbl_ctrl_session_info}, {"session-traffic-enabled", bbl_ctrl_session_traffic_start}, + {"session-traffic", bbl_ctrl_session_traffic_stats}, {"session-traffic-start", bbl_ctrl_session_traffic_start}, {"session-traffic-disabled", bbl_ctrl_session_traffic_stop}, {"session-traffic-stop", bbl_ctrl_session_traffic_stop}, diff --git a/src/bbl_l2tp.c b/src/bbl_l2tp.c index 6fb2edc9..c0a42ffd 100644 --- a/src/bbl_l2tp.c +++ b/src/bbl_l2tp.c @@ -191,7 +191,7 @@ bbl_l2tp_tunnel_update_state(bbl_l2tp_tunnel_t *l2tp_tunnel, l2tp_tunnel_state_t if(ctx->l2tp_tunnels_established > ctx->l2tp_tunnels_established_max) { ctx->l2tp_tunnels_established_max = ctx->l2tp_tunnels_established; } - LOG(L2TP, "L2TP Info (%s) Tunnel %u with %s (%s) estbalished\n", + LOG(L2TP, "L2TP Info (%s) Tunnel %u with %s (%s) established\n", l2tp_tunnel->server->host_name, l2tp_tunnel->tunnel_id, l2tp_tunnel->peer_name, format_ipv4_address(&l2tp_tunnel->peer_ip)); @@ -491,7 +491,11 @@ bbl_l2tp_send_data(bbl_l2tp_session_t *l2tp_session, uint16_t protocol, void *ne q->packet_len = len; CIRCLEQ_INSERT_TAIL(&interface->l2tp_tx_qhead, q, tx_qnode); l2tp_tunnel->stats.data_tx++; + l2tp_session->stats.data_tx++; interface->stats.l2tp_data_tx++; + if(protocol == PROTOCOL_IPV4) { + l2tp_session->stats.data_ipv4_tx++; + } } else { LOG(ERROR, "L2TP Data Encode Error!\n"); free(q); @@ -788,7 +792,7 @@ bbl_l2tp_iccn_rx(bbl_ethernet_header_t *eth, bbl_l2tp_t *l2tp, bbl_interface_s * } if(l2tp_session->state == BBL_L2TP_SESSION_WAIT_CONN) { l2tp_session->state = BBL_L2TP_SESSION_ESTABLISHED; - LOG(L2TP, "L2TP Info (%s) Tunnel (%u) from %s (%s) session (%u) estbalished\n", + LOG(L2TP, "L2TP Info (%s) Tunnel (%u) from %s (%s) session (%u) established\n", l2tp_tunnel->server->host_name, l2tp_tunnel->tunnel_id, l2tp_tunnel->peer_name, format_ipv4_address(&l2tp_tunnel->peer_ip), @@ -847,6 +851,7 @@ bbl_l2tp_data_rx(bbl_ethernet_header_t *eth, bbl_l2tp_t *l2tp, bbl_interface_s * return; } + l2tp_session->stats.data_rx++; switch (l2tp->protocol) { case PROTOCOL_LCP: lcp_rx = (bbl_lcp_t*)l2tp->next; @@ -944,6 +949,7 @@ bbl_l2tp_data_rx(bbl_ethernet_header_t *eth, bbl_l2tp_t *l2tp, bbl_interface_s * } break; case PROTOCOL_IPV4: + l2tp_session->stats.data_ipv4_rx++; ipv4 = (bbl_ipv4_t*)l2tp->next; if(ipv4->protocol == PROTOCOL_IPV4_UDP) { udp = (bbl_udp_t*)ipv4->next; diff --git a/src/bbl_l2tp.h b/src/bbl_l2tp.h index 5a300bbf..de62d1c4 100644 --- a/src/bbl_l2tp.h +++ b/src/bbl_l2tp.h @@ -212,6 +212,13 @@ typedef struct bbl_l2tp_session_ uint16_t session_id; } key; + struct { + uint64_t data_rx; /* Session data traffic received */ + uint64_t data_tx; /* Session data traffic send */ + uint64_t data_ipv4_rx; /* Session data ipv4 traffic received */ + uint64_t data_ipv4_tx; /* Session data ppv4 traffic send */ + } stats; + uint16_t peer_session_id; bool data_sequencing; @@ -250,6 +257,7 @@ typedef struct bbl_l2tp_session_ char *peer_sub_address; char *peer_ari; char *peer_aci; + } bbl_l2tp_session_t; const char* l2tp_message_string(l2tp_message_type type);