Files
rtbrick-bngblaster/code/bngblaster/src/bbl_interactive.c
T

677 lines
32 KiB
C

/*
* BNG Blaster (BBL) - Interactive Mode
*
* Hannes Gredler, July 2020
* Christian Giese, October 2020
*
* Copyright (C) 2020-2022, RtBrick, Inc.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "bbl.h"
#include "bbl_stats.h"
#include "bbl_session.h"
#include "bbl_stream.h"
#define PROGRESS_BAR_SIZE 60
#define STATS_WIN_SIZE 90
#define STRING_SP_SIZE 64
#define VISIBLE(_expression) \
visible = false; \
if(_expression) { \
if(pos > stats_win_postion) { \
visible = true; \
} \
pos++; \
} \
if(visible)
typedef enum {
UI_VIEW_DEFAULT = 0,
UI_VIEW_ACCESS_IF_STATS,
UI_VIEW_SESSION,
UI_VIEW_MAX,
} __attribute__ ((__packed__)) bbl_ui_view;
/* ncurses */
WINDOW *stats_win = NULL;
WINDOW *log_win = NULL;
int stats_win_postion;
extern volatile bool g_teardown;
extern volatile bool g_teardown_request;
extern bool g_banner;
extern bool g_interactive;
/* This global variable is used to switch between access interfaces. */
uint8_t g_access_if_selected = 0;
uint8_t g_network_if_selected = 0;
uint8_t g_a10nsp_if_selected = 0;
/* This global variable is used to switch between views. */
bbl_ui_view g_view_selected = 0;
/* This global variable is used to switch vetween sessions in some views. */
uint32_t g_session_selected = 1;
extern const char banner[];
void
bbl_init_stats_win(bbl_ctx_s *ctx)
{
wclear(stats_win);
wattron(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, "F1: Select View F7/F8: Start/Stop Traffic F9: Terminate Sessions\n");
if(g_view_selected == UI_VIEW_SESSION) {
wprintw(stats_win, "Left/Right: Select Session\n");
} else {
if(ctx->interfaces.network_if_count) {
wprintw(stats_win, "F2: Network Interface ");
}
if(ctx->interfaces.a10nsp_if_count) {
wprintw(stats_win, "F3: Select A10NSP Interface ");
}
if(ctx->interfaces.access_if_count) {
wprintw(stats_win, "Left/Right: Access Interface");
}
wprintw(stats_win, "\n");
}
wattroff(stats_win, COLOR_PAIR(COLOR_GREEN));
if(g_banner) {
wprintw(stats_win, "%s", banner);
}
}
/*
* Interactive keyboard reader
*/
void
bbl_read_key_job (timer_s *timer)
{
bbl_ctx_s *ctx = timer->data;
int ch;
ch = getch();
switch (ch) {
case KEY_F(1):
stats_win_postion = 0;
g_view_selected++;
if(g_view_selected >= UI_VIEW_MAX) {
g_view_selected = UI_VIEW_DEFAULT;
}
/* Skip access interface and session views
* if there is no access interface. */
if(ctx->interfaces.access_if_count == 0) {
switch (g_view_selected) {
case UI_VIEW_ACCESS_IF_STATS:
case UI_VIEW_SESSION:
g_view_selected = UI_VIEW_DEFAULT;
break;
default:
break;
}
}
bbl_init_stats_win(ctx);
break;
case KEY_F(2):
if(ctx->interfaces.network_if_count > 1) {
g_network_if_selected++;
if(g_network_if_selected >= ctx->interfaces.network_if_count) {
g_network_if_selected = 0;
}
bbl_init_stats_win(ctx);
}
break;
case KEY_F(3):
if(ctx->interfaces.a10nsp_if_count > 1) {
g_a10nsp_if_selected++;
if(g_a10nsp_if_selected >= ctx->interfaces.a10nsp_if_count) {
g_a10nsp_if_selected = 0;
}
bbl_init_stats_win(ctx);
}
break;
case KEY_LEFT:
if(g_view_selected == UI_VIEW_SESSION) {
if(g_session_selected > 1) {
g_session_selected--;
} else {
g_session_selected = ctx->sessions;
}
} else {
if(g_access_if_selected == 0) {
g_access_if_selected = ctx->interfaces.access_if_count;
}
g_access_if_selected--;
}
bbl_init_stats_win(ctx);
break;
case KEY_RIGHT:
if(g_view_selected == UI_VIEW_SESSION) {
g_session_selected++;
if(g_session_selected > ctx->sessions) {
g_session_selected = 1;
}
} else {
g_access_if_selected++;
if(g_access_if_selected >= ctx->interfaces.access_if_count) {
g_access_if_selected = 0;
}
}
bbl_init_stats_win(ctx);
break;
case KEY_F(7):
enable_disable_traffic(ctx, true);
LOG_NOARG(INFO, "Start traffic\n");
break;
case KEY_F(8):
enable_disable_traffic(ctx, false);
LOG_NOARG(INFO, "Stop traffic\n");
break;
case KEY_F(9):
g_teardown = true;
g_teardown_request = true;
LOG_NOARG(INFO, "Teardown request\n");
break;
case KEY_DOWN:
if(g_view_selected == UI_VIEW_DEFAULT) {
if(stats_win_postion < 6) {
stats_win_postion++;
}
bbl_init_stats_win(ctx);
} else if(g_view_selected == UI_VIEW_SESSION) {
stats_win_postion++;
bbl_init_stats_win(ctx);
}
break;
case KEY_UP:
if(stats_win_postion) stats_win_postion--;
bbl_init_stats_win(ctx);
break;
default:
break;
}
}
/*
* Format a progress bar.
*/
static char *
bbl_format_progress (uint32_t complete, uint32_t current)
{
static char buf[PROGRESS_BAR_SIZE+1];
float percentage;
uint16_t idx;
if (!complete || !current) {
memset(buf, ' ', sizeof(buf));
goto EXIT;
}
percentage = (float)current / (float)complete;
for (idx = 0; idx < sizeof(buf); idx++) {
if (idx <= (percentage * PROGRESS_BAR_SIZE)) {
buf[idx] = '#';
continue;
}
buf[idx] = ' ';
}
EXIT:
buf[PROGRESS_BAR_SIZE] = 0;
return buf;
}
/*
* Display meaningful stats in a curses window.
*/
void
bbl_stats_job (timer_s *timer)
{
bbl_ctx_s *ctx = timer->data;
struct bbl_interface_ *access_if;
struct bbl_interface_ *network_if;
struct bbl_interface_ *a10nsp_if;
char strsp[STRING_SP_SIZE];
bbl_session_s *session;
int i;
int pos = 1; /* position */
bool visible = false;
access_if = ctx->interfaces.access_if[g_access_if_selected];
network_if = ctx->interfaces.network_if[g_network_if_selected];
a10nsp_if = ctx->interfaces.a10nsp_if[g_a10nsp_if_selected];
if(g_banner) {
wmove(stats_win, 14, 0);
} else {
wmove(stats_win, 2, 0);
}
if(g_view_selected == UI_VIEW_DEFAULT) {
VISIBLE((ctx->sessions)) {
wprintw(stats_win, "\nSessions %10lu (%lu PPPoE / %lu IPoE)\n", ctx->sessions, ctx->sessions_pppoe, ctx->sessions_ipoe);
/* Progress bar established sessions */
wprintw(stats_win, " Established %10lu [", ctx->sessions_established);
if(ctx->sessions == ctx->sessions_established) {
wattron(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, "%s", bbl_format_progress(ctx->sessions, ctx->sessions_established));
wattroff(stats_win, COLOR_PAIR(COLOR_GREEN));
} else {
wattron(stats_win, COLOR_PAIR(COLOR_BLACK));
wprintw(stats_win, "%s", bbl_format_progress(ctx->sessions, ctx->sessions_established));
wattroff(stats_win, COLOR_PAIR(COLOR_BLACK));
}
wprintw(stats_win, "]\n");
/* Progress bar outstanding sessions */
wprintw(stats_win, " Outstanding %10lu [", ctx->sessions_outstanding);
wattron(stats_win, COLOR_PAIR(COLOR_BLACK));
wprintw(stats_win, "%s", bbl_format_progress(ctx->config.sessions_max_outstanding, ctx->sessions_outstanding));
wattroff(stats_win, COLOR_PAIR(COLOR_BLACK));
wprintw(stats_win, "]\n");
/* Progress bar terminated sessions */
wprintw(stats_win, " Terminated %10lu [", ctx->sessions_terminated);
wattron(stats_win, COLOR_PAIR(COLOR_RED));
wprintw(stats_win, "%s", bbl_format_progress(ctx->sessions, ctx->sessions_terminated));
wattroff(stats_win, COLOR_PAIR(COLOR_RED));
wprintw(stats_win, "]\n");
/* DHCPv4 */
if(ctx->dhcp_requested || ctx->dhcp_established_max) {
snprintf(strsp, STRING_SP_SIZE, "%u/%u", ctx->dhcp_established, ctx->dhcp_requested);
wprintw(stats_win, " DHCPv4 %15s [", strsp);
if(ctx->dhcp_requested == ctx->dhcp_established) {
wattron(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, "%s", bbl_format_progress(ctx->dhcp_requested, ctx->dhcp_established));
wattroff(stats_win, COLOR_PAIR(COLOR_GREEN));
} else {
wattron(stats_win, COLOR_PAIR(COLOR_BLACK));
wprintw(stats_win, "%s", bbl_format_progress(ctx->dhcp_requested, ctx->dhcp_established));
wattroff(stats_win, COLOR_PAIR(COLOR_BLACK));
}
wprintw(stats_win, "]\n");
}
/* DHCPv6 */
if(ctx->dhcpv6_requested || ctx->dhcpv6_established_max) {
snprintf(strsp, STRING_SP_SIZE, "%u/%u", ctx->dhcpv6_established, ctx->dhcpv6_requested);
wprintw(stats_win, " DHCPv6 %15s [", strsp);
if(ctx->dhcpv6_requested == ctx->dhcpv6_established) {
wattron(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, "%s", bbl_format_progress(ctx->dhcpv6_requested, ctx->dhcpv6_established));
wattroff(stats_win, COLOR_PAIR(COLOR_GREEN));
} else {
wattron(stats_win, COLOR_PAIR(COLOR_BLACK));
wprintw(stats_win, "%s", bbl_format_progress(ctx->dhcpv6_requested, ctx->dhcpv6_established));
wattroff(stats_win, COLOR_PAIR(COLOR_BLACK));
}
wprintw(stats_win, "]\n");
}
/* Session stats */
wprintw(stats_win, " Setup Time %10lu ms\n", ctx->stats.setup_time);
wprintw(stats_win, " Setup Rate %10.02lf CPS (MIN: %0.02lf AVG: %0.02lf MAX: %0.02lf)\n",
ctx->stats.cps, ctx->stats.cps_min, ctx->stats.cps_avg, ctx->stats.cps_max);
wprintw(stats_win, " Flapped %10lu\n", ctx->sessions_flapped);
}
if(network_if) {
VISIBLE((dict_count(ctx->li_flow_dict))) {
wprintw(stats_win, "\nLI Statistics\n");
wprintw(stats_win, " Flows %10lu\n", dict_count(ctx->li_flow_dict));
wprintw(stats_win, " Rx Packets %10lu (%7lu PPS)\n",
network_if->stats.li_rx, network_if->stats.rate_li_rx.avg);
}
VISIBLE((ctx->config.l2tp_server)) {
wprintw(stats_win, "\nL2TP LNS Statistics\n");
wprintw(stats_win, " Tunnels %10lu\n", ctx->l2tp_tunnels);
wprintw(stats_win, " Established %10lu\n", ctx->l2tp_tunnels_established);
wprintw(stats_win, " Sessions %10lu\n", ctx->l2tp_sessions);
wprintw(stats_win, " Packets:\n");
wprintw(stats_win, " Tx Control %10lu Retries: %lu\n",
network_if->stats.l2tp_control_tx, network_if->stats.l2tp_control_retry);
wprintw(stats_win, " Rx Control %10lu Duplicate: %lu Out-of-Order: %lu\n",
network_if->stats.l2tp_control_rx,
network_if->stats.l2tp_control_rx_dup,
network_if->stats.l2tp_control_rx_ooo);
wprintw(stats_win, " Tx Data %10lu (%7lu PPS)\n",
network_if->stats.l2tp_data_tx, network_if->stats.rate_l2tp_data_tx.avg);
wprintw(stats_win, " Rx Data %10lu (%7lu PPS)\n",
network_if->stats.l2tp_data_rx, network_if->stats.rate_l2tp_data_rx.avg);
}
}
VISIBLE((ctx->stats.session_traffic_flows || ctx->stats.stream_traffic_flows)) {
wprintw(stats_win, "\nTraffic Flows Verified\n");
if(ctx->stats.session_traffic_flows) {
snprintf(strsp, STRING_SP_SIZE, "%u/%u", ctx->stats.session_traffic_flows_verified, ctx->stats.session_traffic_flows);
wprintw(stats_win, " Session %14s [", strsp);
if(ctx->stats.session_traffic_flows == ctx->stats.session_traffic_flows_verified) {
wattron(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, "%s", bbl_format_progress(ctx->stats.session_traffic_flows, ctx->stats.session_traffic_flows_verified));
wattroff(stats_win, COLOR_PAIR(COLOR_GREEN));
} else {
wattron(stats_win, COLOR_PAIR(COLOR_BLACK));
wprintw(stats_win, "%s", bbl_format_progress(ctx->stats.session_traffic_flows, ctx->stats.session_traffic_flows_verified));
wattroff(stats_win, COLOR_PAIR(COLOR_BLACK));
}
wprintw(stats_win, "]\n");
}
if(ctx->stats.stream_traffic_flows) {
snprintf(strsp, STRING_SP_SIZE, "%u/%u", ctx->stats.stream_traffic_flows_verified, ctx->stats.stream_traffic_flows);
wprintw(stats_win, " Stream %15s [", strsp);
if(ctx->stats.stream_traffic_flows == ctx->stats.stream_traffic_flows_verified) {
wattron(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, "%s", bbl_format_progress(ctx->stats.stream_traffic_flows, ctx->stats.stream_traffic_flows_verified));
wattroff(stats_win, COLOR_PAIR(COLOR_GREEN));
} else {
wattron(stats_win, COLOR_PAIR(COLOR_BLACK));
wprintw(stats_win, "%s", bbl_format_progress(ctx->stats.stream_traffic_flows, ctx->stats.stream_traffic_flows_verified));
wattroff(stats_win, COLOR_PAIR(COLOR_BLACK));
}
wprintw(stats_win, "]\n");
}
}
VISIBLE(network_if) {
wprintw(stats_win, "\nNetwork Interface (");
for(i = 0; i < ctx->interfaces.network_if_count; i++) {
if(i == g_network_if_selected) {
wattron(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, " %s", ctx->interfaces.network_if[i]->name);
wattroff(stats_win, COLOR_PAIR(COLOR_GREEN));
} else {
wprintw(stats_win, " %s", ctx->interfaces.network_if[i]->name);
}
}
wprintw(stats_win, " )\n Tx Packets %10lu |%7lu PPS %10lu Kbps\n",
network_if->stats.packets_tx, network_if->stats.rate_packets_tx.avg,
network_if->stats.rate_bytes_tx.avg * 8 / 1000);
wprintw(stats_win, " Rx Packets %10lu |%7lu PPS %10lu Kbps\n",
network_if->stats.packets_rx, network_if->stats.rate_packets_rx.avg,
network_if->stats.rate_bytes_rx.avg * 8 / 1000);
if(ctx->stats.stream_traffic_flows) {
wprintw(stats_win, " Tx Stream Packets %10lu |%7lu PPS\n",
network_if->stats.stream_tx, network_if->stats.rate_stream_tx.avg);
wprintw(stats_win, " Rx Stream Packets %10lu |%7lu PPS %10lu Loss\n",
network_if->stats.stream_rx, network_if->stats.rate_stream_rx.avg,
network_if->stats.stream_loss);
}
if(ctx->stats.session_traffic_flows) {
wprintw(stats_win, " Tx Session Packets %10lu |%7lu PPS\n",
network_if->stats.session_ipv4_tx, network_if->stats.rate_session_ipv4_tx.avg);
wprintw(stats_win, " Rx Session Packets %10lu |%7lu PPS %10lu Loss\n",
network_if->stats.session_ipv4_rx, network_if->stats.rate_session_ipv4_rx.avg,
network_if->stats.session_ipv4_loss);
wprintw(stats_win, " Tx Session Packets IPv6 %10lu |%7lu PPS\n",
network_if->stats.session_ipv6_tx, network_if->stats.rate_session_ipv6_tx.avg);
wprintw(stats_win, " Rx Session Packets IPv6 %10lu |%7lu PPS %10lu Loss\n",
network_if->stats.session_ipv6_rx, network_if->stats.rate_session_ipv6_rx.avg,
network_if->stats.session_ipv6_loss);
wprintw(stats_win, " Tx Session Packets IPv6PD %10lu |%7lu PPS\n",
network_if->stats.session_ipv6pd_tx, network_if->stats.rate_session_ipv6pd_tx.avg);
wprintw(stats_win, " Rx Session Packets IPv6PD %10lu |%7lu PPS %10lu Loss\n",
network_if->stats.session_ipv6pd_rx, network_if->stats.rate_session_ipv6pd_rx.avg,
network_if->stats.session_ipv6pd_loss);
}
wprintw(stats_win, " Tx Multicast Packets %10lu |%7lu PPS\n",
network_if->stats.mc_tx, network_if->stats.rate_mc_tx.avg);
}
VISIBLE(a10nsp_if) {
wprintw(stats_win, "\nA10NSP Interface (");
for(i = 0; i < ctx->interfaces.a10nsp_if_count; i++) {
if(i == g_a10nsp_if_selected) {
wattron(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, " %s", ctx->interfaces.a10nsp_if[i]->name);
wattroff(stats_win, COLOR_PAIR(COLOR_GREEN));
} else {
wprintw(stats_win, " %s", ctx->interfaces.a10nsp_if[i]->name);
}
}
wprintw(stats_win, " )\n Tx Packets %10lu |%7lu PPS %10lu Kbps\n",
a10nsp_if->stats.packets_tx, a10nsp_if->stats.rate_packets_tx.avg,
a10nsp_if->stats.rate_bytes_tx.avg * 8 / 1000);
wprintw(stats_win, " Rx Packets %10lu |%7lu PPS %10lu Kbps\n",
a10nsp_if->stats.packets_rx, a10nsp_if->stats.rate_packets_rx.avg,
a10nsp_if->stats.rate_bytes_rx.avg * 8 / 1000);
if(ctx->stats.stream_traffic_flows) {
wprintw(stats_win, " Tx Stream Packets %10lu |%7lu PPS\n",
a10nsp_if->stats.stream_tx, a10nsp_if->stats.rate_stream_tx.avg);
wprintw(stats_win, " Rx Stream Packets %10lu |%7lu PPS %10lu Loss\n",
a10nsp_if->stats.stream_rx, a10nsp_if->stats.rate_stream_rx.avg,
a10nsp_if->stats.stream_loss);
}
if(ctx->stats.session_traffic_flows) {
wprintw(stats_win, " Tx Session Packets %10lu |%7lu PPS\n",
a10nsp_if->stats.session_ipv4_tx, a10nsp_if->stats.rate_session_ipv4_tx.avg);
wprintw(stats_win, " Rx Session Packets %10lu |%7lu PPS %10lu Loss\n",
a10nsp_if->stats.session_ipv4_rx, a10nsp_if->stats.rate_session_ipv4_rx.avg,
a10nsp_if->stats.session_ipv4_loss);
}
}
VISIBLE(access_if) {
wprintw(stats_win, "\nAccess Interface (");
for(i = 0; i < ctx->interfaces.access_if_count; i++) {
if(i == g_access_if_selected) {
wattron(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, " %s", ctx->interfaces.access_if[i]->name);
wattroff(stats_win, COLOR_PAIR(COLOR_GREEN));
} else {
wprintw(stats_win, " %s", ctx->interfaces.access_if[i]->name);
}
}
wprintw(stats_win, " )\n Tx Packets %10lu |%7lu PPS %10lu Kbps\n",
access_if->stats.packets_tx, access_if->stats.rate_packets_tx.avg,
access_if->stats.rate_bytes_tx.avg * 8 / 1000);
wprintw(stats_win, " Rx Packets %10lu |%7lu PPS %10lu Kbps\n",
access_if->stats.packets_rx, access_if->stats.rate_packets_rx.avg,
access_if->stats.rate_bytes_rx.avg * 8 / 1000);
if(ctx->stats.stream_traffic_flows) {
wprintw(stats_win, " Tx Stream Packets %10lu |%7lu PPS\n",
access_if->stats.stream_tx, access_if->stats.rate_stream_tx.avg);
wprintw(stats_win, " Rx Stream Packets %10lu |%7lu PPS %10lu Loss\n",
access_if->stats.stream_rx, access_if->stats.rate_stream_rx.avg,
access_if->stats.stream_loss);
}
if(ctx->stats.session_traffic_flows) {
wprintw(stats_win, " Tx Session Packets %10lu |%7lu PPS\n",
access_if->stats.session_ipv4_tx, access_if->stats.rate_session_ipv4_tx.avg);
wprintw(stats_win, " Rx Session Packets %10lu |%7lu PPS %10lu Loss %lu Wrong Session\n",
access_if->stats.session_ipv4_rx, access_if->stats.rate_session_ipv4_rx.avg,
access_if->stats.session_ipv4_loss, access_if->stats.session_ipv4_wrong_session);
wprintw(stats_win, " Tx Session Packets IPv6 %10lu |%7lu PPS\n",
access_if->stats.session_ipv6_tx, access_if->stats.rate_session_ipv6_tx.avg);
wprintw(stats_win, " Rx Session Packets IPv6 %10lu |%7lu PPS %10lu Loss %lu Wrong Session\n",
access_if->stats.session_ipv6_rx, access_if->stats.rate_session_ipv6_rx.avg,
access_if->stats.session_ipv6_loss, access_if->stats.session_ipv6_wrong_session);
wprintw(stats_win, " Tx Session Packets IPv6PD %10lu |%7lu PPS\n",
access_if->stats.session_ipv6pd_tx, access_if->stats.rate_session_ipv6pd_tx.avg);
wprintw(stats_win, " Rx Session Packets IPv6PD %10lu |%7lu PPS %10lu Loss %lu Wrong Session\n",
access_if->stats.session_ipv6pd_rx, access_if->stats.rate_session_ipv6pd_rx.avg,
access_if->stats.session_ipv6pd_loss, access_if->stats.session_ipv6pd_wrong_session);
}
wprintw(stats_win, " Rx Multicast Packets %10lu |%7lu PPS %10lu Loss\n",
access_if->stats.mc_rx, access_if->stats.rate_mc_rx.avg,
access_if->stats.mc_loss);
}
} else if(g_view_selected == UI_VIEW_ACCESS_IF_STATS) {
if(access_if) {
wprintw(stats_win, "\nAccess Interface Protocol Stats (");
for(i = 0; i < ctx->interfaces.access_if_count; i++) {
if(i == g_access_if_selected) {
wattron(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, " %s", ctx->interfaces.access_if[i]->name);
wattroff(stats_win, COLOR_PAIR(COLOR_GREEN));
} else {
wprintw(stats_win, " %s", ctx->interfaces.access_if[i]->name);
}
}
wprintw(stats_win, " )\n");
wprintw(stats_win, "\nPacket Stats\n");
wprintw(stats_win, " ARP TX: %10u RX: %10u\n", access_if->stats.arp_tx, access_if->stats.arp_rx);
wprintw(stats_win, " PADI TX: %10u RX: %10u\n", access_if->stats.padi_tx, 0);
wprintw(stats_win, " PADO TX: %10u RX: %10u\n", 0, access_if->stats.pado_rx);
wprintw(stats_win, " PADR TX: %10u RX: %10u\n", access_if->stats.padr_tx, 0);
wprintw(stats_win, " PADS TX: %10u RX: %10u\n", 0, access_if->stats.pads_rx);
wprintw(stats_win, " PADT TX: %10u RX: %10u\n", access_if->stats.padt_tx, access_if->stats.padt_rx);
wprintw(stats_win, " LCP TX: %10u RX: %10u\n", access_if->stats.lcp_tx, access_if->stats.lcp_rx);
wprintw(stats_win, " PAP TX: %10u RX: %10u\n", access_if->stats.pap_tx, access_if->stats.pap_rx);
wprintw(stats_win, " CHAP TX: %10u RX: %10u\n", access_if->stats.chap_tx, access_if->stats.chap_rx);
wprintw(stats_win, " IPCP TX: %10u RX: %10u\n", access_if->stats.ipcp_tx, access_if->stats.ipcp_rx);
wprintw(stats_win, " IP6CP TX: %10u RX: %10u\n", access_if->stats.ip6cp_tx, access_if->stats.ip6cp_rx);
wprintw(stats_win, " IGMP TX: %10u RX: %10u\n", access_if->stats.igmp_tx, access_if->stats.igmp_rx);
wprintw(stats_win, " ICMP TX: %10u RX: %10u\n", access_if->stats.icmp_tx, access_if->stats.icmp_rx);
wprintw(stats_win, " DHCP TX: %10u RX: %10u\n", access_if->stats.dhcp_tx, access_if->stats.dhcp_rx);
wprintw(stats_win, " DHCPv6 TX: %10u RX: %10u\n", access_if->stats.dhcpv6_tx, access_if->stats.dhcpv6_rx);
wprintw(stats_win, " ICMPv6 TX: %10u RX: %10u\n", access_if->stats.icmpv6_tx, access_if->stats.icmpv6_rx);
wprintw(stats_win, "\nTimeout Stats\n");
wprintw(stats_win, " LCP Echo Request: %10u\n", access_if->stats.lcp_echo_timeout);
wprintw(stats_win, " LCP Request: %10u\n", access_if->stats.lcp_timeout);
wprintw(stats_win, " IPCP Request: %10u\n", access_if->stats.ipcp_timeout);
wprintw(stats_win, " IP6CP Request: %10u\n", access_if->stats.ip6cp_timeout);
wprintw(stats_win, " PAP: %10u\n", access_if->stats.pap_timeout);
wprintw(stats_win, " CHAP: %10u\n", access_if->stats.chap_timeout);
wprintw(stats_win, " DHCP Request: %10u\n", access_if->stats.dhcp_timeout);
wprintw(stats_win, " DHCPv6 Request: %10u\n", access_if->stats.dhcpv6_timeout);
wprintw(stats_win, " ICMPv6 RS: %10u\n", access_if->stats.icmpv6_rs_timeout);
} else {
wprintw(stats_win, "\nAccess Interface Protocol Stats");
}
} else if(g_view_selected == UI_VIEW_SESSION) {
wprintw(stats_win, "\nSession and Streams ( Session-Id: ", g_session_selected);
wattron(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, "%u", g_session_selected);
wattroff(stats_win, COLOR_PAIR(COLOR_GREEN));
wprintw(stats_win, " )\n", g_session_selected);
session = bbl_session_get(ctx, g_session_selected);
if(session) {
wprintw(stats_win, "\n State: %s \n", session_state_string(session->session_state));
if(session->username) {
wprintw(stats_win, " Username: %s \n", session->username);
}
if(session->agent_remote_id) {
wprintw(stats_win, " ARI: %s \n", session->agent_remote_id);
}
if(session->agent_remote_id) {
wprintw(stats_win, " ACI: %s \n", session->agent_circuit_id);
}
if(session->connections_status_message || session->reply_message) {
wprintw(stats_win, "\n");
if(session->reply_message) {
wprintw(stats_win, " Reply-Message: %s \n", session->reply_message);
}
if(session->connections_status_message) {
wprintw(stats_win, " Connection-Status-Message: %s \n", session->connections_status_message);
}
}
wprintw(stats_win, "\n Access Client Interface\n");
wprintw(stats_win, " Tx Packets %10lu | %7lu PPS | %10lu Kbps\n",
session->stats.packets_tx, session->stats.rate_packets_tx.avg,
session->stats.rate_bytes_tx.avg * 8 / 1000);
wprintw(stats_win, " Rx Packets %10lu | %7lu PPS | %10lu Kbps\n",
session->stats.packets_rx, session->stats.rate_packets_rx.avg,
session->stats.rate_bytes_rx.avg * 8 / 1000);
if(session->stream) {
wprintw(stats_win, "\n Stream | Direction | Tx PPS | Tx Kbps | Rx PPS | Rx Kbps | Loss\n");
wprintw(stats_win, " -------------------------------------------------------------------------------------\n");
uint64_t tx_kbps;
uint64_t rx_kbps;
uint64_t stream_sum_up_tx_pps = 0;
uint64_t stream_sum_up_tx_kbps = 0;
uint64_t stream_sum_up_rx_pps = 0;
uint64_t stream_sum_up_rx_kbps = 0;
uint64_t stream_sum_up_loss = 0;
uint64_t stream_sum_down_tx_pps = 0;
uint64_t stream_sum_down_rx_pps = 0;
uint64_t stream_sum_down_tx_kbps = 0;
uint64_t stream_sum_down_rx_kbps = 0;
uint64_t stream_sum_down_loss = 0;
bbl_stream *stream = session->stream;
i = 0;
while(stream) {
tx_kbps = stream->rate_packets_tx.avg * stream->tx_len * 8 / 1000;
rx_kbps = stream->rate_packets_rx.avg * stream->rx_len * 8 / 1000;
if(i >= stats_win_postion && i < 16+stats_win_postion) {
wprintw(stats_win, " %-16.16s | %-9.9s | %7lu | %10lu | %7lu | %10lu | %8lu\n", stream->config->name,
stream->direction == STREAM_DIRECTION_UP ? "up" : "down",
stream->rate_packets_tx.avg, tx_kbps, stream->rate_packets_rx.avg, rx_kbps, stream->loss);
} else if (i == 16+stats_win_postion) {
wprintw(stats_win, " ...\n");
}
i++;
if(stream->direction == STREAM_DIRECTION_UP) {
stream_sum_up_tx_pps += stream->rate_packets_tx.avg;
stream_sum_up_tx_kbps += tx_kbps;
stream_sum_up_rx_pps += stream->rate_packets_rx.avg;
stream_sum_up_rx_kbps += rx_kbps;
stream_sum_up_loss += stream->loss;
} else {
stream_sum_down_tx_pps += stream->rate_packets_tx.avg;
stream_sum_down_tx_kbps += tx_kbps;
stream_sum_down_rx_pps += stream->rate_packets_rx.avg;
stream_sum_down_rx_kbps += rx_kbps;
stream_sum_down_loss += stream->loss;
}
stream = stream->next;
}
wprintw(stats_win, " =====================================================================================\n");
wprintw(stats_win, " SUM | up | %7lu | %10lu | %7lu | %10lu | %8lu\n",
stream_sum_up_tx_pps, stream_sum_up_tx_kbps, stream_sum_up_rx_pps, stream_sum_up_rx_kbps, stream_sum_up_loss);
wprintw(stats_win, " | down | %7lu | %10lu | %7lu | %10lu | %8lu\n",
stream_sum_down_tx_pps, stream_sum_down_tx_kbps, stream_sum_down_rx_pps, stream_sum_down_rx_kbps, stream_sum_down_loss);
}
}
}
wrefresh(stats_win);
}
/*
* Curses init.
*/
void
bbl_init_curses (bbl_ctx_s *ctx)
{
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
/* Stats window */
stats_win = newwin(LINES, STATS_WIN_SIZE, 0, 0);
stats_win_postion = 0;
/* Log window */
log_win = newwin(LINES, COLS-STATS_WIN_SIZE, 0, STATS_WIN_SIZE);
scrollok(log_win, TRUE);
start_color();
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
init_pair(3, COLOR_BLACK, COLOR_CYAN);
init_pair(4, COLOR_BLACK, COLOR_BLUE);
curs_set(0); /* cursor off */
refresh();
timeout(0);
bbl_init_stats_win(ctx);
wrefresh(stats_win);
timer_add_periodic(&ctx->timer_root, &ctx->stats_timer, "Statistics Timer",
0, 100 * MSEC, ctx, &bbl_stats_job);
timer_add_periodic(&ctx->timer_root, &ctx->keyboard_timer, "Keyboard Reader",
0, 100 * MSEC, ctx, &bbl_read_key_job);
g_interactive = true;
}