diff --git a/code/bngblaster/src/bbl.h b/code/bngblaster/src/bbl.h index fe777c9d..23c6b27a 100644 --- a/code/bngblaster/src/bbl.h +++ b/code/bngblaster/src/bbl.h @@ -26,6 +26,7 @@ #include "bgp/bgp_def.h" #include "isis/isis_def.h" +#include "bbl_ctrl.h" #include "bbl_stats.h" #include "bbl_access_line.h" #include "bbl_config.h" @@ -39,6 +40,8 @@ #include "bbl_network.h" #include "bbl_a10nsp.h" #include "bbl_li.h" +#include "bbl_igmp.h" +#include "bbl_cfm.h" #include "bbl_tcp.h" #include "io/io.h" diff --git a/code/bngblaster/src/bbl_a10nsp.c b/code/bngblaster/src/bbl_a10nsp.c index dd5d927b..d6c3e722 100644 --- a/code/bngblaster/src/bbl_a10nsp.c +++ b/code/bngblaster/src/bbl_a10nsp.c @@ -547,4 +547,71 @@ bbl_a10nsp_rx_handler(bbl_a10nsp_interface_s *interface, if(session) { bbl_a10nsp_rx(interface, session, eth); } +} + +static json_t * +bbl_a10nsp_interface_json(bbl_a10nsp_interface_s *interface) +{ + return json_pack("{ss si ss si si si si si si si si si si si si si si si si si si si si si si si si si si si si}", + "name", interface->name, + "ifindex", interface->ifindex, + "type", "a10nsp", + "tx-packets", interface->stats.packets_tx, + "tx-bytes", interface->stats.bytes_tx, + "tx-pps", interface->stats.rate_packets_tx.avg, + "tx-kbps", interface->stats.rate_bytes_tx.avg * 8 / 1000, + "rx-packets", interface->stats.packets_rx, + "rx-bytes", interface->stats.bytes_rx, + "rx-pps", interface->stats.rate_packets_rx.avg, + "rx-kbps", interface->stats.rate_bytes_rx.avg * 8 / 1000, + "tx-packets-session-ipv4", interface->stats.session_ipv4_tx, + "tx-pps-session-ipv4", interface->stats.rate_session_ipv4_tx.avg, + "rx-packets-session-ipv4", interface->stats.session_ipv4_rx, + "rx-pps-session-ipv4", interface->stats.rate_session_ipv4_rx.avg, + "rx-loss-packets-session-ipv4", interface->stats.session_ipv4_loss, + "tx-packets-session-ipv6", interface->stats.session_ipv6_tx, + "tx-pps-session-ipv6", interface->stats.rate_session_ipv6_tx.avg, + "rx-packets-session-ipv6", interface->stats.session_ipv6_rx, + "rx-pps-session-ipv6", interface->stats.rate_session_ipv6_rx.avg, + "rx-loss-packets-session-ipv6", interface->stats.session_ipv6_loss, + "tx-packets-session-ipv6pd", interface->stats.session_ipv6pd_tx, + "tx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_tx.avg, + "rx-packets-session-ipv6pd", interface->stats.session_ipv6pd_rx, + "rx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_rx.avg, + "rx-loss-packets-session-ipv6pd", interface->stats.session_ipv6pd_loss, + "tx-packets-streams", interface->stats.stream_tx, + "tx-pps-streams", interface->stats.rate_stream_tx.avg, + "rx-packets-streams", interface->stats.stream_rx, + "rx-pps-streams", interface->stats.rate_stream_rx.avg, + "rx-loss-packets-streams", interface->stats.stream_loss + ); +} + +/* Control Socket Commands */ + +int +bbl_a10nsp_ctrl_interfaces(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root, *interfaces; + bbl_interface_s *interface; + + interfaces = json_array(); + CIRCLEQ_FOREACH(interface, &g_ctx->interface_qhead, interface_qnode) { + if(interface->a10nsp) { + json_array_append(interfaces, bbl_a10nsp_interface_json(interface->a10nsp)); + } + } + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "a10nsp-interfaces", interfaces); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(interfaces); + } + return result; } \ No newline at end of file diff --git a/code/bngblaster/src/bbl_a10nsp.h b/code/bngblaster/src/bbl_a10nsp.h index 5f8a667e..a6b76d72 100644 --- a/code/bngblaster/src/bbl_a10nsp.h +++ b/code/bngblaster/src/bbl_a10nsp.h @@ -111,4 +111,7 @@ void bbl_a10nsp_rx_handler(bbl_a10nsp_interface_s *interface, bbl_ethernet_header_s *eth); -#endif +int +bbl_a10nsp_ctrl_interfaces(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/bbl_access.c b/code/bngblaster/src/bbl_access.c index d25e807f..e074dc70 100644 --- a/code/bngblaster/src/bbl_access.c +++ b/code/bngblaster/src/bbl_access.c @@ -1846,4 +1846,74 @@ bbl_access_rx_handler(bbl_access_interface_s *interface, } } } +} + +static json_t * +bbl_access_interface_json(bbl_access_interface_s *interface) +{ + return json_pack("{ss si ss si si si si si si si si si si si si si si si si si si si si si si si si si si si si si si si}", + "name", interface->name, + "ifindex", interface->ifindex, + "type", "access", + "tx-packets", interface->stats.packets_tx, + "tx-bytes", interface->stats.bytes_tx, + "tx-pps", interface->stats.rate_packets_tx.avg, + "tx-kbps", interface->stats.rate_bytes_tx.avg * 8 / 1000, + "rx-packets", interface->stats.packets_rx, + "rx-bytes", interface->stats.bytes_rx, + "rx-pps", interface->stats.rate_packets_rx.avg, + "rx-kbps", interface->stats.rate_bytes_rx.avg * 8 / 1000, + "rx-packets-multicast", interface->stats.mc_rx, + "rx-pps-multicast", interface->stats.rate_mc_rx.avg, + "rx-loss-packets-multicast", interface->stats.mc_loss, + "tx-packets-session-ipv4", interface->stats.session_ipv4_tx, + "tx-pps-session-ipv4", interface->stats.rate_session_ipv4_tx.avg, + "rx-packets-session-ipv4", interface->stats.session_ipv4_rx, + "rx-pps-session-ipv4", interface->stats.rate_session_ipv4_rx.avg, + "rx-loss-packets-session-ipv4", interface->stats.session_ipv4_loss, + "tx-packets-session-ipv6", interface->stats.session_ipv6_tx, + "tx-pps-session-ipv6", interface->stats.rate_session_ipv6_tx.avg, + "rx-packets-session-ipv6", interface->stats.session_ipv6_rx, + "rx-pps-session-ipv6", interface->stats.rate_session_ipv6_rx.avg, + "rx-loss-packets-session-ipv6", interface->stats.session_ipv6_loss, + "tx-packets-session-ipv6pd", interface->stats.session_ipv6pd_tx, + "tx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_tx.avg, + "rx-packets-session-ipv6pd", interface->stats.session_ipv6pd_rx, + "rx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_rx.avg, + "rx-loss-packets-session-ipv6pd", interface->stats.session_ipv6pd_loss, + "tx-packets-streams", interface->stats.stream_tx, + "tx-pps-streams", interface->stats.rate_stream_tx.avg, + "rx-packets-streams", interface->stats.stream_rx, + "rx-pps-streams", interface->stats.rate_stream_rx.avg, + "rx-loss-packets-streams", interface->stats.stream_loss + ); +} + +/* Control Socket Commands */ + +int +bbl_access_ctrl_interfaces(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root, *interfaces; + bbl_interface_s *interface; + + interfaces = json_array(); + CIRCLEQ_FOREACH(interface, &g_ctx->interface_qhead, interface_qnode) { + if(interface->access) { + json_array_append(interfaces, bbl_access_interface_json(interface->access)); + } + } + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "access-interfaces", interfaces); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(interfaces); + } + return result; } \ No newline at end of file diff --git a/code/bngblaster/src/bbl_access.h b/code/bngblaster/src/bbl_access.h index f8511b87..6db94451 100644 --- a/code/bngblaster/src/bbl_access.h +++ b/code/bngblaster/src/bbl_access.h @@ -140,4 +140,7 @@ void bbl_access_rx_handler(bbl_access_interface_s *interface, bbl_ethernet_header_s *eth); +int +bbl_access_ctrl_interfaces(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + #endif diff --git a/code/bngblaster/src/bbl_cfm.c b/code/bngblaster/src/bbl_cfm.c new file mode 100644 index 00000000..70c1b6a4 --- /dev/null +++ b/code/bngblaster/src/bbl_cfm.c @@ -0,0 +1,83 @@ +/* + * BNG Blaster (BBL) - CFM Functions + * + * Christian Giese, October 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "bbl.h" + +static int +bbl_cfm_ctrl_cc_start_stop(int fd, uint32_t session_id, bool status) +{ + bbl_session_s *session; + uint32_t i; + if(session_id) { + session = bbl_session_get(session_id); + if(session) { + session->cfm_cc = status; + return bbl_ctrl_status(fd, "ok", 200, NULL); + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } + } else { + /* Iterate over all sessions */ + for(i = 0; i < g_ctx->sessions; i++) { + session = &g_ctx->session_list[i]; + if(session) { + session->cfm_cc = status; + } + } + return bbl_ctrl_status(fd, "ok", 200, NULL); + } +} + +int +bbl_cfm_ctrl_cc_start(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_cfm_ctrl_cc_start_stop(fd, session_id, true); +} + +int +bbl_cfm_ctrl_cc_stop(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_cfm_ctrl_cc_start_stop(fd, session_id, false); +} + +static int +bbl_cfm_ctrl_cc_rdi(int fd, uint32_t session_id, bool status) +{ + bbl_session_s *session; + uint32_t i; + if(session_id) { + session = bbl_session_get(session_id); + if(session) { + session->cfm_rdi = status; + return bbl_ctrl_status(fd, "ok", 200, NULL); + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } + } else { + /* Iterate over all sessions */ + for(i = 0; i < g_ctx->sessions; i++) { + session = &g_ctx->session_list[i]; + if(session) { + session->cfm_rdi = status; + } + } + return bbl_ctrl_status(fd, "ok", 200, NULL); + } +} + +int +bbl_cfm_ctrl_cc_rdi_on(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_cfm_ctrl_cc_rdi(fd, session_id, true); +} + +int +bbl_cfm_ctrl_cc_rdi_off(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_cfm_ctrl_cc_rdi(fd, session_id, false); +} \ No newline at end of file diff --git a/code/bngblaster/src/bbl_cfm.h b/code/bngblaster/src/bbl_cfm.h new file mode 100644 index 00000000..51dfbc0b --- /dev/null +++ b/code/bngblaster/src/bbl_cfm.h @@ -0,0 +1,25 @@ +/* + * BNG Blaster (BBL) - CFM Functions + * + * Christian Giese, October 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __BBL_CFM_H__ +#define __BBL_CFM_H__ + +int +bbl_cfm_ctrl_cc_start(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_cfm_ctrl_cc_stop(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_cfm_ctrl_cc_rdi_on(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_cfm_ctrl_cc_rdi_off(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/bbl_ctrl.c b/code/bngblaster/src/bbl_ctrl.c index 14773573..ee330d0d 100644 --- a/code/bngblaster/src/bbl_ctrl.c +++ b/code/bngblaster/src/bbl_ctrl.c @@ -6,7 +6,6 @@ * Copyright (C) 2020-2022, RtBrick, Inc. * SPDX-License-Identifier: BSD-3-Clause */ - #include #include #include @@ -28,22 +27,6 @@ #define BACKLOG 4 -extern volatile bool g_teardown; -extern volatile bool g_teardown_request; -extern volatile bool g_monkey; - -typedef int callback_function(int fd, uint32_t session_id, json_t* arguments); - -static char * -string_or_na(char *string) -{ - if(string) { - return string; - } else { - return "N/A"; - } -} - int bbl_ctrl_status(int fd, const char *status, uint32_t code, const char *message) { @@ -57,1559 +40,34 @@ bbl_ctrl_status(int fd, const char *status, uint32_t code, const char *message) } int -bbl_ctrl_multicast_traffic_start(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) +bbl_ctrl_multicast_traffic_start(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) { g_ctx->multicast_traffic = true; return bbl_ctrl_status(fd, "ok", 200, NULL); } int -bbl_ctrl_multicast_traffic_stop(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) +bbl_ctrl_multicast_traffic_stop(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) { g_ctx->multicast_traffic = false; return bbl_ctrl_status(fd, "ok", 200, NULL); } int -bbl_ctrl_session_traffic_stats(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - int result = 0; - json_t *root = json_pack("{ss si s{si si}}", - "status", "ok", - "code", 200, - "session-traffic", - "total-flows", g_ctx->stats.session_traffic_flows, - "verified-flows", g_ctx->stats.session_traffic_flows_verified); - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } - return result; -} - -int -bbl_ctrl_session_traffic(int fd, uint32_t session_id, bool status) -{ - bbl_session_s *session; - uint32_t i; - if(session_id) { - session = bbl_session_get(session_id); - if(session) { - session->session_traffic.active = status; - return bbl_ctrl_status(fd, "ok", 200, NULL); - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } - } else { - /* Iterate over all sessions */ - for(i = 0; i < g_ctx->sessions; i++) { - session = &g_ctx->session_list[i]; - if(session) { - session->session_traffic.active = status; - } - } - return bbl_ctrl_status(fd, "ok", 200, NULL); - } -} - -int -bbl_ctrl_session_traffic_start(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_session_traffic(fd, session_id, true); -} - -int -bbl_ctrl_session_traffic_stop(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_session_traffic(fd, session_id, false); -} - -int -bbl_ctrl_igmp_join(int fd, uint32_t session_id, json_t* arguments) { - bbl_session_s *session; - const char *s; - uint32_t group_address = 0; - uint32_t source1 = 0; - uint32_t source2 = 0; - uint32_t source3 = 0; - bbl_igmp_group_s *group = NULL; - int i; - - if(session_id == 0) { - /* session-id is mandatory */ - return bbl_ctrl_status(fd, "error", 400, "missing session-id"); - } - /* Unpack further arguments */ - if (json_unpack(arguments, "{s:s}", "group", &s) == 0) { - if(!inet_pton(AF_INET, s, &group_address)) { - return bbl_ctrl_status(fd, "error", 400, "invalid group address"); - } - } else { - return bbl_ctrl_status(fd, "error", 400, "missing group address"); - } - if (json_unpack(arguments, "{s:s}", "source1", &s) == 0) { - if(!inet_pton(AF_INET, s, &source1)) { - return bbl_ctrl_status(fd, "error", 400, "invalid source1 address"); - } - } - if (json_unpack(arguments, "{s:s}", "source2", &s) == 0) { - if(!inet_pton(AF_INET, s, &source2)) { - return bbl_ctrl_status(fd, "error", 400, "invalid source2 address"); - } - } - if (json_unpack(arguments, "{s:s}", "source3", &s) == 0) { - if(!inet_pton(AF_INET, s, &source3)) { - return bbl_ctrl_status(fd, "error", 400, "invalid source3 address"); - } - } - - /* Search session */ - session = bbl_session_get(session_id); - if(session) { - /* Search for free slot ... */ - for(i=0; i < IGMP_MAX_GROUPS; i++) { - if(!session->igmp_groups[i].zapping) { - if (session->igmp_groups[i].group == group_address) { - group = &session->igmp_groups[i]; - if(group->state == IGMP_GROUP_IDLE) { - break; - } else { - return bbl_ctrl_status(fd, "error", 409, "group already exists"); - } - } else if(session->igmp_groups[i].state == IGMP_GROUP_IDLE) { - group = &session->igmp_groups[i]; - } - } - } - if(!group) { - return bbl_ctrl_status(fd, "error", 409, "no igmp group slot available"); - } - /* Join group... */ - memset(group, 0x0, sizeof(bbl_igmp_group_s)); - group->group = group_address; - if(source1) group->source[0] = source1; - if(source2) group->source[1] = source2; - if(source3) group->source[2] = source3; - group->state = IGMP_GROUP_JOINING; - group->robustness_count = session->igmp_robustness; - group->send = true; - session->send_requests |= BBL_SEND_IGMP; - bbl_session_tx_qnode_insert(session); - LOG(IGMP, "IGMP (ID: %u) join %s\n", - session->session_id, format_ipv4_address(&group->group)); - return bbl_ctrl_status(fd, "ok", 200, NULL); - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } -} - -int -bbl_ctrl_igmp_join_iter(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments) -{ - bbl_session_s *session; - const char *s; - uint32_t group_address = 0; - uint32_t group_iter = 1; - int group_count = 0; - bbl_igmp_group_s *group = NULL; - uint32_t source1 = 0; - uint32_t source2 = 0; - uint32_t source3 = 0; - uint32_t i, i2; - uint32_t join_count; - - /* Unpack group arguments */ - if (json_unpack(arguments, "{s:s}", "group", &s) == 0) { - if(!inet_pton(AF_INET, s, &group_address)) { - return bbl_ctrl_status(fd, "error", 400, "invalid group address"); - } - } else { - return bbl_ctrl_status(fd, "error", 400, "missing group address"); - } - if (json_unpack(arguments, "{s:d}", "group-iter", &s) == 0) { - if(!inet_pton(AF_INET, s, &group_iter)) { - return bbl_ctrl_status(fd, "error", 400, "invalid group-iter"); - } - group_iter = be32toh(group_iter); - } - json_unpack(arguments, "{s:i}", "group-count", &group_count); - if(group_count < 1) group_count = 1; - - /* Unpack source address arguments */ - if (json_unpack(arguments, "{s:s}", "source1", &s) == 0) { - if(!inet_pton(AF_INET, s, &source1)) { - return bbl_ctrl_status(fd, "error", 400, "invalid source1 address"); - } - } - if (json_unpack(arguments, "{s:s}", "source2", &s) == 0) { - if(!inet_pton(AF_INET, s, &source2)) { - return bbl_ctrl_status(fd, "error", 400, "invalid source2 address"); - } - } - if (json_unpack(arguments, "{s:s}", "source3", &s) == 0) { - if(!inet_pton(AF_INET, s, &source3)) { - return bbl_ctrl_status(fd, "error", 400, "invalid source3 address"); - } - } - - while(group_count) { - /* Iterate over all sessions */ - join_count = 0; - for(i = 0; i < g_ctx->sessions; i++) { - session = &g_ctx->session_list[i]; - if(session) { - /* Search for free slot ... */ - for(i2=0; i2 < IGMP_MAX_GROUPS; i2++) { - group = &session->igmp_groups[i2]; - if(group->zapping) { - continue; - } - if(group->group == group_address && - group->state != IGMP_GROUP_IDLE) { - /* Group already exists. */ - group_address = htobe32(be32toh(group_address) + group_iter); - break; - } - if(group->state != IGMP_GROUP_IDLE) { - continue; - } - /* Join group. */ - memset(group, 0x0, sizeof(bbl_igmp_group_s)); - group->group = group_address; - if(source1) group->source[0] = source1; - if(source2) group->source[1] = source2; - if(source3) group->source[2] = source3; - group->state = IGMP_GROUP_JOINING; - group->robustness_count = session->igmp_robustness; - group->send = true; - LOG(IGMP, "IGMP (ID: %u) join %s\n", - session->session_id, format_ipv4_address(&group->group)); - session->send_requests |= BBL_SEND_IGMP; - - join_count++; - if(--group_count == 0) { - return bbl_ctrl_status(fd, "ok", 200, NULL); - }; - /* Get next group address. */ - group_address = htobe32(be32toh(group_address) + group_iter); - break; - } - } - } - /* Prevent infinity loops! */ - if(!join_count) break; - } - return bbl_ctrl_status(fd, "ok", 200, NULL); -} - -int -bbl_ctrl_igmp_leave(int fd, uint32_t session_id, json_t* arguments) -{ - bbl_session_s *session; - const char *s; - uint32_t group_address = 0; - bbl_igmp_group_s *group = NULL; - int i; - - if(session_id == 0) { - /* session-id is mandatory */ - return bbl_ctrl_status(fd, "error", 400, "missing session-id"); - } - /* Unpack further arguments */ - if (json_unpack(arguments, "{s:s}", "group", &s) == 0) { - if(!inet_pton(AF_INET, s, &group_address)) { - return bbl_ctrl_status(fd, "error", 400, "invalid group address"); - } - } else { - return bbl_ctrl_status(fd, "error", 400, "missing group address"); - } - - session = bbl_session_get(session_id); - if(session) { - /* Search for group ... */ - for(i=0; i < IGMP_MAX_GROUPS; i++) { - if (session->igmp_groups[i].group == group_address) { - group = &session->igmp_groups[i]; - break; - } - } - if(!group) { - return bbl_ctrl_status(fd, "warning", 404, "group not found"); - } - if(group->zapping) { - return bbl_ctrl_status(fd, "error", 408, "group used by zapping test"); - } - if(group->state <= IGMP_GROUP_LEAVING) { - return bbl_ctrl_status(fd, "ok", 200, NULL); - } - group->state = IGMP_GROUP_LEAVING; - group->robustness_count = session->igmp_robustness; - group->send = true; - group->leave_tx_time.tv_sec = 0; - group->leave_tx_time.tv_nsec = 0; - group->last_mc_rx_time.tv_sec = 0; - group->last_mc_rx_time.tv_nsec = 0; - session->send_requests |= BBL_SEND_IGMP; - bbl_session_tx_qnode_insert(session); - LOG(IGMP, "IGMP (ID: %u) leave %s\n", - session->session_id, format_ipv4_address(&group->group)); - return bbl_ctrl_status(fd, "ok", 200, NULL); - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } -} - -int -bbl_ctrl_igmp_leave_all(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - bbl_session_s *session; - bbl_igmp_group_s *group = NULL; - uint32_t i, i2; - - /* Iterate over all sessions */ - for(i = 0; i < g_ctx->sessions; i++) { - session = &g_ctx->session_list[i]; - if(session) { - /* Search for group ... */ - for(i2=0; i2 < IGMP_MAX_GROUPS; i2++) { - group = &session->igmp_groups[i2]; - if(group->zapping || group->state <= IGMP_GROUP_LEAVING) { - continue; - } - group->state = IGMP_GROUP_LEAVING; - group->robustness_count = session->igmp_robustness; - group->send = true; - group->leave_tx_time.tv_sec = 0; - group->leave_tx_time.tv_nsec = 0; - group->last_mc_rx_time.tv_sec = 0; - group->last_mc_rx_time.tv_nsec = 0; - LOG(IGMP, "IGMP (ID: %u) leave %s\n", - session->session_id, format_ipv4_address(&group->group)); - session->send_requests |= BBL_SEND_IGMP; - bbl_session_tx_qnode_insert(session); - } - } - } - return bbl_ctrl_status(fd, "ok", 200, NULL); -} - -int -bbl_ctrl_igmp_info(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - int result = 0; - json_t *root, *groups, *record, *sources; - bbl_session_s *session = NULL; - bbl_igmp_group_s *group = NULL; - uint32_t delay = 0; - uint32_t ms; - - struct timespec time_diff; - int i, i2; - - if(session_id == 0) { - /* session-id is mandatory */ - return bbl_ctrl_status(fd, "error", 400, "missing session-id"); - } - - session = bbl_session_get(session_id); - if(session) { - groups = json_array(); - /* Add group informations */ - for(i=0; i < IGMP_MAX_GROUPS; i++) { - group = &session->igmp_groups[i]; - if(group->group) { - sources = json_array(); - for(i2=0; i2 < IGMP_MAX_SOURCES; i2++) { - if(group->source[i2]) { - json_array_append(sources, json_string(format_ipv4_address(&group->source[i2]))); - } - } - record = json_pack("{ss so si si}", - "group", format_ipv4_address(&group->group), - "sources", sources, - "packets", group->packets, - "loss", group->loss); - - switch (group->state) { - case IGMP_GROUP_IDLE: - json_object_set(record, "state", json_string("idle")); - if(group->last_mc_rx_time.tv_sec && group->leave_tx_time.tv_sec) { - timespec_sub(&time_diff, &group->last_mc_rx_time, &group->leave_tx_time); - ms = time_diff.tv_nsec / 1000000; /* convert nanoseconds to milliseconds */ - if(time_diff.tv_nsec % 1000000) ms++; /* simple roundup function */ - delay = (time_diff.tv_sec * 1000) + ms; - json_object_set(record, "leave-delay-ms", json_integer(delay)); - } - break; - case IGMP_GROUP_LEAVING: - json_object_set(record, "state", json_string("leaving")); - break; - case IGMP_GROUP_ACTIVE: - json_object_set(record, "state", json_string("active")); - if(group->first_mc_rx_time.tv_sec) { - timespec_sub(&time_diff, &group->first_mc_rx_time, &group->join_tx_time); - ms = time_diff.tv_nsec / 1000000; /* convert nanoseconds to milliseconds */ - if(time_diff.tv_nsec % 1000000) ms++; /* simple roundup function */ - delay = (time_diff.tv_sec * 1000) + ms; - json_object_set(record, "join-delay-ms", json_integer(delay)); - } - break; - case IGMP_GROUP_JOINING: - json_object_set(record, "state", json_string("joining")); - if(group->first_mc_rx_time.tv_sec) { - timespec_sub(&time_diff, &group->first_mc_rx_time, &group->join_tx_time); - ms = time_diff.tv_nsec / 1000000; /* convert nanoseconds to milliseconds */ - if(time_diff.tv_nsec % 1000000) ms++; /* simple roundup function */ - delay = (time_diff.tv_sec * 1000) + ms; - json_object_set(record, "join-delay-ms", json_integer(delay)); - } - break; - default: - break; - } - json_array_append(groups, record); - } - } - root = json_pack("{ss si so}", - "status", "ok", - "code", 200, - "igmp-groups", groups); - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } else { - result = bbl_ctrl_status(fd, "error", 500, "internal error"); - json_decref(groups); - } - return result; - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } -} - -int -bbl_ctrl_zapping_start(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - g_ctx->zapping = true; - return bbl_ctrl_status(fd, "ok", 200, NULL); -} - -int -bbl_ctrl_zapping_stop(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - g_ctx->zapping = false; - return bbl_ctrl_status(fd, "ok", 200, NULL); -} - -int -bbl_ctrl_zapping_stats(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - int result = 0; - json_t *root; - - bbl_stats_s stats = {0}; - int reset = 0; - - json_unpack(arguments, "{s:b}", "reset", &reset); - bbl_stats_generate_multicast(&stats, reset); - - root = json_pack("{ss si s{si si si si si si si si si si si si si si si si si}}", - "status", "ok", - "code", 200, - "zapping-stats", - "join-delay-ms-min", stats.min_join_delay, - "join-delay-ms-avg", stats.avg_join_delay, - "join-delay-ms-max", stats.max_join_delay, - "join-delay-violations", stats.join_delay_violations, - "join-delay-violations-threshold", g_ctx->config.igmp_max_join_delay, - "join-delay-violations-125ms", stats.join_delay_violations_125ms, - "join-delay-violations-250ms", stats.join_delay_violations_250ms, - "join-delay-violations-500ms", stats.join_delay_violations_500ms, - "join-delay-violations-1s", stats.join_delay_violations_1s, - "join-delay-violations-2s", stats.join_delay_violations_2s, - "join-count", stats.zapping_join_count, - "leave-delay-ms-min", stats.min_leave_delay, - "leave-delay-ms-avg", stats.avg_leave_delay, - "leave-delay-ms-max", stats.max_leave_delay, - "leave-count", stats.zapping_leave_count, - "multicast-packets-overlap", stats.mc_old_rx_after_first_new, - "multicast-not-received", stats.mc_not_received); - - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } else { - result = bbl_ctrl_status(fd, "error", 500, "internal error"); - } - return result; -} - -int -bbl_ctrl_session_counters(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - int result = 0; - json_t *root = json_pack("{ss si s{si si si si si si si si si si si si si si sf sf sf sf si si si si}}", - "status", "ok", - "code", 200, - "session-counters", - "sessions", g_ctx->config.sessions, - "sessions-pppoe", g_ctx->sessions_pppoe, - "sessions-ipoe", g_ctx->sessions_ipoe, - "sessions-established", g_ctx->sessions_established, - "sessions-established-max", g_ctx->sessions_established_max, - "sessions-terminated", g_ctx->sessions_terminated, - "sessions-flapped", g_ctx->sessions_flapped, - "dhcp-sessions", g_ctx->dhcp_requested, - "dhcp-sessions-established", g_ctx->dhcp_established, - "dhcp-sessions-established-max", g_ctx->dhcp_established_max, - "dhcpv6-sessions", g_ctx->dhcpv6_requested, - "dhcpv6-sessions-established", g_ctx->dhcpv6_established, - "dhcpv6-sessions-established-max", g_ctx->dhcpv6_established_max, - "setup-time", g_ctx->stats.setup_time, - "setup-rate", g_ctx->stats.cps, - "setup-rate-min", g_ctx->stats.cps_min, - "setup-rate-avg", g_ctx->stats.cps_avg, - "setup-rate-max", g_ctx->stats.cps_max, - "session-traffic-flows", g_ctx->stats.session_traffic_flows, - "session-traffic-flows-verified", g_ctx->stats.session_traffic_flows_verified, - "stream-traffic-flows", g_ctx->stats.stream_traffic_flows, - "stream-traffic-flows-verified", g_ctx->stats.stream_traffic_flows_verified - ); - - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } - return result; -} - -int -bbl_ctrl_session_info(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - int result = 0; - json_t *root; - json_t *session_json; - bbl_session_s *session; - - if(session_id == 0) { - /* session-id is mandatory */ - return bbl_ctrl_status(fd, "error", 400, "missing session-id"); - } - - session = bbl_session_get(session_id); - if(session) { - session_json = bbl_session_json(session); - if(!session_json) { - return bbl_ctrl_status(fd, "error", 500, "internal error"); - } - - root = json_pack("{ss si so*}", - "status", "ok", - "code", 200, - "session-info", session_json); - - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } else { - result = bbl_ctrl_status(fd, "error", 500, "internal error"); - json_decref(session_json); - } - return result; - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } -} - -int -bbl_ctrl_session_start(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - bbl_session_s *session; - - if(g_teardown) { - return bbl_ctrl_status(fd, "error", 405, "teardown"); - } - - if(session_id == 0) { - /* session-id is mandatory */ - return bbl_ctrl_status(fd, "error", 400, "missing session-id"); - } - - session = bbl_session_get(session_id); - if(session) { - if(session->session_state == BBL_TERMINATED && - session->reconnect_delay == 0) { - g_ctx->sessions_flapped++; - session->stats.flapped++; - session->session_state = BBL_IDLE; - bbl_session_reset(session); - if(g_ctx->sessions_terminated) { - g_ctx->sessions_terminated--; - } - } else if(session->session_state != BBL_IDLE || - CIRCLEQ_NEXT(session, session_idle_qnode) || - CIRCLEQ_PREV(session, session_idle_qnode)) { - return bbl_ctrl_status(fd, "error", 405, "wrong session state"); - } - CIRCLEQ_INSERT_TAIL(&g_ctx->sessions_idle_qhead, session, session_idle_qnode); - return bbl_ctrl_status(fd, "ok", 200, NULL); - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } -} - -static json_t * -bbl_ctrl_network_interface_json(bbl_network_interface_s *interface) -{ - return json_pack("{ss si ss si si si si si si si si si si si si si si si si si si si si si si si si si si si si si si}", - "name", interface->name, - "ifindex", interface->ifindex, - "type", "network", - "tx-packets", interface->stats.packets_tx, - "tx-bytes", interface->stats.bytes_tx, - "tx-pps", interface->stats.rate_packets_tx.avg, - "tx-kbps", interface->stats.rate_bytes_tx.avg * 8 / 1000, - "rx-packets", interface->stats.packets_rx, - "rx-bytes", interface->stats.bytes_rx, - "rx-pps", interface->stats.rate_packets_rx.avg, - "rx-kbps", interface->stats.rate_bytes_rx.avg * 8 / 1000, - "tx-packets-multicast", interface->stats.mc_tx, - "tx-pps-multicast", interface->stats.rate_mc_tx.avg, - "tx-packets-session-ipv4", interface->stats.session_ipv4_tx, - "tx-pps-session-ipv4", interface->stats.rate_session_ipv4_tx.avg, - "rx-packets-session-ipv4", interface->stats.session_ipv4_rx, - "rx-pps-session-ipv4", interface->stats.rate_session_ipv4_rx.avg, - "loss-packets-session-ipv4", interface->stats.session_ipv4_loss, - "tx-packets-session-ipv6", interface->stats.session_ipv6_tx, - "tx-pps-session-ipv6", interface->stats.rate_session_ipv6_tx.avg, - "rx-packets-session-ipv6", interface->stats.session_ipv6_rx, - "rx-pps-session-ipv6", interface->stats.rate_session_ipv6_rx.avg, - "loss-packets-session-ipv6", interface->stats.session_ipv6_loss, - "tx-packets-session-ipv6pd", interface->stats.session_ipv6pd_tx, - "tx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_tx.avg, - "rx-packets-session-ipv6pd", interface->stats.session_ipv6pd_rx, - "rx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_rx.avg, - "loss-packets-session-ipv6pd", interface->stats.session_ipv6pd_loss, - "tx-packets-streams", interface->stats.stream_tx, - "tx-pps-streams", interface->stats.rate_stream_tx.avg, - "rx-packets-streams", interface->stats.stream_rx, - "rx-pps-streams", interface->stats.rate_stream_rx.avg, - "loss-packets-streams", interface->stats.stream_loss - ); -} - -static json_t * -bbl_ctrl_access_interface_json(bbl_access_interface_s *interface) -{ - return json_pack("{ss si ss si si si si si si si si si si si si si si si si si si si si si si si si si si si si si si si}", - "name", interface->name, - "ifindex", interface->ifindex, - "type", "access", - "tx-packets", interface->stats.packets_tx, - "tx-bytes", interface->stats.bytes_tx, - "tx-pps", interface->stats.rate_packets_tx.avg, - "tx-kbps", interface->stats.rate_bytes_tx.avg * 8 / 1000, - "rx-packets", interface->stats.packets_rx, - "rx-bytes", interface->stats.bytes_rx, - "rx-pps", interface->stats.rate_packets_rx.avg, - "rx-kbps", interface->stats.rate_bytes_rx.avg * 8 / 1000, - "rx-packets-multicast", interface->stats.mc_rx, - "rx-pps-multicast", interface->stats.rate_mc_rx.avg, - "loss-packets-multicast", interface->stats.mc_loss, - "tx-packets-session-ipv4", interface->stats.session_ipv4_tx, - "tx-pps-session-ipv4", interface->stats.rate_session_ipv4_tx.avg, - "rx-packets-session-ipv4", interface->stats.session_ipv4_rx, - "rx-pps-session-ipv4", interface->stats.rate_session_ipv4_rx.avg, - "loss-packets-session-ipv4", interface->stats.session_ipv4_loss, - "tx-packets-session-ipv6", interface->stats.session_ipv6_tx, - "tx-pps-session-ipv6", interface->stats.rate_session_ipv6_tx.avg, - "rx-packets-session-ipv6", interface->stats.session_ipv6_rx, - "rx-pps-session-ipv6", interface->stats.rate_session_ipv6_rx.avg, - "loss-packets-session-ipv6", interface->stats.session_ipv6_loss, - "tx-packets-session-ipv6pd", interface->stats.session_ipv6pd_tx, - "tx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_tx.avg, - "rx-packets-session-ipv6pd", interface->stats.session_ipv6pd_rx, - "rx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_rx.avg, - "loss-packets-session-ipv6pd", interface->stats.session_ipv6pd_loss, - "tx-packets-streams", interface->stats.stream_tx, - "tx-pps-streams", interface->stats.rate_stream_tx.avg, - "rx-packets-streams", interface->stats.stream_rx, - "rx-pps-streams", interface->stats.rate_stream_rx.avg, - "loss-packets-streams", interface->stats.stream_loss - ); -} - -static json_t * -bbl_ctrl_a10nsp_interface_json(bbl_a10nsp_interface_s *interface) -{ - return json_pack("{ss si ss si si si si si si si si si si si si si si si si si si si si si si si si si si si si}", - "name", interface->name, - "ifindex", interface->ifindex, - "type", "a10nsp", - "tx-packets", interface->stats.packets_tx, - "tx-bytes", interface->stats.bytes_tx, - "tx-pps", interface->stats.rate_packets_tx.avg, - "tx-kbps", interface->stats.rate_bytes_tx.avg * 8 / 1000, - "rx-packets", interface->stats.packets_rx, - "rx-bytes", interface->stats.bytes_rx, - "rx-pps", interface->stats.rate_packets_rx.avg, - "rx-kbps", interface->stats.rate_bytes_rx.avg * 8 / 1000, - "tx-packets-session-ipv4", interface->stats.session_ipv4_tx, - "tx-pps-session-ipv4", interface->stats.rate_session_ipv4_tx.avg, - "rx-packets-session-ipv4", interface->stats.session_ipv4_rx, - "rx-pps-session-ipv4", interface->stats.rate_session_ipv4_rx.avg, - "loss-packets-session-ipv4", interface->stats.session_ipv4_loss, - "tx-packets-session-ipv6", interface->stats.session_ipv6_tx, - "tx-pps-session-ipv6", interface->stats.rate_session_ipv6_tx.avg, - "rx-packets-session-ipv6", interface->stats.session_ipv6_rx, - "rx-pps-session-ipv6", interface->stats.rate_session_ipv6_rx.avg, - "loss-packets-session-ipv6", interface->stats.session_ipv6_loss, - "tx-packets-session-ipv6pd", interface->stats.session_ipv6pd_tx, - "tx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_tx.avg, - "rx-packets-session-ipv6pd", interface->stats.session_ipv6pd_rx, - "rx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_rx.avg, - "loss-packets-session-ipv6pd", interface->stats.session_ipv6pd_loss, - "tx-packets-streams", interface->stats.stream_tx, - "tx-pps-streams", interface->stats.rate_stream_tx.avg, - "rx-packets-streams", interface->stats.stream_rx, - "rx-pps-streams", interface->stats.rate_stream_rx.avg, - "loss-packets-streams", interface->stats.stream_loss - ); -} - -int -bbl_ctrl_interfaces(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - int result = 0; - json_t *root, *interfaces; - - bbl_interface_s *interface; - bbl_network_interface_s *network_interface; - - interfaces = json_array(); - CIRCLEQ_FOREACH(interface, &g_ctx->interface_qhead, interface_qnode) { - network_interface = interface->network; - while(network_interface) { - json_array_append(interfaces, bbl_ctrl_network_interface_json(network_interface)); - network_interface = network_interface->next; - } - if(interface->access) { - json_array_append(interfaces, bbl_ctrl_access_interface_json(interface->access)); - } else if(interface->a10nsp) { - json_array_append(interfaces, bbl_ctrl_a10nsp_interface_json(interface->a10nsp)); - } - } - root = json_pack("{ss si so}", - "status", "ok", - "code", 200, - "interfaces", interfaces); - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } else { - result = bbl_ctrl_status(fd, "error", 500, "internal error"); - json_decref(interfaces); - } - return result; -} - -int -bbl_ctrl_session_terminate(int fd, uint32_t session_id, json_t* arguments) -{ - bbl_session_s *session; - int reconnect_delay = 0; - - if(session_id) { - /* Terminate single matching session ... */ - session = bbl_session_get(session_id); - if(session) { - json_unpack(arguments, "{s:i}", "reconnect-delay", &session->reconnect_delay); - if(reconnect_delay > 0) { - session->reconnect_delay = reconnect_delay; - } - bbl_session_clear(session); - return bbl_ctrl_status(fd, "ok", 200, "terminate session"); - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } - } else { - /* Terminate all sessions ... */ - g_teardown = true; - g_teardown_request = true; - LOG_NOARG(INFO, "Teardown request\n"); - return bbl_ctrl_status(fd, "ok", 200, "terminate all sessions"); - } -} - -int -bbl_ctrl_session_ncp_open_close(int fd, uint32_t session_id, bool open, bool ipcp) { - bbl_session_s *session; - uint32_t i; - if(session_id) { - session = bbl_session_get(session_id); - if(session) { - if(session->access_type == ACCESS_TYPE_PPPOE) { - if(open) { - bbl_session_ncp_open(session, ipcp); - } else { - bbl_session_ncp_close(session, ipcp); - } - } else { - return bbl_ctrl_status(fd, "warning", 400, "matching session is not of type pppoe"); - } - return bbl_ctrl_status(fd, "ok", 200, NULL); - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } - } else { - /* Iterate over all sessions */ - for(i = 0; i < g_ctx->sessions; i++) { - session = &g_ctx->session_list[i]; - if(session) { - if(session->access_type == ACCESS_TYPE_PPPOE) { - if(open) { - bbl_session_ncp_open(session, ipcp); - } else { - bbl_session_ncp_close(session, ipcp); - } - } - } - } - return bbl_ctrl_status(fd, "ok", 200, NULL); - } -} - -int -bbl_ctrl_session_ipcp_open(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_session_ncp_open_close(fd, session_id, true, true); -} - -int -bbl_ctrl_session_ipcp_close(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_session_ncp_open_close(fd, session_id, false, true); -} - -int -bbl_ctrl_session_ip6cp_open(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_session_ncp_open_close(fd, session_id, true, false); -} - -int -bbl_ctrl_session_ip6cp_close(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_session_ncp_open_close(fd, session_id, false, false); -} - -int -bbl_ctrl_li_flows(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - int result = 0; - json_t *root, *flows, *flow; - bbl_li_flow_t *li_flow; - struct dict_itor *itor; - - flows = json_array(); - itor = dict_itor_new(g_ctx->li_flow_dict); - dict_itor_first(itor); - for (; dict_itor_valid(itor); dict_itor_next(itor)) { - li_flow = (bbl_li_flow_t*)*dict_itor_datum(itor); - if(li_flow) { - flow = json_pack("{ss si ss si ss ss ss si si si si si si si si si si si si}", - "source-address", format_ipv4_address(&li_flow->src_ipv4), - "source-port", li_flow->src_port, - "destination-address", format_ipv4_address(&li_flow->dst_ipv4), - "destination-port", li_flow->dst_port, - "direction", bbl_li_direction_string(li_flow->direction), - "packet-type", bbl_li_packet_type_string(li_flow->packet_type), - "sub-packet-type", bbl_li_sub_packet_type_string(li_flow->sub_packet_type), - "liid", li_flow->liid, - "bytes-rx", li_flow->bytes_rx, - "packets-rx", li_flow->packets_rx, - "packets-rx-ipv4", li_flow->packets_rx_ipv4, - "packets-rx-ipv4-tcp", li_flow->packets_rx_ipv4_tcp, - "packets-rx-ipv4-udp", li_flow->packets_rx_ipv4_udp, - "packets-rx-ipv4-host-internal", li_flow->packets_rx_ipv4_internal, - "packets-rx-ipv6", li_flow->packets_rx_ipv6, - "packets-rx-ipv6-tcp", li_flow->packets_rx_ipv6_tcp, - "packets-rx-ipv6-udp", li_flow->packets_rx_ipv6_udp, - "packets-rx-ipv6-host-internal", li_flow->packets_rx_ipv6_internal, - "packets-rx-ipv6-no-next-header", li_flow->packets_rx_ipv6_no_next_header); - json_array_append(flows, flow); - } - } - dict_itor_free(itor); - root = json_pack("{ss si so}", - "status", "ok", - "code", 200, - "li-flows", flows); - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } else { - result = bbl_ctrl_status(fd, "error", 500, "internal error"); - json_decref(flows); - } - return result; -} - -int -bbl_ctrl_l2tp_tunnels(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - int result = 0; - json_t *root, *tunnels, *tunnel; - - bbl_l2tp_server_s *l2tp_server = g_ctx->config.l2tp_server; - bbl_l2tp_sunnel_s *l2tp_tunnel; - - tunnels = json_array(); - - while(l2tp_server) { - CIRCLEQ_FOREACH(l2tp_tunnel, &l2tp_server->tunnel_qhead, tunnel_qnode) { - - tunnel = json_pack("{ss ss ss si si ss ss ss ss si si si si si si si}", - "state", l2tp_tunnel_state_string(l2tp_tunnel->state), - "server-name", l2tp_server->host_name, - "server-address", format_ipv4_address(&l2tp_server->ip), - "tunnel-id", l2tp_tunnel->tunnel_id, - "peer-tunnel-id", l2tp_tunnel->peer_tunnel_id, - "peer-name", string_or_na(l2tp_tunnel->peer_name), - "peer-address", format_ipv4_address(&l2tp_tunnel->peer_ip), - "peer-vendor", string_or_na(l2tp_tunnel->peer_vendor), - "secret", string_or_na(l2tp_server->secret), - "control-packets-rx", l2tp_tunnel->stats.control_rx, - "control-packets-rx-dup", l2tp_tunnel->stats.control_rx_dup, - "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, - "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; - } - - root = json_pack("{ss si so}", - "status", "ok", - "code", 200, - "l2tp-tunnels", tunnels); - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } else { - result = bbl_ctrl_status(fd, "error", 500, "internal error"); - json_decref(tunnels); - } - return result; -} - -json_t * -l2tp_session_json(bbl_l2tp_session_s *l2tp_session) -{ - char *proxy_auth_response = NULL; - - if(l2tp_session->proxy_auth_response) { - if(l2tp_session->proxy_auth_type == L2TP_PROXY_AUTH_TYPE_PAP) { - proxy_auth_response = (char*)l2tp_session->proxy_auth_response; - } else { - proxy_auth_response = "0x..."; - } - } - - return json_pack("{ss si si si si si ss 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, - "peer-tunnel-id", l2tp_session->tunnel->peer_tunnel_id, - "peer-session-id", l2tp_session->peer_session_id, - "peer-proxy-auth-type", l2tp_session->proxy_auth_type, - "peer-proxy-auth-name", string_or_na(l2tp_session->proxy_auth_name), - "peer-proxy-auth-response", string_or_na(proxy_auth_response), - "peer-called-number", string_or_na(l2tp_session->peer_called_number), - "peer-calling-number", string_or_na(l2tp_session->peer_calling_number), - "peer-sub-address", string_or_na(l2tp_session->peer_sub_address), - "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), - "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); -} - -int -bbl_ctrl_l2tp_sessions(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments) -{ - int result = 0; - json_t *root, *sessions; - - bbl_l2tp_server_s *l2tp_server = g_ctx->config.l2tp_server; - bbl_l2tp_sunnel_s *l2tp_tunnel; - bbl_l2tp_session_s *l2tp_session; - l2tp_key_t l2tp_key = {0}; - void **search = NULL; - - int l2tp_tunnel_id = 0; - int l2tp_session_id = 0; - - json_unpack(arguments, "{s:i}", "tunnel-id", &l2tp_tunnel_id); - json_unpack(arguments, "{s:i}", "session-id", &l2tp_session_id); - - sessions = json_array(); - - if(l2tp_tunnel_id && l2tp_session_id) { - l2tp_key.tunnel_id = l2tp_tunnel_id; - l2tp_key.session_id = l2tp_session_id; - search = dict_search(g_ctx->l2tp_session_dict, &l2tp_key); - if(search) { - l2tp_session = *search; - json_array_append(sessions, l2tp_session_json(l2tp_session)); - } else { - result = bbl_ctrl_status(fd, "warning", 404, "session not found"); - json_decref(sessions); - return result; - } - } else if (l2tp_tunnel_id) { - l2tp_key.tunnel_id = l2tp_tunnel_id; - search = dict_search(g_ctx->l2tp_session_dict, &l2tp_key); - if(search) { - l2tp_session = *search; - l2tp_tunnel = l2tp_session->tunnel; - CIRCLEQ_FOREACH(l2tp_session, &l2tp_tunnel->session_qhead, session_qnode) { - if(!l2tp_session->key.session_id) continue; /* skip tunnel session */ - json_array_append(sessions, l2tp_session_json(l2tp_session)); - } - } else { - result = bbl_ctrl_status(fd, "warning", 404, "tunnel not found"); - json_decref(sessions); - return result; - } - } else { - while(l2tp_server) { - CIRCLEQ_FOREACH(l2tp_tunnel, &l2tp_server->tunnel_qhead, tunnel_qnode) { - CIRCLEQ_FOREACH(l2tp_session, &l2tp_tunnel->session_qhead, session_qnode) { - if(!l2tp_session->key.session_id) continue; /* skip tunnel session */ - json_array_append(sessions, l2tp_session_json(l2tp_session)); - } - } - l2tp_server = l2tp_server->next; - } - } - root = json_pack("{ss si so}", - "status", "ok", - "code", 200, - "l2tp-sessions", sessions); - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } else { - result = bbl_ctrl_status(fd, "error", 500, "internal error"); - json_decref(sessions); - } - return result; -} - -int -bbl_ctrl_l2tp_csurq(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments) -{ - json_t *sessions, *number; - - bbl_l2tp_sunnel_s *l2tp_tunnel; - bbl_l2tp_session_s *l2tp_session; - l2tp_key_t l2tp_key = {0}; - void **search = NULL; - - uint16_t l2tp_session_id = 0; - int l2tp_tunnel_id = 0; - int size, i; - - /* Unpack further arguments */ - if (json_unpack(arguments, "{s:i}", "tunnel-id", &l2tp_tunnel_id) != 0) { - return bbl_ctrl_status(fd, "error", 400, "missing tunnel-id"); - } - l2tp_key.tunnel_id = l2tp_tunnel_id; - search = dict_search(g_ctx->l2tp_session_dict, &l2tp_key); - if(search) { - l2tp_session = *search; - l2tp_tunnel = l2tp_session->tunnel; - if(l2tp_tunnel->state != BBL_L2TP_TUNNEL_ESTABLISHED) { - return bbl_ctrl_status(fd, "warning", 400, "tunnel not established"); - } - sessions = json_object_get(arguments, "sessions"); - if (json_is_array(sessions)) { - size = json_array_size(sessions); - l2tp_tunnel->csurq_requests_len = size; - l2tp_tunnel->csurq_requests = malloc(size * sizeof(uint16_t)); - for (i = 0; i < size; i++) { - number = json_array_get(sessions, i); - if(json_is_number(number)) { - l2tp_session_id = json_number_value(number); - l2tp_tunnel->csurq_requests[i] = l2tp_session_id; - } - } - bbl_l2tp_send(l2tp_tunnel, NULL, L2TP_MESSAGE_CSURQ); - return bbl_ctrl_status(fd, "ok", 200, NULL); - } else { - return bbl_ctrl_status(fd, "error", 400, "invalid request"); - } - } else { - return bbl_ctrl_status(fd, "warning", 404, "tunnel not found"); - } -} - -int -bbl_ctrl_l2tp_tunnel_terminate(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments) -{ - bbl_l2tp_sunnel_s *l2tp_tunnel; - bbl_l2tp_session_s *l2tp_session; - l2tp_key_t l2tp_key = {0}; - void **search = NULL; - - int l2tp_tunnel_id = 0; - int result_code; - int error_code; - char *error_message; - - /* Unpack further arguments */ - if (json_unpack(arguments, "{s:i}", "tunnel-id", &l2tp_tunnel_id) != 0) { - return bbl_ctrl_status(fd, "error", 400, "missing tunnel-id"); - } - l2tp_key.tunnel_id = l2tp_tunnel_id; - search = dict_search(g_ctx->l2tp_session_dict, &l2tp_key); - if(search) { - l2tp_session = *search; - l2tp_tunnel = l2tp_session->tunnel; - if(l2tp_tunnel->state != BBL_L2TP_TUNNEL_ESTABLISHED) { - return bbl_ctrl_status(fd, "warning", 400, "tunnel not established"); - } - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); - if (json_unpack(arguments, "{s:i}", "result-code", &result_code) != 0) { - result_code = 1; - } - l2tp_tunnel->result_code = result_code; - if (json_unpack(arguments, "{s:i}", "error-code", &error_code) != 0) { - error_code = 0; - } - l2tp_tunnel->error_code = error_code; - if (json_unpack(arguments, "{s:s}", "error-message", &error_message) != 0) { - error_message = NULL; - } - l2tp_tunnel->error_message = error_message; - bbl_l2tp_send(l2tp_tunnel, NULL, L2TP_MESSAGE_STOPCCN); - return bbl_ctrl_status(fd, "ok", 200, NULL); - } else { - return bbl_ctrl_status(fd, "warning", 404, "tunnel not found"); - } -} - -int -bbl_ctrl_l2tp_session_terminate(int fd, uint32_t session_id, json_t* arguments) -{ - bbl_session_s *session; - bbl_l2tp_sunnel_s *l2tp_tunnel; - bbl_l2tp_session_s *l2tp_session; - - int result_code; - int error_code; - char *error_message; - int disconnect_code; - int disconnect_protocol; - int disconnect_direction; - char* disconnect_message; - - if(session_id == 0) { - /* session-id is mandatory */ - return bbl_ctrl_status(fd, "error", 400, "missing session-id"); - } - - session = bbl_session_get(session_id); - if(session) { - l2tp_session = session->l2tp_session; - if(!l2tp_session) { - return bbl_ctrl_status(fd, "error", 400, "no L2TP session"); - } - l2tp_tunnel = l2tp_session->tunnel; - if(l2tp_tunnel->state != BBL_L2TP_TUNNEL_ESTABLISHED) { - return bbl_ctrl_status(fd, "warning", 400, "tunnel not established"); - } - if(l2tp_session->state != BBL_L2TP_SESSION_ESTABLISHED) { - return bbl_ctrl_status(fd, "warning", 400, "session not established"); - } - if (json_unpack(arguments, "{s:i}", "result-code", &result_code) != 0) { - result_code = 2; - } - l2tp_session->result_code = result_code; - if (json_unpack(arguments, "{s:i}", "error-code", &error_code) != 0) { - error_code = 0; - } - l2tp_session->error_code = error_code; - if (json_unpack(arguments, "{s:s}", "error-message", &error_message) != 0) { - error_message = NULL; - } - l2tp_session->error_message = error_message; - if (json_unpack(arguments, "{s:i}", "disconnect-code", &disconnect_code) != 0) { - disconnect_code = 0; - } - l2tp_session->disconnect_code = disconnect_code; - if (json_unpack(arguments, "{s:i}", "disconnect-protocol", &disconnect_protocol) != 0) { - disconnect_protocol = 0; - } - l2tp_session->disconnect_protocol = disconnect_protocol; - if (json_unpack(arguments, "{s:i}", "disconnect-direction", &disconnect_direction) != 0) { - disconnect_direction = 0; - } - l2tp_session->disconnect_direction = disconnect_direction; - if (json_unpack(arguments, "{s:s}", "disconnect-message", &disconnect_message) != 0) { - disconnect_message = NULL; - } - l2tp_session->disconnect_message = disconnect_message; - bbl_l2tp_send(l2tp_tunnel, l2tp_session, L2TP_MESSAGE_CDN); - bbl_l2tp_session_delete(l2tp_session); - return bbl_ctrl_status(fd, "ok", 200, NULL); - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } -} - -int -bbl_ctrl_session_streams(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) { - int result = 0; - json_t *root; - json_t *json_streams = NULL; - json_t *json_stream = NULL; - - bbl_session_s *session; - bbl_stream_s *stream; - - if(session_id == 0) { - /* session-id is mandatory */ - return bbl_ctrl_status(fd, "error", 400, "missing session-id"); - } - - session = bbl_session_get(session_id); - if(session) { - stream = session->streams.head; - - json_streams = json_array(); - while(stream) { - json_stream = bbl_stream_json(stream); - json_array_append(json_streams, json_stream); - stream = stream->session_next; - } - root = json_pack("{ss si s{si si si si si si si si si sf sf so*}}", - "status", "ok", - "code", 200, - "session-streams", - "session-id", session->session_id, - "rx-packets", session->stats.packets_rx, - "tx-packets", session->stats.packets_tx, - "rx-accounting-packets", session->stats.accounting_packets_rx, - "tx-accounting-packets", session->stats.accounting_packets_tx, - "rx-pps", session->stats.rate_packets_rx.avg, - "tx-pps", session->stats.rate_packets_tx.avg, - "rx-bps-l2", session->stats.rate_bytes_rx.avg * 8, - "tx-bps-l2", session->stats.rate_bytes_tx.avg * 8, - "rx-mbps-l2", (double)(session->stats.rate_bytes_rx.avg * 8) / 1000000.0, - "tx-mbps-l2", (double)(session->stats.rate_bytes_tx.avg * 8) / 1000000.0, - "streams", json_streams); - - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } else { - result = bbl_ctrl_status(fd, "error", 500, "internal error"); - json_decref(json_streams); - } - return result; - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } -} - -static int -bbl_ctrl_stream_traffic_start_stop(int fd, uint32_t session_id, bool status) -{ - bbl_session_s *session; - uint32_t i; - - if(session_id) { - session = bbl_session_get(session_id); - if(session) { - session->streams.active = status; - return bbl_ctrl_status(fd, "ok", 200, NULL); - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } - } else { - /* Iterate over all sessions */ - for(i = 0; i < g_ctx->sessions; i++) { - session = &g_ctx->session_list[i]; - if(session) { - session->streams.active = status; - } - } - return bbl_ctrl_status(fd, "ok", 200, NULL); - } -} - -int -bbl_ctrl_stream_traffic_start(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_stream_traffic_start_stop(fd, session_id, true); -} - -int -bbl_ctrl_stream_traffic_stop(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_stream_traffic_start_stop(fd, session_id, false); -} - -int -bbl_ctrl_stream_reset(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - bbl_stream_s *stream; - struct dict_itor *itor; - - g_ctx->stats.stream_traffic_flows_verified = 0; - - /* Iterate over all traffic streams */ - itor = dict_itor_new(g_ctx->stream_flow_dict); - dict_itor_first(itor); - for (; dict_itor_valid(itor); dict_itor_next(itor)) { - stream = (bbl_stream_s*)*dict_itor_datum(itor); - if(!stream) { - continue; - } - bbl_stream_reset(stream); - } - dict_itor_free(itor); - return bbl_ctrl_status(fd, "ok", 200, NULL); -} - -int -bbl_ctrl_sessions_pending(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - int result = 0; - json_t *root, *json_session, *json_sessions; - - bbl_session_s *session; - uint32_t i; - - json_sessions = json_array(); - - /* Iterate over all sessions */ - for(i = 0; i < g_ctx->sessions; i++) { - session = &g_ctx->session_list[i]; - if(!session) continue; - - if(session->session_state != BBL_ESTABLISHED || - session->session_traffic.flows != session->session_traffic.flows_verified) { - json_session = json_pack("{si ss si si}", - "session-id", session->session_id, - "session-state", session_state_string(session->session_state), - "session-traffic-flows", session->session_traffic.flows, - "session-traffic-flows-verified", session->session_traffic.flows_verified); - json_array_append(json_sessions, json_session); - } - } - - root = json_pack("{ss si so}", - "status", "ok", - "code", 200, - "sessions-pending", json_sessions); - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } else { - result = bbl_ctrl_status(fd, "error", 500, "internal error"); - json_decref(json_sessions); - } - return result; -} - -int -bbl_ctrl_cfm_cc_start_stop(int fd, uint32_t session_id, bool status) -{ - bbl_session_s *session; - uint32_t i; - if(session_id) { - session = bbl_session_get(session_id); - if(session) { - session->cfm_cc = status; - return bbl_ctrl_status(fd, "ok", 200, NULL); - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } - } else { - /* Iterate over all sessions */ - for(i = 0; i < g_ctx->sessions; i++) { - session = &g_ctx->session_list[i]; - if(session) { - session->cfm_cc = status; - } - } - return bbl_ctrl_status(fd, "ok", 200, NULL); - } -} - -int -bbl_ctrl_cfm_cc_start(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_cfm_cc_start_stop(fd, session_id, true); -} - -int -bbl_ctrl_cfm_cc_stop(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_cfm_cc_start_stop(fd, session_id, false); -} - -int -bbl_ctrl_cfm_cc_rdi(int fd, uint32_t session_id, bool status) -{ - bbl_session_s *session; - uint32_t i; - if(session_id) { - session = bbl_session_get(session_id); - if(session) { - session->cfm_rdi = status; - return bbl_ctrl_status(fd, "ok", 200, NULL); - } else { - return bbl_ctrl_status(fd, "warning", 404, "session not found"); - } - } else { - /* Iterate over all sessions */ - for(i = 0; i < g_ctx->sessions; i++) { - session = &g_ctx->session_list[i]; - if(session) { - session->cfm_rdi = status; - } - } - return bbl_ctrl_status(fd, "ok", 200, NULL); - } -} - -int -bbl_ctrl_cfm_cc_rdi_on(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_cfm_cc_rdi(fd, session_id, true); -} - -int -bbl_ctrl_cfm_cc_rdi_off(int fd, uint32_t session_id, json_t* arguments __attribute__((unused))) -{ - return bbl_ctrl_cfm_cc_rdi(fd, session_id, false); -} - -int -bbl_ctrl_stream_stats(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) { - int result = 0; - json_t *root = json_pack("{ss si s{si si}}", - "status", "ok", - "code", 200, - "stream-stats", - "total-flows", g_ctx->stats.stream_traffic_flows, - "verified-flows", g_ctx->stats.stream_traffic_flows_verified); - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } - return result; -} - -int -bbl_ctrl_stream_info(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments) -{ - int result = 0; - - json_t *root; - json_t *json_stream = NULL; - - bbl_stream_s *stream; - void **search = NULL; - - int number = 0; - uint64_t flow_id; - - /* Unpack further arguments */ - if (json_unpack(arguments, "{s:i}", "flow-id", &number) != 0) { - return bbl_ctrl_status(fd, "error", 400, "missing flow-id"); - } - - flow_id = number; - search = dict_search(g_ctx->stream_flow_dict, &flow_id); - if(search) { - stream = *search; - json_stream = bbl_stream_json(stream); - root = json_pack("{ss si so*}", - "status", "ok", - "code", 200, - "stream-info", json_stream); - if(root) { - result = json_dumpfd(root, fd, 0); - json_decref(root); - } else { - result = bbl_ctrl_status(fd, "error", 500, "internal error"); - json_decref(json_stream); - } - return result; - } else { - return bbl_ctrl_status(fd, "warning", 404, "stream not found"); - } -} - -int -bbl_ctrl_stream_summary(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - int result = 0; - - json_t *root = json_pack("{ss si so*}", - "status", "ok", - "code", 200, - "stream-summary", - bbl_stream_summary_json()); - - result = json_dumpfd(root, fd, 0); - json_decref(root); - return result; -} - -int -bbl_ctrl_traffic_start(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) +bbl_ctrl_traffic_start(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) { enable_disable_traffic(true); return bbl_ctrl_status(fd, "ok", 200, NULL); } int -bbl_ctrl_traffic_stop(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) +bbl_ctrl_traffic_stop(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) { enable_disable_traffic(false); return bbl_ctrl_status(fd, "ok", 200, NULL); } -int -bbl_ctrl_monkey_start(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - if(!g_monkey) { - LOG_NOARG(INFO, "Start monkey\n"); - } - g_monkey = true; - return bbl_ctrl_status(fd, "ok", 200, NULL); -} - -int -bbl_ctrl_monkey_stop(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) -{ - if(g_monkey) { - LOG_NOARG(INFO, "Stop monkey\n"); - } - g_monkey = false; - return bbl_ctrl_status(fd, "ok", 200, NULL); -} +typedef int callback_function(int fd, uint32_t session_id, json_t *arguments); struct action { char *name; @@ -1618,50 +76,53 @@ struct action { }; struct action actions[] = { - {"interfaces", bbl_ctrl_interfaces, true}, - {"terminate", bbl_ctrl_session_terminate, false}, - {"session-counters", bbl_ctrl_session_counters, true}, - {"session-info", bbl_ctrl_session_info, true}, - {"session-start", bbl_ctrl_session_start, true}, - {"session-traffic", bbl_ctrl_session_traffic_stats, true}, - {"session-traffic-enabled", bbl_ctrl_session_traffic_start, false}, - {"session-traffic-start", bbl_ctrl_session_traffic_start, false}, - {"session-traffic-disabled", bbl_ctrl_session_traffic_stop, false}, - {"session-traffic-stop", bbl_ctrl_session_traffic_stop, false}, - {"session-streams", bbl_ctrl_session_streams, true}, - {"sessions-pending", bbl_ctrl_sessions_pending, true}, - {"stream-traffic-enabled", bbl_ctrl_stream_traffic_start, false}, - {"stream-traffic-start", bbl_ctrl_stream_traffic_start, false}, - {"stream-traffic-disabled", bbl_ctrl_stream_traffic_stop, false}, - {"stream-traffic-stop", bbl_ctrl_stream_traffic_stop, false}, - {"stream-info", bbl_ctrl_stream_info, true}, - {"stream-summary", bbl_ctrl_stream_summary, true}, - {"stream-stats", bbl_ctrl_stream_stats, true}, - {"stream-reset", bbl_ctrl_stream_reset, false}, + {"interfaces", bbl_interface_ctrl, true}, + {"access-interfaces", bbl_access_ctrl_interfaces, true}, + {"network-interfaces", bbl_network_ctrl_interfaces, true}, + {"a10nsp-interfaces", bbl_a10nsp_ctrl_interfaces, true}, + {"terminate", bbl_session_ctrl_terminate, false}, + {"sessions-pending", bbl_session_ctrl_pending, true}, + {"session-counters", bbl_session_ctrl_counters, true}, + {"session-info", bbl_session_ctrl_info, true}, + {"session-start", bbl_session_ctrl_start, true}, + {"session-traffic", bbl_session_ctrl_traffic_stats, true}, + {"session-traffic-enabled", bbl_session_ctrl_traffic_start, false}, + {"session-traffic-start", bbl_session_ctrl_traffic_start, false}, + {"session-traffic-disabled", bbl_session_ctrl_traffic_stop, false}, + {"session-traffic-stop", bbl_session_ctrl_traffic_stop, false}, + {"session-streams", bbl_stream_ctrl_session, true}, + {"stream-traffic-enabled", bbl_stream_ctrl_traffic_start, false}, + {"stream-traffic-start", bbl_stream_ctrl_traffic_start, false}, + {"stream-traffic-disabled", bbl_stream_ctrl_traffic_stop, false}, + {"stream-traffic-stop", bbl_stream_ctrl_traffic_stop, false}, + {"stream-info", bbl_stream_ctrl_info, true}, + {"stream-summary", bbl_stream_ctrl_summary, true}, + {"stream-stats", bbl_stream_ctrl_stats, true}, + {"stream-reset", bbl_stream_ctrl_reset, false}, {"multicast-traffic-start", bbl_ctrl_multicast_traffic_start, false}, {"multicast-traffic-stop", bbl_ctrl_multicast_traffic_stop, false}, - {"igmp-join", bbl_ctrl_igmp_join, false}, - {"igmp-join-iter", bbl_ctrl_igmp_join_iter, false}, - {"igmp-leave", bbl_ctrl_igmp_leave, false}, - {"igmp-leave-all", bbl_ctrl_igmp_leave_all, false}, - {"igmp-info", bbl_ctrl_igmp_info, true}, - {"zapping-start", bbl_ctrl_zapping_start, true}, - {"zapping-stop", bbl_ctrl_zapping_stop, false}, - {"zapping-stats", bbl_ctrl_zapping_stats, true}, - {"li-flows", bbl_ctrl_li_flows, true}, - {"l2tp-tunnels", bbl_ctrl_l2tp_tunnels, true}, - {"l2tp-sessions", bbl_ctrl_l2tp_sessions, true}, - {"l2tp-csurq", bbl_ctrl_l2tp_csurq, false}, - {"l2tp-tunnel-terminate", bbl_ctrl_l2tp_tunnel_terminate, false}, - {"l2tp-session-terminate", bbl_ctrl_l2tp_session_terminate, false}, - {"ipcp-open", bbl_ctrl_session_ipcp_open, false}, - {"ipcp-close", bbl_ctrl_session_ipcp_close, false}, - {"ip6cp-open", bbl_ctrl_session_ip6cp_open, false}, - {"ip6cp-close", bbl_ctrl_session_ip6cp_close, false}, - {"cfm-cc-start", bbl_ctrl_cfm_cc_start, false}, - {"cfm-cc-stop", bbl_ctrl_cfm_cc_stop, false}, - {"cfm-cc-rdi-on", bbl_ctrl_cfm_cc_rdi_on, false}, - {"cfm-cc-rdi-off", bbl_ctrl_cfm_cc_rdi_off, false}, + {"igmp-join", bbl_igmp_ctrl_join, false}, + {"igmp-join-iter", bbl_igmp_ctrl_join_iter, false}, + {"igmp-leave", bbl_igmp_ctrl_leave, false}, + {"igmp-leave-all", bbl_igmp_ctrl_leave_all, false}, + {"igmp-info", bbl_igmp_ctrl_info, true}, + {"zapping-start", bbl_igmp_ctrl_zapping_start, true}, + {"zapping-stop", bbl_igmp_ctrl_zapping_stop, false}, + {"zapping-stats", bbl_igmp_ctrl_zapping_stats, true}, + {"li-flows", bbl_li_ctrl_flows, true}, + {"l2tp-tunnels", bbl_l2tp_ctrl_tunnels, true}, + {"l2tp-sessions", bbl_l2tp_ctrl_sessions, true}, + {"l2tp-csurq", bbl_l2tp_ctrl_csurq, false}, + {"l2tp-tunnel-terminate", bbl_l2tp_ctrl_tunnel_terminate, false}, + {"l2tp-session-terminate", bbl_l2tp_ctrl_session_terminate, false}, + {"ipcp-open", bbl_session_ctrl_ipcp_open, false}, + {"ipcp-close", bbl_session_ctrl_ipcp_close, false}, + {"ip6cp-open", bbl_session_ctrl_ip6cp_open, false}, + {"ip6cp-close", bbl_session_ctrl_ip6cp_close, false}, + {"cfm-cc-start", bbl_cfm_ctrl_cc_start, false}, + {"cfm-cc-stop", bbl_cfm_ctrl_cc_stop, false}, + {"cfm-cc-rdi-on", bbl_cfm_ctrl_cc_rdi_on, false}, + {"cfm-cc-rdi-off", bbl_cfm_ctrl_cc_rdi_off, false}, {"traffic-start", bbl_ctrl_traffic_start, false}, {"traffic-stop", bbl_ctrl_traffic_stop, false}, {"isis-adjacencies", isis_ctrl_adjacencies, true}, @@ -1674,8 +135,8 @@ struct action actions[] = { {"bgp-teardown", bgp_ctrl_teardown, true}, {"bgp-raw-update-list", bgp_ctrl_raw_update_list, true}, {"bgp-raw-update", bgp_ctrl_raw_update, false}, - {"monkey-start", bbl_ctrl_monkey_start, false}, - {"monkey-stop", bbl_ctrl_monkey_stop, false}, + {"monkey-start", bbl_session_ctrl_monkey_start, false}, + {"monkey-stop", bbl_session_ctrl_monkey_stop, false}, {"lag-info", bbl_lag_ctrl_info, true}, {NULL, NULL, false}, }; diff --git a/code/bngblaster/src/bbl_igmp.c b/code/bngblaster/src/bbl_igmp.c new file mode 100644 index 00000000..a6e8dc1e --- /dev/null +++ b/code/bngblaster/src/bbl_igmp.c @@ -0,0 +1,430 @@ +/* + * BNG Blaster (BBL) - IGMP Functions + * + * Christian Giese, October 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "bbl.h" + +int +bbl_igmp_ctrl_join(int fd, uint32_t session_id, json_t *arguments) +{ + bbl_session_s *session; + const char *s; + uint32_t group_address = 0; + uint32_t source1 = 0; + uint32_t source2 = 0; + uint32_t source3 = 0; + bbl_igmp_group_s *group = NULL; + int i; + + if(session_id == 0) { + /* session-id is mandatory */ + return bbl_ctrl_status(fd, "error", 400, "missing session-id"); + } + /* Unpack further arguments */ + if (json_unpack(arguments, "{s:s}", "group", &s) == 0) { + if(!inet_pton(AF_INET, s, &group_address)) { + return bbl_ctrl_status(fd, "error", 400, "invalid group address"); + } + } else { + return bbl_ctrl_status(fd, "error", 400, "missing group address"); + } + if (json_unpack(arguments, "{s:s}", "source1", &s) == 0) { + if(!inet_pton(AF_INET, s, &source1)) { + return bbl_ctrl_status(fd, "error", 400, "invalid source1 address"); + } + } + if (json_unpack(arguments, "{s:s}", "source2", &s) == 0) { + if(!inet_pton(AF_INET, s, &source2)) { + return bbl_ctrl_status(fd, "error", 400, "invalid source2 address"); + } + } + if (json_unpack(arguments, "{s:s}", "source3", &s) == 0) { + if(!inet_pton(AF_INET, s, &source3)) { + return bbl_ctrl_status(fd, "error", 400, "invalid source3 address"); + } + } + + /* Search session */ + session = bbl_session_get(session_id); + if(session) { + /* Search for free slot ... */ + for(i=0; i < IGMP_MAX_GROUPS; i++) { + if(!session->igmp_groups[i].zapping) { + if (session->igmp_groups[i].group == group_address) { + group = &session->igmp_groups[i]; + if(group->state == IGMP_GROUP_IDLE) { + break; + } else { + return bbl_ctrl_status(fd, "error", 409, "group already exists"); + } + } else if(session->igmp_groups[i].state == IGMP_GROUP_IDLE) { + group = &session->igmp_groups[i]; + } + } + } + if(!group) { + return bbl_ctrl_status(fd, "error", 409, "no igmp group slot available"); + } + /* Join group... */ + memset(group, 0x0, sizeof(bbl_igmp_group_s)); + group->group = group_address; + if(source1) group->source[0] = source1; + if(source2) group->source[1] = source2; + if(source3) group->source[2] = source3; + group->state = IGMP_GROUP_JOINING; + group->robustness_count = session->igmp_robustness; + group->send = true; + session->send_requests |= BBL_SEND_IGMP; + bbl_session_tx_qnode_insert(session); + LOG(IGMP, "IGMP (ID: %u) join %s\n", + session->session_id, format_ipv4_address(&group->group)); + return bbl_ctrl_status(fd, "ok", 200, NULL); + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } +} + +int +bbl_igmp_ctrl_join_iter(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) +{ + bbl_session_s *session; + const char *s; + uint32_t group_address = 0; + uint32_t group_iter = 1; + int group_count = 0; + bbl_igmp_group_s *group = NULL; + uint32_t source1 = 0; + uint32_t source2 = 0; + uint32_t source3 = 0; + uint32_t i, i2; + uint32_t join_count; + + /* Unpack group arguments */ + if (json_unpack(arguments, "{s:s}", "group", &s) == 0) { + if(!inet_pton(AF_INET, s, &group_address)) { + return bbl_ctrl_status(fd, "error", 400, "invalid group address"); + } + } else { + return bbl_ctrl_status(fd, "error", 400, "missing group address"); + } + if (json_unpack(arguments, "{s:d}", "group-iter", &s) == 0) { + if(!inet_pton(AF_INET, s, &group_iter)) { + return bbl_ctrl_status(fd, "error", 400, "invalid group-iter"); + } + group_iter = be32toh(group_iter); + } + json_unpack(arguments, "{s:i}", "group-count", &group_count); + if(group_count < 1) group_count = 1; + + /* Unpack source address arguments */ + if (json_unpack(arguments, "{s:s}", "source1", &s) == 0) { + if(!inet_pton(AF_INET, s, &source1)) { + return bbl_ctrl_status(fd, "error", 400, "invalid source1 address"); + } + } + if (json_unpack(arguments, "{s:s}", "source2", &s) == 0) { + if(!inet_pton(AF_INET, s, &source2)) { + return bbl_ctrl_status(fd, "error", 400, "invalid source2 address"); + } + } + if (json_unpack(arguments, "{s:s}", "source3", &s) == 0) { + if(!inet_pton(AF_INET, s, &source3)) { + return bbl_ctrl_status(fd, "error", 400, "invalid source3 address"); + } + } + + while(group_count) { + /* Iterate over all sessions */ + join_count = 0; + for(i = 0; i < g_ctx->sessions; i++) { + session = &g_ctx->session_list[i]; + if(session) { + /* Search for free slot ... */ + for(i2=0; i2 < IGMP_MAX_GROUPS; i2++) { + group = &session->igmp_groups[i2]; + if(group->zapping) { + continue; + } + if(group->group == group_address && + group->state != IGMP_GROUP_IDLE) { + /* Group already exists. */ + group_address = htobe32(be32toh(group_address) + group_iter); + break; + } + if(group->state != IGMP_GROUP_IDLE) { + continue; + } + /* Join group. */ + memset(group, 0x0, sizeof(bbl_igmp_group_s)); + group->group = group_address; + if(source1) group->source[0] = source1; + if(source2) group->source[1] = source2; + if(source3) group->source[2] = source3; + group->state = IGMP_GROUP_JOINING; + group->robustness_count = session->igmp_robustness; + group->send = true; + LOG(IGMP, "IGMP (ID: %u) join %s\n", + session->session_id, format_ipv4_address(&group->group)); + session->send_requests |= BBL_SEND_IGMP; + + join_count++; + if(--group_count == 0) { + return bbl_ctrl_status(fd, "ok", 200, NULL); + }; + /* Get next group address. */ + group_address = htobe32(be32toh(group_address) + group_iter); + break; + } + } + } + /* Prevent infinity loops! */ + if(!join_count) break; + } + return bbl_ctrl_status(fd, "ok", 200, NULL); +} + +int +bbl_igmp_ctrl_leave(int fd, uint32_t session_id, json_t *arguments) +{ + bbl_session_s *session; + const char *s; + uint32_t group_address = 0; + bbl_igmp_group_s *group = NULL; + int i; + + if(session_id == 0) { + /* session-id is mandatory */ + return bbl_ctrl_status(fd, "error", 400, "missing session-id"); + } + /* Unpack further arguments */ + if (json_unpack(arguments, "{s:s}", "group", &s) == 0) { + if(!inet_pton(AF_INET, s, &group_address)) { + return bbl_ctrl_status(fd, "error", 400, "invalid group address"); + } + } else { + return bbl_ctrl_status(fd, "error", 400, "missing group address"); + } + + session = bbl_session_get(session_id); + if(session) { + /* Search for group ... */ + for(i=0; i < IGMP_MAX_GROUPS; i++) { + if (session->igmp_groups[i].group == group_address) { + group = &session->igmp_groups[i]; + break; + } + } + if(!group) { + return bbl_ctrl_status(fd, "warning", 404, "group not found"); + } + if(group->zapping) { + return bbl_ctrl_status(fd, "error", 408, "group used by zapping test"); + } + if(group->state <= IGMP_GROUP_LEAVING) { + return bbl_ctrl_status(fd, "ok", 200, NULL); + } + group->state = IGMP_GROUP_LEAVING; + group->robustness_count = session->igmp_robustness; + group->send = true; + group->leave_tx_time.tv_sec = 0; + group->leave_tx_time.tv_nsec = 0; + group->last_mc_rx_time.tv_sec = 0; + group->last_mc_rx_time.tv_nsec = 0; + session->send_requests |= BBL_SEND_IGMP; + bbl_session_tx_qnode_insert(session); + LOG(IGMP, "IGMP (ID: %u) leave %s\n", + session->session_id, format_ipv4_address(&group->group)); + return bbl_ctrl_status(fd, "ok", 200, NULL); + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } +} + +int +bbl_igmp_ctrl_leave_all(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + bbl_session_s *session; + bbl_igmp_group_s *group = NULL; + uint32_t i, i2; + + /* Iterate over all sessions */ + for(i = 0; i < g_ctx->sessions; i++) { + session = &g_ctx->session_list[i]; + if(session) { + /* Search for group ... */ + for(i2=0; i2 < IGMP_MAX_GROUPS; i2++) { + group = &session->igmp_groups[i2]; + if(group->zapping || group->state <= IGMP_GROUP_LEAVING) { + continue; + } + group->state = IGMP_GROUP_LEAVING; + group->robustness_count = session->igmp_robustness; + group->send = true; + group->leave_tx_time.tv_sec = 0; + group->leave_tx_time.tv_nsec = 0; + group->last_mc_rx_time.tv_sec = 0; + group->last_mc_rx_time.tv_nsec = 0; + LOG(IGMP, "IGMP (ID: %u) leave %s\n", + session->session_id, format_ipv4_address(&group->group)); + session->send_requests |= BBL_SEND_IGMP; + bbl_session_tx_qnode_insert(session); + } + } + } + return bbl_ctrl_status(fd, "ok", 200, NULL); +} + +int +bbl_igmp_ctrl_info(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root, *groups, *record, *sources; + bbl_session_s *session = NULL; + bbl_igmp_group_s *group = NULL; + uint32_t delay = 0; + uint32_t ms; + + struct timespec time_diff; + int i, i2; + + if(session_id == 0) { + /* session-id is mandatory */ + return bbl_ctrl_status(fd, "error", 400, "missing session-id"); + } + + session = bbl_session_get(session_id); + if(session) { + groups = json_array(); + /* Add group informations */ + for(i=0; i < IGMP_MAX_GROUPS; i++) { + group = &session->igmp_groups[i]; + if(group->group) { + sources = json_array(); + for(i2=0; i2 < IGMP_MAX_SOURCES; i2++) { + if(group->source[i2]) { + json_array_append(sources, json_string(format_ipv4_address(&group->source[i2]))); + } + } + record = json_pack("{ss so si si}", + "group", format_ipv4_address(&group->group), + "sources", sources, + "packets", group->packets, + "loss", group->loss); + + switch (group->state) { + case IGMP_GROUP_IDLE: + json_object_set(record, "state", json_string("idle")); + if(group->last_mc_rx_time.tv_sec && group->leave_tx_time.tv_sec) { + timespec_sub(&time_diff, &group->last_mc_rx_time, &group->leave_tx_time); + ms = time_diff.tv_nsec / 1000000; /* convert nanoseconds to milliseconds */ + if(time_diff.tv_nsec % 1000000) ms++; /* simple roundup function */ + delay = (time_diff.tv_sec * 1000) + ms; + json_object_set(record, "leave-delay-ms", json_integer(delay)); + } + break; + case IGMP_GROUP_LEAVING: + json_object_set(record, "state", json_string("leaving")); + break; + case IGMP_GROUP_ACTIVE: + json_object_set(record, "state", json_string("active")); + if(group->first_mc_rx_time.tv_sec) { + timespec_sub(&time_diff, &group->first_mc_rx_time, &group->join_tx_time); + ms = time_diff.tv_nsec / 1000000; /* convert nanoseconds to milliseconds */ + if(time_diff.tv_nsec % 1000000) ms++; /* simple roundup function */ + delay = (time_diff.tv_sec * 1000) + ms; + json_object_set(record, "join-delay-ms", json_integer(delay)); + } + break; + case IGMP_GROUP_JOINING: + json_object_set(record, "state", json_string("joining")); + if(group->first_mc_rx_time.tv_sec) { + timespec_sub(&time_diff, &group->first_mc_rx_time, &group->join_tx_time); + ms = time_diff.tv_nsec / 1000000; /* convert nanoseconds to milliseconds */ + if(time_diff.tv_nsec % 1000000) ms++; /* simple roundup function */ + delay = (time_diff.tv_sec * 1000) + ms; + json_object_set(record, "join-delay-ms", json_integer(delay)); + } + break; + default: + break; + } + json_array_append(groups, record); + } + } + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "igmp-groups", groups); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(groups); + } + return result; + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } +} + +int +bbl_igmp_ctrl_zapping_start(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + g_ctx->zapping = true; + return bbl_ctrl_status(fd, "ok", 200, NULL); +} + +int +bbl_igmp_ctrl_zapping_stop(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + g_ctx->zapping = false; + return bbl_ctrl_status(fd, "ok", 200, NULL); +} + +int +bbl_igmp_ctrl_zapping_stats(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root; + + bbl_stats_s stats = {0}; + int reset = 0; + + json_unpack(arguments, "{s:b}", "reset", &reset); + bbl_stats_generate_multicast(&stats, reset); + + root = json_pack("{ss si s{si si si si si si si si si si si si si si si si si}}", + "status", "ok", + "code", 200, + "zapping-stats", + "join-delay-ms-min", stats.min_join_delay, + "join-delay-ms-avg", stats.avg_join_delay, + "join-delay-ms-max", stats.max_join_delay, + "join-delay-violations", stats.join_delay_violations, + "join-delay-violations-threshold", g_ctx->config.igmp_max_join_delay, + "join-delay-violations-125ms", stats.join_delay_violations_125ms, + "join-delay-violations-250ms", stats.join_delay_violations_250ms, + "join-delay-violations-500ms", stats.join_delay_violations_500ms, + "join-delay-violations-1s", stats.join_delay_violations_1s, + "join-delay-violations-2s", stats.join_delay_violations_2s, + "join-count", stats.zapping_join_count, + "leave-delay-ms-min", stats.min_leave_delay, + "leave-delay-ms-avg", stats.avg_leave_delay, + "leave-delay-ms-max", stats.max_leave_delay, + "leave-count", stats.zapping_leave_count, + "multicast-packets-overlap", stats.mc_old_rx_after_first_new, + "multicast-not-received", stats.mc_not_received); + + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + } + return result; +} \ No newline at end of file diff --git a/code/bngblaster/src/bbl_igmp.h b/code/bngblaster/src/bbl_igmp.h new file mode 100644 index 00000000..16e184bd --- /dev/null +++ b/code/bngblaster/src/bbl_igmp.h @@ -0,0 +1,37 @@ +/* + * BNG Blaster (BBL) - IGMP Functions + * + * Christian Giese, October 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __BBL_IGMP_H__ +#define __BBL_IGMP_H__ + +int +bbl_igmp_ctrl_join(int fd, uint32_t session_id, json_t *arguments); + +int +bbl_igmp_ctrl_join_iter(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); + +int +bbl_igmp_ctrl_leave(int fd, uint32_t session_id, json_t *arguments); + +int +bbl_igmp_ctrl_leave_all(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +bbl_igmp_ctrl_info(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_igmp_ctrl_zapping_start(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +bbl_igmp_ctrl_zapping_stop(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +bbl_igmp_ctrl_zapping_stats(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/bbl_interface.c b/code/bngblaster/src/bbl_interface.c index 3bd398c3..3432d644 100644 --- a/code/bngblaster/src/bbl_interface.c +++ b/code/bngblaster/src/bbl_interface.c @@ -214,3 +214,39 @@ bbl_interface_get(char *interface_name) } return NULL; } + +int +bbl_interface_ctrl(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + + bbl_interface_s *interface; + json_t *root, *jobj, *jobj_array; + + jobj_array = json_array(); + + CIRCLEQ_FOREACH(interface, &g_ctx->interface_qhead, interface_qnode) { + jobj = json_pack("{ss si ss* ss* si }", + "name", interface->name, + "ifindex", interface->ifindex, + "type", interface_type_string(interface->type), + "state", interface_state_string(interface->state), + "state-transitions", interface->state_transitions); + if(jobj) { + json_array_append(jobj_array, jobj); + } + } + + root = json_pack("{ss si so*}", + "status", "ok", + "code", 200, + "interfaces", jobj_array); + + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + } + return result; +} \ No newline at end of file diff --git a/code/bngblaster/src/bbl_interface.h b/code/bngblaster/src/bbl_interface.h index 93773167..5fcd9170 100644 --- a/code/bngblaster/src/bbl_interface.h +++ b/code/bngblaster/src/bbl_interface.h @@ -55,4 +55,7 @@ bbl_interface_init(); bbl_interface_s * bbl_interface_get(char *interface_name); +int +bbl_interface_ctrl(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + #endif \ No newline at end of file diff --git a/code/bngblaster/src/bbl_l2tp.c b/code/bngblaster/src/bbl_l2tp.c index c456a96b..28483b1a 100644 --- a/code/bngblaster/src/bbl_l2tp.c +++ b/code/bngblaster/src/bbl_l2tp.c @@ -14,7 +14,7 @@ #include void -bbl_l2tp_send(bbl_l2tp_sunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, l2tp_message_t l2tp_type); +bbl_l2tp_send(bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, l2tp_message_t l2tp_type); const char* l2tp_message_string(l2tp_message_t type) @@ -71,7 +71,7 @@ l2tp_session_state_string(l2tp_session_state_t state) * bbl_l2tp_force_stop */ static void -bbl_l2tp_force_stop(bbl_l2tp_sunnel_s *l2tp_tunnel) +bbl_l2tp_force_stop(bbl_l2tp_tunnel_s *l2tp_tunnel) { bbl_l2tp_queue_s *q = NULL; bbl_l2tp_queue_s *q_del = NULL; @@ -149,7 +149,7 @@ bbl_l2tp_session_delete(bbl_l2tp_session_s *l2tp_session) } /** - * bbl_l2tp_sunnel_delete + * bbl_l2tp_tunnel_delete * * This function will free all dynamic memory for the given * l2tp tunnel instance including corresponding send queues. @@ -157,7 +157,7 @@ bbl_l2tp_session_delete(bbl_l2tp_session_s *l2tp_session) * @param l2tp_tunnel L2TP tunnel structure to be deleted. */ void -bbl_l2tp_sunnel_delete(bbl_l2tp_sunnel_s *l2tp_tunnel) +bbl_l2tp_tunnel_delete(bbl_l2tp_tunnel_s *l2tp_tunnel) { bbl_l2tp_queue_s *q; if(l2tp_tunnel) { @@ -205,13 +205,13 @@ bbl_l2tp_sunnel_delete(bbl_l2tp_sunnel_s *l2tp_tunnel) } /** - * bbl_l2tp_sunnel_update_state + * bbl_l2tp_tunnel_update_state * * @param l2tp_tunnel L2TP tunnel structure. * @param state New L2TP tunnel state. */ void -bbl_l2tp_sunnel_update_state(bbl_l2tp_sunnel_s *l2tp_tunnel, l2tp_tunnel_state_t state) { +bbl_l2tp_tunnel_update_state(bbl_l2tp_tunnel_s *l2tp_tunnel, l2tp_tunnel_state_t state) { if(l2tp_tunnel->state != state) { /* State has changed */ LOG(DEBUG, "L2TP Debug (%s) Tunnel %u state changed from %s to %s\n", @@ -241,12 +241,12 @@ bbl_l2tp_sunnel_update_state(bbl_l2tp_sunnel_s *l2tp_tunnel, l2tp_tunnel_state_t } /** - * bbl_l2tp_sunnel_tx_job + * bbl_l2tp_tunnel_tx_job */ void -bbl_l2tp_sunnel_tx_job(timer_s *timer) +bbl_l2tp_tunnel_tx_job(timer_s *timer) { - bbl_l2tp_sunnel_s *l2tp_tunnel = timer->data; + bbl_l2tp_tunnel_s *l2tp_tunnel = timer->data; bbl_network_interface_s *interface = l2tp_tunnel->interface; bbl_l2tp_queue_s *q = NULL; bbl_l2tp_queue_s *q_del = NULL; @@ -260,7 +260,7 @@ bbl_l2tp_sunnel_tx_job(timer_s *timer) l2tp_tunnel->timer_tx_active = false; if(l2tp_tunnel->state == BBL_L2TP_TUNNEL_SEND_STOPCCN) { if(CIRCLEQ_EMPTY(&l2tp_tunnel->txq_qhead)) { - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_TERMINATED); + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_TERMINATED); } } @@ -303,7 +303,7 @@ bbl_l2tp_sunnel_tx_job(timer_s *timer) l2tp_tunnel->result_code = 2; l2tp_tunnel->error_code = 6; l2tp_tunnel->error_message = "max retry"; - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); bbl_l2tp_force_stop(l2tp_tunnel); } /* When congestion occurs (indicated by the triggering of a @@ -336,12 +336,12 @@ bbl_l2tp_sunnel_tx_job(timer_s *timer) } /** - * bbl_l2tp_sunnel_control_job + * bbl_l2tp_tunnel_control_job */ void -bbl_l2tp_sunnel_control_job(timer_s *timer) +bbl_l2tp_tunnel_control_job(timer_s *timer) { - bbl_l2tp_sunnel_s *l2tp_tunnel = timer->data; + bbl_l2tp_tunnel_s *l2tp_tunnel = timer->data; l2tp_tunnel->state_seconds++; switch(l2tp_tunnel->state) { case BBL_L2TP_TUNNEL_WAIT_CTR_CONN: @@ -349,7 +349,7 @@ bbl_l2tp_sunnel_control_job(timer_s *timer) l2tp_tunnel->result_code = 2; l2tp_tunnel->error_code = 6; l2tp_tunnel->error_message = "timeout"; - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); bbl_l2tp_force_stop(l2tp_tunnel); } break; @@ -362,23 +362,23 @@ bbl_l2tp_sunnel_control_job(timer_s *timer) break; case BBL_L2TP_TUNNEL_RCVD_STOPCCN: if(l2tp_tunnel->state_seconds > 5) { - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_TERMINATED); + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_TERMINATED); } break; case BBL_L2TP_TUNNEL_SEND_STOPCCN: if(l2tp_tunnel->state_seconds > 30) { - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_TERMINATED); + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_TERMINATED); } break; case BBL_L2TP_TUNNEL_TERMINATED: timer->periodic = false; - bbl_l2tp_sunnel_delete(l2tp_tunnel); + bbl_l2tp_tunnel_delete(l2tp_tunnel); return; default: break; } if(!l2tp_tunnel->timer_tx_active) { - timer_add(&g_ctx->timer_root, &l2tp_tunnel->timer_tx, "L2TP TX", 0, L2TP_TX_WAIT_MS * MSEC, l2tp_tunnel, &bbl_l2tp_sunnel_tx_job); + timer_add(&g_ctx->timer_root, &l2tp_tunnel->timer_tx, "L2TP TX", 0, L2TP_TX_WAIT_MS * MSEC, l2tp_tunnel, &bbl_l2tp_tunnel_tx_job); l2tp_tunnel->timer_tx_active = true; } } @@ -394,7 +394,7 @@ bbl_l2tp_sunnel_control_job(timer_s *timer) * @param l2tp_type L2TP message type (SCCRP, ICRP, ...). */ void -bbl_l2tp_send(bbl_l2tp_sunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, l2tp_message_t l2tp_type) { +bbl_l2tp_send(bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, l2tp_message_t l2tp_type) { bbl_network_interface_s *interface = l2tp_tunnel->interface; bbl_l2tp_queue_s *q = calloc(1, sizeof(bbl_l2tp_queue_s)); @@ -459,7 +459,7 @@ bbl_l2tp_send(bbl_l2tp_sunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, } else { CIRCLEQ_INSERT_TAIL(&l2tp_tunnel->txq_qhead, q, txq_qnode); if(!l2tp_tunnel->timer_tx_active) { - timer_add(&g_ctx->timer_root, &l2tp_tunnel->timer_tx, "L2TP TX", 0, L2TP_TX_WAIT_MS * MSEC, l2tp_tunnel, &bbl_l2tp_sunnel_tx_job); + timer_add(&g_ctx->timer_root, &l2tp_tunnel->timer_tx, "L2TP TX", 0, L2TP_TX_WAIT_MS * MSEC, l2tp_tunnel, &bbl_l2tp_tunnel_tx_job); l2tp_tunnel->timer_tx_active = true; } } @@ -483,7 +483,7 @@ bbl_l2tp_send(bbl_l2tp_sunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, static void bbl_l2tp_send_data(bbl_l2tp_session_s *l2tp_session, uint16_t protocol, void *next) { - bbl_l2tp_sunnel_s *l2tp_tunnel = l2tp_session->tunnel; + bbl_l2tp_tunnel_s *l2tp_tunnel = l2tp_session->tunnel; bbl_l2tp_server_s *l2tp_server = l2tp_tunnel->server; bbl_network_interface_s *interface = l2tp_tunnel->interface; bbl_l2tp_queue_s *q = calloc(1, sizeof(bbl_l2tp_queue_s)); @@ -542,8 +542,8 @@ bbl_l2tp_sccrq_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth bbl_ipv4_s *ipv4 = (bbl_ipv4_s*)eth->next; bbl_l2tp_server_s *l2tp_server = g_ctx->config.l2tp_server; - bbl_l2tp_sunnel_s *l2tp_tunnel; - bbl_l2tp_sunnel_s *l2tp_tunnel2; + bbl_l2tp_tunnel_s *l2tp_tunnel; + bbl_l2tp_tunnel_s *l2tp_tunnel2; bbl_l2tp_session_s *l2tp_session; dict_insert_result result; @@ -557,7 +557,7 @@ bbl_l2tp_sccrq_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth l2tp_server->host_name, format_ipv4_address(&ipv4->src)); /* Init tunnel ... */ - l2tp_tunnel = calloc(1, sizeof(bbl_l2tp_sunnel_s)); + l2tp_tunnel = calloc(1, sizeof(bbl_l2tp_tunnel_s)); g_ctx->l2tp_tunnels++; CIRCLEQ_INIT(&l2tp_tunnel->txq_qhead); CIRCLEQ_INIT(&l2tp_tunnel->session_qhead); @@ -574,7 +574,7 @@ bbl_l2tp_sccrq_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth interface->stats.l2tp_control_rx++; /* Decode received attributes and store in tunnel */ if(!bbl_l2tp_avp_decode_tunnel(l2tp, l2tp_tunnel)) { - bbl_l2tp_sunnel_delete(l2tp_tunnel); + bbl_l2tp_tunnel_delete(l2tp_tunnel); return; } if(!l2tp_tunnel->peer_tunnel_id || @@ -582,7 +582,7 @@ bbl_l2tp_sccrq_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth LOG(ERROR, "L2TP Error (%s) Invalid SCCRQ received from %s\n", l2tp_server->host_name, format_ipv4_address(&ipv4->src)); - bbl_l2tp_sunnel_delete(l2tp_tunnel); + bbl_l2tp_tunnel_delete(l2tp_tunnel); return; } @@ -591,7 +591,7 @@ bbl_l2tp_sccrq_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth if(l2tp_tunnel2->peer_ip == l2tp_tunnel->peer_ip && l2tp_tunnel2->peer_tunnel_id == l2tp_tunnel->peer_tunnel_id) { /* Seems to be an SCCRQ retry ... */ - bbl_l2tp_sunnel_delete(l2tp_tunnel); + bbl_l2tp_tunnel_delete(l2tp_tunnel); return; } } @@ -620,7 +620,7 @@ bbl_l2tp_sccrq_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth LOG(ERROR, "L2TP Error (%s) Failed to add tunnel session\n", l2tp_tunnel->server->host_name); free(l2tp_session); - bbl_l2tp_sunnel_delete(l2tp_tunnel); + bbl_l2tp_tunnel_delete(l2tp_tunnel); return; } *result.datum_ptr = l2tp_session; @@ -668,7 +668,7 @@ bbl_l2tp_sccrq_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth CIRCLEQ_INSERT_TAIL(&l2tp_server->tunnel_qhead, l2tp_tunnel, tunnel_qnode); /* Start control job * WARNING: Do not change the interval! */ - timer_add_periodic(&g_ctx->timer_root, &l2tp_tunnel->timer_ctrl, "L2TP Control", 1, 0, l2tp_tunnel, &bbl_l2tp_sunnel_control_job); + timer_add_periodic(&g_ctx->timer_root, &l2tp_tunnel->timer_ctrl, "L2TP Control", 1, 0, l2tp_tunnel, &bbl_l2tp_tunnel_control_job); /* Prepare ZLB */ bbl_l2tp_send(l2tp_tunnel, NULL, L2TP_MESSAGE_ZLB); /* Send response */ @@ -685,7 +685,7 @@ bbl_l2tp_sccrq_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth static void bbl_l2tp_scccn_rx(bbl_network_interface_s *interface, - bbl_l2tp_sunnel_s *l2tp_tunnel, + bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_ethernet_header_s *eth, bbl_l2tp_s *l2tp) { uint8_t digest[L2TP_MD5_DIGEST_LEN]; @@ -700,7 +700,7 @@ bbl_l2tp_scccn_rx(bbl_network_interface_s *interface, LOG(ERROR, "L2TP Error (%s) Invalid SCCCN received from %s\n", l2tp_tunnel->server->host_name, format_ipv4_address(&l2tp_tunnel->peer_ip)); - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); l2tp_tunnel->result_code = 2; l2tp_tunnel->error_code = 6; l2tp_tunnel->error_message = "decode error"; @@ -719,7 +719,7 @@ bbl_l2tp_scccn_rx(bbl_network_interface_s *interface, LOG(ERROR, "L2TP Error (%s) Wrong challenge response in SCCCN from %s\n", l2tp_tunnel->server->host_name, format_ipv4_address(&l2tp_tunnel->peer_ip)); - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); l2tp_tunnel->result_code = 2; l2tp_tunnel->error_code = 6; l2tp_tunnel->error_message = "challenge authentication failed"; @@ -730,7 +730,7 @@ bbl_l2tp_scccn_rx(bbl_network_interface_s *interface, LOG(ERROR, "L2TP Error (%s) Missing challenge response in SCCCN from %s\n", l2tp_tunnel->server->host_name, format_ipv4_address(&l2tp_tunnel->peer_ip)); - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); l2tp_tunnel->result_code = 2; l2tp_tunnel->error_code = 6; l2tp_tunnel->error_message = "missing challenge response"; @@ -738,25 +738,25 @@ bbl_l2tp_scccn_rx(bbl_network_interface_s *interface, return; } } - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_ESTABLISHED); + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_ESTABLISHED); } } static void bbl_l2tp_stopccn_rx(bbl_network_interface_s *interface, - bbl_l2tp_sunnel_s *l2tp_tunnel, + bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_ethernet_header_s *eth, bbl_l2tp_s *l2tp) { UNUSED(interface); UNUSED(eth); UNUSED(l2tp); - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_RCVD_STOPCCN); + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_RCVD_STOPCCN); } static void bbl_l2tp_csun_rx(bbl_network_interface_s *interface, - bbl_l2tp_sunnel_s *l2tp_tunnel, + bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_ethernet_header_s *eth, bbl_l2tp_s *l2tp) { UNUSED(interface); @@ -767,7 +767,7 @@ bbl_l2tp_csun_rx(bbl_network_interface_s *interface, static void bbl_l2tp_icrq_rx(bbl_network_interface_s *interface, - bbl_l2tp_sunnel_s *l2tp_tunnel, + bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_ethernet_header_s *eth, bbl_l2tp_s *l2tp) { dict_insert_result result; @@ -824,7 +824,7 @@ bbl_l2tp_iccn_rx(bbl_network_interface_s *interface, bbl_l2tp_session_s *l2tp_session, bbl_ethernet_header_s *eth, bbl_l2tp_s *l2tp) { - bbl_l2tp_sunnel_s *l2tp_tunnel = l2tp_session->tunnel; + bbl_l2tp_tunnel_s *l2tp_tunnel = l2tp_session->tunnel; UNUSED(interface); UNUSED(eth); @@ -857,7 +857,7 @@ bbl_l2tp_cdn_rx(bbl_network_interface_s *interface, bbl_l2tp_session_s *l2tp_session, bbl_ethernet_header_s *eth, bbl_l2tp_s *l2tp) { - bbl_l2tp_sunnel_s *l2tp_tunnel = l2tp_session->tunnel; + bbl_l2tp_tunnel_s *l2tp_tunnel = l2tp_session->tunnel; UNUSED(interface); UNUSED(eth); @@ -1034,7 +1034,7 @@ bbl_l2tp_handler_rx(bbl_network_interface_s *interface, { bbl_ipv4_s *ipv4 = (bbl_ipv4_s*)eth->next; bbl_l2tp_session_s *l2tp_session; - bbl_l2tp_sunnel_s *l2tp_tunnel; + bbl_l2tp_tunnel_s *l2tp_tunnel; l2tp_key_t key = {0}; void **search = NULL; @@ -1085,7 +1085,7 @@ bbl_l2tp_handler_rx(bbl_network_interface_s *interface, /* Start tx timer */ if(!l2tp_tunnel->timer_tx_active) { timer_add(&g_ctx->timer_root, &l2tp_tunnel->timer_tx, "L2TP TX", - 0, L2TP_TX_WAIT_MS * MSEC, l2tp_tunnel, &bbl_l2tp_sunnel_tx_job); + 0, L2TP_TX_WAIT_MS * MSEC, l2tp_tunnel, &bbl_l2tp_tunnel_tx_job); l2tp_tunnel->timer_tx_active = true; } } @@ -1174,7 +1174,7 @@ bbl_l2tp_handler_rx(bbl_network_interface_s *interface, interface->stats.l2tp_control_rx_dup++; if(!l2tp_tunnel->timer_tx_active) { timer_add(&g_ctx->timer_root, &l2tp_tunnel->timer_tx, "L2TP TX", - 0, L2TP_TX_WAIT_MS * MSEC, l2tp_tunnel, &bbl_l2tp_sunnel_tx_job); + 0, L2TP_TX_WAIT_MS * MSEC, l2tp_tunnel, &bbl_l2tp_tunnel_tx_job); l2tp_tunnel->timer_tx_active = true; } } else { @@ -1204,11 +1204,11 @@ void bbl_l2tp_stop_all_tunnel() { bbl_l2tp_server_s *l2tp_server = g_ctx->config.l2tp_server; - bbl_l2tp_sunnel_s *l2tp_tunnel; + bbl_l2tp_tunnel_s *l2tp_tunnel; while(l2tp_server) { CIRCLEQ_FOREACH(l2tp_tunnel, &l2tp_server->tunnel_qhead, tunnel_qnode) { if(l2tp_tunnel->state < BBL_L2TP_TUNNEL_SEND_STOPCCN) { - bbl_l2tp_sunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); l2tp_tunnel->result_code = 6; bbl_l2tp_force_stop(l2tp_tunnel); } @@ -1216,3 +1216,324 @@ bbl_l2tp_stop_all_tunnel() l2tp_server = l2tp_server->next; } } + +static json_t * +l2tp_session_json(bbl_l2tp_session_s *l2tp_session) +{ + char *proxy_auth_response = NULL; + + if(l2tp_session->proxy_auth_response) { + if(l2tp_session->proxy_auth_type == L2TP_PROXY_AUTH_TYPE_PAP) { + proxy_auth_response = (char*)l2tp_session->proxy_auth_response; + } else { + proxy_auth_response = "0x..."; + } + } + + return json_pack("{ss si si si si si ss 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, + "peer-tunnel-id", l2tp_session->tunnel->peer_tunnel_id, + "peer-session-id", l2tp_session->peer_session_id, + "peer-proxy-auth-type", l2tp_session->proxy_auth_type, + "peer-proxy-auth-name", string_or_na(l2tp_session->proxy_auth_name), + "peer-proxy-auth-response", string_or_na(proxy_auth_response), + "peer-called-number", string_or_na(l2tp_session->peer_called_number), + "peer-calling-number", string_or_na(l2tp_session->peer_calling_number), + "peer-sub-address", string_or_na(l2tp_session->peer_sub_address), + "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), + "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); +} + +/* Control Socket Commands */ + +int +bbl_l2tp_ctrl_sessions(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) +{ + int result = 0; + json_t *root, *sessions; + + bbl_l2tp_server_s *l2tp_server = g_ctx->config.l2tp_server; + bbl_l2tp_tunnel_s *l2tp_tunnel; + bbl_l2tp_session_s *l2tp_session; + l2tp_key_t l2tp_key = {0}; + void **search = NULL; + + int l2tp_tunnel_id = 0; + int l2tp_session_id = 0; + + json_unpack(arguments, "{s:i}", "tunnel-id", &l2tp_tunnel_id); + json_unpack(arguments, "{s:i}", "session-id", &l2tp_session_id); + + sessions = json_array(); + + if(l2tp_tunnel_id && l2tp_session_id) { + l2tp_key.tunnel_id = l2tp_tunnel_id; + l2tp_key.session_id = l2tp_session_id; + search = dict_search(g_ctx->l2tp_session_dict, &l2tp_key); + if(search) { + l2tp_session = *search; + json_array_append(sessions, l2tp_session_json(l2tp_session)); + } else { + result = bbl_ctrl_status(fd, "warning", 404, "session not found"); + json_decref(sessions); + return result; + } + } else if (l2tp_tunnel_id) { + l2tp_key.tunnel_id = l2tp_tunnel_id; + search = dict_search(g_ctx->l2tp_session_dict, &l2tp_key); + if(search) { + l2tp_session = *search; + l2tp_tunnel = l2tp_session->tunnel; + CIRCLEQ_FOREACH(l2tp_session, &l2tp_tunnel->session_qhead, session_qnode) { + if(!l2tp_session->key.session_id) continue; /* skip tunnel session */ + json_array_append(sessions, l2tp_session_json(l2tp_session)); + } + } else { + result = bbl_ctrl_status(fd, "warning", 404, "tunnel not found"); + json_decref(sessions); + return result; + } + } else { + while(l2tp_server) { + CIRCLEQ_FOREACH(l2tp_tunnel, &l2tp_server->tunnel_qhead, tunnel_qnode) { + CIRCLEQ_FOREACH(l2tp_session, &l2tp_tunnel->session_qhead, session_qnode) { + if(!l2tp_session->key.session_id) continue; /* skip tunnel session */ + json_array_append(sessions, l2tp_session_json(l2tp_session)); + } + } + l2tp_server = l2tp_server->next; + } + } + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "l2tp-sessions", sessions); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(sessions); + } + return result; +} + +int +bbl_l2tp_ctrl_csurq(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) +{ + json_t *sessions, *number; + + bbl_l2tp_tunnel_s *l2tp_tunnel; + bbl_l2tp_session_s *l2tp_session; + l2tp_key_t l2tp_key = {0}; + void **search = NULL; + + uint16_t l2tp_session_id = 0; + int l2tp_tunnel_id = 0; + int size, i; + + /* Unpack further arguments */ + if (json_unpack(arguments, "{s:i}", "tunnel-id", &l2tp_tunnel_id) != 0) { + return bbl_ctrl_status(fd, "error", 400, "missing tunnel-id"); + } + l2tp_key.tunnel_id = l2tp_tunnel_id; + search = dict_search(g_ctx->l2tp_session_dict, &l2tp_key); + if(search) { + l2tp_session = *search; + l2tp_tunnel = l2tp_session->tunnel; + if(l2tp_tunnel->state != BBL_L2TP_TUNNEL_ESTABLISHED) { + return bbl_ctrl_status(fd, "warning", 400, "tunnel not established"); + } + sessions = json_object_get(arguments, "sessions"); + if (json_is_array(sessions)) { + size = json_array_size(sessions); + l2tp_tunnel->csurq_requests_len = size; + l2tp_tunnel->csurq_requests = malloc(size * sizeof(uint16_t)); + for (i = 0; i < size; i++) { + number = json_array_get(sessions, i); + if(json_is_number(number)) { + l2tp_session_id = json_number_value(number); + l2tp_tunnel->csurq_requests[i] = l2tp_session_id; + } + } + bbl_l2tp_send(l2tp_tunnel, NULL, L2TP_MESSAGE_CSURQ); + return bbl_ctrl_status(fd, "ok", 200, NULL); + } else { + return bbl_ctrl_status(fd, "error", 400, "invalid request"); + } + } else { + return bbl_ctrl_status(fd, "warning", 404, "tunnel not found"); + } +} + +int +bbl_l2tp_ctrl_tunnel_terminate(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) +{ + bbl_l2tp_tunnel_s *l2tp_tunnel; + bbl_l2tp_session_s *l2tp_session; + l2tp_key_t l2tp_key = {0}; + void **search = NULL; + + int l2tp_tunnel_id = 0; + int result_code; + int error_code; + char *error_message; + + /* Unpack further arguments */ + if (json_unpack(arguments, "{s:i}", "tunnel-id", &l2tp_tunnel_id) != 0) { + return bbl_ctrl_status(fd, "error", 400, "missing tunnel-id"); + } + l2tp_key.tunnel_id = l2tp_tunnel_id; + search = dict_search(g_ctx->l2tp_session_dict, &l2tp_key); + if(search) { + l2tp_session = *search; + l2tp_tunnel = l2tp_session->tunnel; + if(l2tp_tunnel->state != BBL_L2TP_TUNNEL_ESTABLISHED) { + return bbl_ctrl_status(fd, "warning", 400, "tunnel not established"); + } + bbl_l2tp_tunnel_update_state(l2tp_tunnel, BBL_L2TP_TUNNEL_SEND_STOPCCN); + if (json_unpack(arguments, "{s:i}", "result-code", &result_code) != 0) { + result_code = 1; + } + l2tp_tunnel->result_code = result_code; + if (json_unpack(arguments, "{s:i}", "error-code", &error_code) != 0) { + error_code = 0; + } + l2tp_tunnel->error_code = error_code; + if (json_unpack(arguments, "{s:s}", "error-message", &error_message) != 0) { + error_message = NULL; + } + l2tp_tunnel->error_message = error_message; + bbl_l2tp_send(l2tp_tunnel, NULL, L2TP_MESSAGE_STOPCCN); + return bbl_ctrl_status(fd, "ok", 200, NULL); + } else { + return bbl_ctrl_status(fd, "warning", 404, "tunnel not found"); + } +} + +int +bbl_l2tp_ctrl_session_terminate(int fd, uint32_t session_id, json_t *arguments) +{ + bbl_session_s *session; + bbl_l2tp_tunnel_s *l2tp_tunnel; + bbl_l2tp_session_s *l2tp_session; + + int result_code; + int error_code; + char *error_message; + int disconnect_code; + int disconnect_protocol; + int disconnect_direction; + char* disconnect_message; + + if(session_id == 0) { + /* session-id is mandatory */ + return bbl_ctrl_status(fd, "error", 400, "missing session-id"); + } + + session = bbl_session_get(session_id); + if(session) { + l2tp_session = session->l2tp_session; + if(!l2tp_session) { + return bbl_ctrl_status(fd, "error", 400, "no L2TP session"); + } + l2tp_tunnel = l2tp_session->tunnel; + if(l2tp_tunnel->state != BBL_L2TP_TUNNEL_ESTABLISHED) { + return bbl_ctrl_status(fd, "warning", 400, "tunnel not established"); + } + if(l2tp_session->state != BBL_L2TP_SESSION_ESTABLISHED) { + return bbl_ctrl_status(fd, "warning", 400, "session not established"); + } + if (json_unpack(arguments, "{s:i}", "result-code", &result_code) != 0) { + result_code = 2; + } + l2tp_session->result_code = result_code; + if (json_unpack(arguments, "{s:i}", "error-code", &error_code) != 0) { + error_code = 0; + } + l2tp_session->error_code = error_code; + if (json_unpack(arguments, "{s:s}", "error-message", &error_message) != 0) { + error_message = NULL; + } + l2tp_session->error_message = error_message; + if (json_unpack(arguments, "{s:i}", "disconnect-code", &disconnect_code) != 0) { + disconnect_code = 0; + } + l2tp_session->disconnect_code = disconnect_code; + if (json_unpack(arguments, "{s:i}", "disconnect-protocol", &disconnect_protocol) != 0) { + disconnect_protocol = 0; + } + l2tp_session->disconnect_protocol = disconnect_protocol; + if (json_unpack(arguments, "{s:i}", "disconnect-direction", &disconnect_direction) != 0) { + disconnect_direction = 0; + } + l2tp_session->disconnect_direction = disconnect_direction; + if (json_unpack(arguments, "{s:s}", "disconnect-message", &disconnect_message) != 0) { + disconnect_message = NULL; + } + l2tp_session->disconnect_message = disconnect_message; + bbl_l2tp_send(l2tp_tunnel, l2tp_session, L2TP_MESSAGE_CDN); + bbl_l2tp_session_delete(l2tp_session); + return bbl_ctrl_status(fd, "ok", 200, NULL); + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } +} + +int +bbl_l2tp_ctrl_tunnels(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root, *tunnels, *tunnel; + + bbl_l2tp_server_s *l2tp_server = g_ctx->config.l2tp_server; + bbl_l2tp_tunnel_s *l2tp_tunnel; + + tunnels = json_array(); + + while(l2tp_server) { + CIRCLEQ_FOREACH(l2tp_tunnel, &l2tp_server->tunnel_qhead, tunnel_qnode) { + + tunnel = json_pack("{ss ss ss si si ss ss ss ss si si si si si si si}", + "state", l2tp_tunnel_state_string(l2tp_tunnel->state), + "server-name", l2tp_server->host_name, + "server-address", format_ipv4_address(&l2tp_server->ip), + "tunnel-id", l2tp_tunnel->tunnel_id, + "peer-tunnel-id", l2tp_tunnel->peer_tunnel_id, + "peer-name", string_or_na(l2tp_tunnel->peer_name), + "peer-address", format_ipv4_address(&l2tp_tunnel->peer_ip), + "peer-vendor", string_or_na(l2tp_tunnel->peer_vendor), + "secret", string_or_na(l2tp_server->secret), + "control-packets-rx", l2tp_tunnel->stats.control_rx, + "control-packets-rx-dup", l2tp_tunnel->stats.control_rx_dup, + "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, + "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; + } + + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "l2tp-tunnels", tunnels); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(tunnels); + } + return result; +} \ No newline at end of file diff --git a/code/bngblaster/src/bbl_l2tp.h b/code/bngblaster/src/bbl_l2tp.h index efd3d9a5..34d54bf4 100644 --- a/code/bngblaster/src/bbl_l2tp.h +++ b/code/bngblaster/src/bbl_l2tp.h @@ -87,7 +87,7 @@ typedef struct bbl_l2tp_server_ /* List of L2TP tunnel instances * for the corresponding server. */ - CIRCLEQ_HEAD(tunnel_, bbl_l2tp_sunnel_) tunnel_qhead; + CIRCLEQ_HEAD(tunnel_, bbl_l2tp_tunnel_) tunnel_qhead; } bbl_l2tp_server_s; /* L2TP Session Key */ @@ -107,15 +107,15 @@ typedef struct bbl_l2tp_queue_ uint8_t packet[L2TP_MAX_PACKET_SIZE]; uint16_t packet_len; struct timespec last_tx_time; - struct bbl_l2tp_sunnel_ *tunnel; + struct bbl_l2tp_tunnel_ *tunnel; CIRCLEQ_ENTRY(bbl_l2tp_queue_) txq_qnode; /* TX queue */ CIRCLEQ_ENTRY(bbl_l2tp_queue_) tx_qnode; /* TX request */ } bbl_l2tp_queue_s; /* L2TP Tunnel Instance */ -typedef struct bbl_l2tp_sunnel_ +typedef struct bbl_l2tp_tunnel_ { - CIRCLEQ_ENTRY(bbl_l2tp_sunnel_) tunnel_qnode; + CIRCLEQ_ENTRY(bbl_l2tp_tunnel_) tunnel_qnode; CIRCLEQ_HEAD(session_, bbl_l2tp_session_) session_qhead; CIRCLEQ_HEAD(txq_, bbl_l2tp_queue_) txq_qhead; @@ -193,14 +193,14 @@ typedef struct bbl_l2tp_sunnel_ char *peer_name; char *peer_vendor; -} bbl_l2tp_sunnel_s; +} bbl_l2tp_tunnel_s; /* L2TP Session Instance */ typedef struct bbl_l2tp_session_ { CIRCLEQ_ENTRY(bbl_l2tp_session_) session_qnode; - bbl_l2tp_sunnel_s *tunnel; + bbl_l2tp_tunnel_s *tunnel; l2tp_session_state_t state; bbl_session_s *pppoe_session; @@ -261,18 +261,23 @@ typedef struct bbl_l2tp_session_ char *peer_aci; } bbl_l2tp_session_s; -const char* l2tp_message_string(l2tp_message_t type); -const char* l2tp_tunnel_state_string(l2tp_tunnel_state_t state); -const char* l2tp_session_state_string(l2tp_session_state_t state); +const char* +l2tp_message_string(l2tp_message_t type); + +const char* +l2tp_tunnel_state_string(l2tp_tunnel_state_t state); + +const char* +l2tp_session_state_string(l2tp_session_state_t state); void bbl_l2tp_session_delete(bbl_l2tp_session_s *l2tp_session); void -bbl_l2tp_sunnel_update_state(bbl_l2tp_sunnel_s *l2tp_tunnel, l2tp_tunnel_state_t state); +bbl_l2tp_tunnel_update_state(bbl_l2tp_tunnel_s *l2tp_tunnel, l2tp_tunnel_state_t state); void -bbl_l2tp_send(bbl_l2tp_sunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, l2tp_message_t l2tp_type); +bbl_l2tp_send(bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, l2tp_message_t l2tp_type); void bbl_l2tp_handler_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth, bbl_l2tp_s *l2tp); @@ -280,4 +285,19 @@ bbl_l2tp_handler_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *e void bbl_l2tp_stop_all_tunnel(); +int +bbl_l2tp_ctrl_sessions(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); + +int +bbl_l2tp_ctrl_csurq(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); + +int +bbl_l2tp_ctrl_tunnel_terminate(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); + +int +bbl_l2tp_ctrl_session_terminate(int fd, uint32_t session_id, json_t *arguments); + +int +bbl_l2tp_ctrl_tunnels(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + #endif diff --git a/code/bngblaster/src/bbl_l2tp_avp.c b/code/bngblaster/src/bbl_l2tp_avp.c index 59692f12..6ee5914f 100644 --- a/code/bngblaster/src/bbl_l2tp_avp.c +++ b/code/bngblaster/src/bbl_l2tp_avp.c @@ -172,7 +172,7 @@ bbl_l2tp_avp_encode_disconnect_code(uint8_t **_buf, uint16_t *len, /* bbl_l2tp_avp_unhide */ static bool -bbl_l2tp_avp_unhide(bbl_l2tp_sunnel_s *l2tp_tunnel, bbl_l2tp_avp_t *avp, uint8_t +bbl_l2tp_avp_unhide(bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_l2tp_avp_t *avp, uint8_t *random_vector, uint16_t random_vector_len) { MD5_CTX ctx; @@ -236,7 +236,7 @@ bbl_l2tp_avp_unhide(bbl_l2tp_sunnel_s *l2tp_tunnel, bbl_l2tp_avp_t *avp, uint8_t } bool -bbl_l2tp_avp_decode_session(bbl_l2tp_s *l2tp, bbl_l2tp_sunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session) +bbl_l2tp_avp_decode_session(bbl_l2tp_s *l2tp, bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session) { uint8_t *buf = l2tp->payload; uint16_t len = l2tp->payload_len; @@ -483,7 +483,7 @@ bbl_l2tp_avp_decode_session(bbl_l2tp_s *l2tp, bbl_l2tp_sunnel_s *l2tp_tunnel, bb } bool -bbl_l2tp_avp_decode_tunnel(bbl_l2tp_s *l2tp, bbl_l2tp_sunnel_s *l2tp_tunnel) +bbl_l2tp_avp_decode_tunnel(bbl_l2tp_s *l2tp, bbl_l2tp_tunnel_s *l2tp_tunnel) { uint8_t *buf = l2tp->payload; uint16_t len = l2tp->payload_len; @@ -639,7 +639,7 @@ bbl_l2tp_avp_decode_tunnel(bbl_l2tp_s *l2tp, bbl_l2tp_sunnel_s *l2tp_tunnel) } bool -bbl_l2tp_avp_decode_csun(bbl_l2tp_s *l2tp, bbl_l2tp_sunnel_s *l2tp_tunnel) +bbl_l2tp_avp_decode_csun(bbl_l2tp_s *l2tp, bbl_l2tp_tunnel_s *l2tp_tunnel) { uint8_t *buf = l2tp->payload; uint16_t len = l2tp->payload_len; @@ -708,7 +708,7 @@ bbl_l2tp_avp_decode_csun(bbl_l2tp_s *l2tp, bbl_l2tp_sunnel_s *l2tp_tunnel) } void -bbl_l2tp_avp_encode_attributes(bbl_l2tp_sunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, +bbl_l2tp_avp_encode_attributes(bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, l2tp_message_t l2tp_type, uint8_t *buf, uint16_t *len) { bbl_l2tp_avp_t avp = {0}; diff --git a/code/bngblaster/src/bbl_l2tp_avp.h b/code/bngblaster/src/bbl_l2tp_avp.h index e8709920..ffb49886 100644 --- a/code/bngblaster/src/bbl_l2tp_avp.h +++ b/code/bngblaster/src/bbl_l2tp_avp.h @@ -74,16 +74,16 @@ typedef struct bbl_l2tp_avp_ } bbl_l2tp_avp_t; bool -bbl_l2tp_avp_decode_session(bbl_l2tp_s *l2tp, bbl_l2tp_sunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session); +bbl_l2tp_avp_decode_session(bbl_l2tp_s *l2tp, bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session); bool -bbl_l2tp_avp_decode_tunnel(bbl_l2tp_s *l2tp, bbl_l2tp_sunnel_s *l2tp_tunnel); +bbl_l2tp_avp_decode_tunnel(bbl_l2tp_s *l2tp, bbl_l2tp_tunnel_s *l2tp_tunnel); bool -bbl_l2tp_avp_decode_csun(bbl_l2tp_s *l2tp, bbl_l2tp_sunnel_s *l2tp_tunnel); +bbl_l2tp_avp_decode_csun(bbl_l2tp_s *l2tp, bbl_l2tp_tunnel_s *l2tp_tunnel); void -bbl_l2tp_avp_encode_attributes(bbl_l2tp_sunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, +bbl_l2tp_avp_encode_attributes(bbl_l2tp_tunnel_s *l2tp_tunnel, bbl_l2tp_session_s *l2tp_session, l2tp_message_t l2tp_type, uint8_t *buf, uint16_t *len); #endif diff --git a/code/bngblaster/src/bbl_lag.c b/code/bngblaster/src/bbl_lag.c index e4ed3000..4ef8eddb 100644 --- a/code/bngblaster/src/bbl_lag.c +++ b/code/bngblaster/src/bbl_lag.c @@ -7,7 +7,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ #include "bbl.h" -#include "../bbl_ctrl.h" uint16_t g_lag_port_id = 1; @@ -331,7 +330,7 @@ bbl_lag_json(bbl_lag_s *lag) } int -bbl_lag_ctrl_info(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) +bbl_lag_ctrl_info(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) { int result = 0; diff --git a/code/bngblaster/src/bbl_lag.h b/code/bngblaster/src/bbl_lag.h index d4734107..76501ec3 100644 --- a/code/bngblaster/src/bbl_lag.h +++ b/code/bngblaster/src/bbl_lag.h @@ -76,6 +76,6 @@ bbl_lag_rx_lacp(bbl_interface_s *interface, bbl_ethernet_header_s *eth); int -bbl_lag_ctrl_info(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments); +bbl_lag_ctrl_info(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); #endif \ No newline at end of file diff --git a/code/bngblaster/src/bbl_li.c b/code/bngblaster/src/bbl_li.c index fc14dc8b..80c22ccd 100644 --- a/code/bngblaster/src/bbl_li.c +++ b/code/bngblaster/src/bbl_li.c @@ -136,4 +136,58 @@ bbl_qmx_li_handler_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s break; } } +} + +/* Control Socket Commands */ + +int +bbl_li_ctrl_flows(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root, *flows, *flow; + bbl_li_flow_t *li_flow; + struct dict_itor *itor; + + flows = json_array(); + itor = dict_itor_new(g_ctx->li_flow_dict); + dict_itor_first(itor); + for (; dict_itor_valid(itor); dict_itor_next(itor)) { + li_flow = (bbl_li_flow_t*)*dict_itor_datum(itor); + if(li_flow) { + flow = json_pack("{ss si ss si ss ss ss si si si si si si si si si si si si}", + "source-address", format_ipv4_address(&li_flow->src_ipv4), + "source-port", li_flow->src_port, + "destination-address", format_ipv4_address(&li_flow->dst_ipv4), + "destination-port", li_flow->dst_port, + "direction", bbl_li_direction_string(li_flow->direction), + "packet-type", bbl_li_packet_type_string(li_flow->packet_type), + "sub-packet-type", bbl_li_sub_packet_type_string(li_flow->sub_packet_type), + "liid", li_flow->liid, + "bytes-rx", li_flow->bytes_rx, + "packets-rx", li_flow->packets_rx, + "packets-rx-ipv4", li_flow->packets_rx_ipv4, + "packets-rx-ipv4-tcp", li_flow->packets_rx_ipv4_tcp, + "packets-rx-ipv4-udp", li_flow->packets_rx_ipv4_udp, + "packets-rx-ipv4-host-internal", li_flow->packets_rx_ipv4_internal, + "packets-rx-ipv6", li_flow->packets_rx_ipv6, + "packets-rx-ipv6-tcp", li_flow->packets_rx_ipv6_tcp, + "packets-rx-ipv6-udp", li_flow->packets_rx_ipv6_udp, + "packets-rx-ipv6-host-internal", li_flow->packets_rx_ipv6_internal, + "packets-rx-ipv6-no-next-header", li_flow->packets_rx_ipv6_no_next_header); + json_array_append(flows, flow); + } + } + dict_itor_free(itor); + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "li-flows", flows); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(flows); + } + return result; } \ No newline at end of file diff --git a/code/bngblaster/src/bbl_li.h b/code/bngblaster/src/bbl_li.h index c2236f37..e3eb5ee2 100644 --- a/code/bngblaster/src/bbl_li.h +++ b/code/bngblaster/src/bbl_li.h @@ -37,10 +37,10 @@ typedef struct bbl_li_flow_ uint64_t packets_rx_ipv6_no_next_header; } bbl_li_flow_t; -const char* bbl_li_direction_string(uint8_t direction); -const char* bbl_li_packet_type_string(uint8_t packet_type); -const char* bbl_li_sub_packet_type_string(uint8_t sub_packet_type); +void +bbl_qmx_li_handler_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth, bbl_qmx_li_s *qmx_li); -void bbl_qmx_li_handler_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth, bbl_qmx_li_s *qmx_li); +int +bbl_li_ctrl_flows(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); #endif \ No newline at end of file diff --git a/code/bngblaster/src/bbl_network.c b/code/bngblaster/src/bbl_network.c index dd0185de..ea827cb7 100644 --- a/code/bngblaster/src/bbl_network.c +++ b/code/bngblaster/src/bbl_network.c @@ -414,4 +414,76 @@ bbl_network_rx_handler(bbl_network_interface_s *interface, break; } interface->stats.unknown++; +} + +static json_t * +bbl_network_interface_json(bbl_network_interface_s *interface) +{ + return json_pack("{ss si ss si si si si si si si si si si si si si si si si si si si si si si si si si si si si si si}", + "name", interface->name, + "ifindex", interface->ifindex, + "type", "network", + "tx-packets", interface->stats.packets_tx, + "tx-bytes", interface->stats.bytes_tx, + "tx-pps", interface->stats.rate_packets_tx.avg, + "tx-kbps", interface->stats.rate_bytes_tx.avg * 8 / 1000, + "rx-packets", interface->stats.packets_rx, + "rx-bytes", interface->stats.bytes_rx, + "rx-pps", interface->stats.rate_packets_rx.avg, + "rx-kbps", interface->stats.rate_bytes_rx.avg * 8 / 1000, + "tx-packets-multicast", interface->stats.mc_tx, + "tx-pps-multicast", interface->stats.rate_mc_tx.avg, + "tx-packets-session-ipv4", interface->stats.session_ipv4_tx, + "tx-pps-session-ipv4", interface->stats.rate_session_ipv4_tx.avg, + "rx-packets-session-ipv4", interface->stats.session_ipv4_rx, + "rx-pps-session-ipv4", interface->stats.rate_session_ipv4_rx.avg, + "rx-loss-packets-session-ipv4", interface->stats.session_ipv4_loss, + "tx-packets-session-ipv6", interface->stats.session_ipv6_tx, + "tx-pps-session-ipv6", interface->stats.rate_session_ipv6_tx.avg, + "rx-packets-session-ipv6", interface->stats.session_ipv6_rx, + "rx-pps-session-ipv6", interface->stats.rate_session_ipv6_rx.avg, + "rx-loss-packets-session-ipv6", interface->stats.session_ipv6_loss, + "tx-packets-session-ipv6pd", interface->stats.session_ipv6pd_tx, + "tx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_tx.avg, + "rx-packets-session-ipv6pd", interface->stats.session_ipv6pd_rx, + "rx-pps-session-ipv6pd", interface->stats.rate_session_ipv6pd_rx.avg, + "rx-loss-packets-session-ipv6pd", interface->stats.session_ipv6pd_loss, + "tx-packets-streams", interface->stats.stream_tx, + "tx-pps-streams", interface->stats.rate_stream_tx.avg, + "rx-packets-streams", interface->stats.stream_rx, + "rx-pps-streams", interface->stats.rate_stream_rx.avg, + "rx-loss-packets-streams", interface->stats.stream_loss + ); +} + +/* Control Socket Commands */ + +int +bbl_network_ctrl_interfaces(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root, *interfaces; + bbl_interface_s *interface; + bbl_network_interface_s *network_interface; + + interfaces = json_array(); + CIRCLEQ_FOREACH(interface, &g_ctx->interface_qhead, interface_qnode) { + network_interface = interface->network; + while(network_interface) { + json_array_append(interfaces, bbl_network_interface_json(network_interface)); + network_interface = network_interface->next; + } + } + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "network-interfaces", interfaces); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(interfaces); + } + return result; } \ No newline at end of file diff --git a/code/bngblaster/src/bbl_network.h b/code/bngblaster/src/bbl_network.h index c17c7c49..3b69503c 100644 --- a/code/bngblaster/src/bbl_network.h +++ b/code/bngblaster/src/bbl_network.h @@ -145,4 +145,7 @@ void bbl_network_rx_handler(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth); +int +bbl_network_ctrl_interfaces(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + #endif diff --git a/code/bngblaster/src/bbl_session.c b/code/bngblaster/src/bbl_session.c index 64735d80..3064a984 100644 --- a/code/bngblaster/src/bbl_session.c +++ b/code/bngblaster/src/bbl_session.c @@ -13,6 +13,7 @@ #include "bbl_dhcpv6.h" extern volatile bool g_teardown; +extern volatile bool g_teardown_request; extern volatile bool g_monkey; const char * @@ -1170,4 +1171,328 @@ bbl_session_json(bbl_session_s *session) if(session_traffic) json_decref(session_traffic); } return root; -} \ No newline at end of file +} + +/* Control Socket Commands */ + +int +bbl_session_ctrl_pending(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root, *json_session, *json_sessions; + + bbl_session_s *session; + uint32_t i; + + json_sessions = json_array(); + + /* Iterate over all sessions */ + for(i = 0; i < g_ctx->sessions; i++) { + session = &g_ctx->session_list[i]; + if(!session) continue; + + if(session->session_state != BBL_ESTABLISHED || + session->session_traffic.flows != session->session_traffic.flows_verified) { + json_session = json_pack("{si ss si si}", + "session-id", session->session_id, + "session-state", session_state_string(session->session_state), + "session-traffic-flows", session->session_traffic.flows, + "session-traffic-flows-verified", session->session_traffic.flows_verified); + json_array_append(json_sessions, json_session); + } + } + + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "sessions-pending", json_sessions); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(json_sessions); + } + return result; +} + +int +bbl_session_ctrl_counters(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root = json_pack("{ss si s{si si si si si si si si si si si si si si sf sf sf sf si si si si}}", + "status", "ok", + "code", 200, + "session-counters", + "sessions", g_ctx->config.sessions, + "sessions-pppoe", g_ctx->sessions_pppoe, + "sessions-ipoe", g_ctx->sessions_ipoe, + "sessions-established", g_ctx->sessions_established, + "sessions-established-max", g_ctx->sessions_established_max, + "sessions-terminated", g_ctx->sessions_terminated, + "sessions-flapped", g_ctx->sessions_flapped, + "dhcp-sessions", g_ctx->dhcp_requested, + "dhcp-sessions-established", g_ctx->dhcp_established, + "dhcp-sessions-established-max", g_ctx->dhcp_established_max, + "dhcpv6-sessions", g_ctx->dhcpv6_requested, + "dhcpv6-sessions-established", g_ctx->dhcpv6_established, + "dhcpv6-sessions-established-max", g_ctx->dhcpv6_established_max, + "setup-time", g_ctx->stats.setup_time, + "setup-rate", g_ctx->stats.cps, + "setup-rate-min", g_ctx->stats.cps_min, + "setup-rate-avg", g_ctx->stats.cps_avg, + "setup-rate-max", g_ctx->stats.cps_max, + "session-traffic-flows", g_ctx->stats.session_traffic_flows, + "session-traffic-flows-verified", g_ctx->stats.session_traffic_flows_verified, + "stream-traffic-flows", g_ctx->stats.stream_traffic_flows, + "stream-traffic-flows-verified", g_ctx->stats.stream_traffic_flows_verified + ); + + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } + return result; +} + +int +bbl_session_ctrl_info(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root; + json_t *session_json; + bbl_session_s *session; + + if(session_id == 0) { + /* session-id is mandatory */ + return bbl_ctrl_status(fd, "error", 400, "missing session-id"); + } + + session = bbl_session_get(session_id); + if(session) { + session_json = bbl_session_json(session); + if(!session_json) { + return bbl_ctrl_status(fd, "error", 500, "internal error"); + } + + root = json_pack("{ss si so*}", + "status", "ok", + "code", 200, + "session-info", session_json); + + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(session_json); + } + return result; + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } +} + +int +bbl_session_ctrl_start(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + bbl_session_s *session; + + if(g_teardown) { + return bbl_ctrl_status(fd, "error", 405, "teardown"); + } + + if(session_id == 0) { + /* session-id is mandatory */ + return bbl_ctrl_status(fd, "error", 400, "missing session-id"); + } + + session = bbl_session_get(session_id); + if(session) { + if(session->session_state == BBL_TERMINATED && + session->reconnect_delay == 0) { + g_ctx->sessions_flapped++; + session->stats.flapped++; + session->session_state = BBL_IDLE; + bbl_session_reset(session); + if(g_ctx->sessions_terminated) { + g_ctx->sessions_terminated--; + } + } else if(session->session_state != BBL_IDLE || + CIRCLEQ_NEXT(session, session_idle_qnode) || + CIRCLEQ_PREV(session, session_idle_qnode)) { + return bbl_ctrl_status(fd, "error", 405, "wrong session state"); + } + CIRCLEQ_INSERT_TAIL(&g_ctx->sessions_idle_qhead, session, session_idle_qnode); + return bbl_ctrl_status(fd, "ok", 200, NULL); + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } +} + +int +bbl_session_ctrl_terminate(int fd, uint32_t session_id, json_t *arguments) +{ + bbl_session_s *session; + int reconnect_delay = 0; + + if(session_id) { + /* Terminate single matching session ... */ + session = bbl_session_get(session_id); + if(session) { + json_unpack(arguments, "{s:i}", "reconnect-delay", &session->reconnect_delay); + if(reconnect_delay > 0) { + session->reconnect_delay = reconnect_delay; + } + bbl_session_clear(session); + return bbl_ctrl_status(fd, "ok", 200, "terminate session"); + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } + } else { + /* Terminate all sessions ... */ + g_teardown = true; + g_teardown_request = true; + LOG_NOARG(INFO, "Teardown request\n"); + return bbl_ctrl_status(fd, "ok", 200, "terminate all sessions"); + } +} + +static int +bbl_session_ctrl_ncp_open_close(int fd, uint32_t session_id, bool open, bool ipcp) +{ + bbl_session_s *session; + uint32_t i; + if(session_id) { + session = bbl_session_get(session_id); + if(session) { + if(session->access_type == ACCESS_TYPE_PPPOE) { + if(open) { + bbl_session_ncp_open(session, ipcp); + } else { + bbl_session_ncp_close(session, ipcp); + } + } else { + return bbl_ctrl_status(fd, "warning", 400, "matching session is not of type pppoe"); + } + return bbl_ctrl_status(fd, "ok", 200, NULL); + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } + } else { + /* Iterate over all sessions */ + for(i = 0; i < g_ctx->sessions; i++) { + session = &g_ctx->session_list[i]; + if(session) { + if(session->access_type == ACCESS_TYPE_PPPOE) { + if(open) { + bbl_session_ncp_open(session, ipcp); + } else { + bbl_session_ncp_close(session, ipcp); + } + } + } + } + return bbl_ctrl_status(fd, "ok", 200, NULL); + } +} + +int +bbl_session_ctrl_ipcp_open(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_session_ctrl_ncp_open_close(fd, session_id, true, true); +} + +int +bbl_session_ctrl_ipcp_close(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_session_ctrl_ncp_open_close(fd, session_id, false, true); +} + +int +bbl_session_ctrl_ip6cp_open(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_session_ctrl_ncp_open_close(fd, session_id, true, false); +} + +int +bbl_session_ctrl_ip6cp_close(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_session_ctrl_ncp_open_close(fd, session_id, false, false); +} + +static int +bbl_session_ctrl_traffic(int fd, uint32_t session_id, bool status) +{ + bbl_session_s *session; + uint32_t i; + if(session_id) { + session = bbl_session_get(session_id); + if(session) { + session->session_traffic.active = status; + return bbl_ctrl_status(fd, "ok", 200, NULL); + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } + } else { + /* Iterate over all sessions */ + for(i = 0; i < g_ctx->sessions; i++) { + session = &g_ctx->session_list[i]; + if(session) { + session->session_traffic.active = status; + } + } + return bbl_ctrl_status(fd, "ok", 200, NULL); + } +} + +int +bbl_session_ctrl_traffic_start(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_session_ctrl_traffic(fd, session_id, true); +} + +int +bbl_session_ctrl_traffic_stop(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_session_ctrl_traffic(fd, session_id, false); +} + + +int +bbl_session_ctrl_traffic_stats(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root = json_pack("{ss si s{si si}}", + "status", "ok", + "code", 200, + "session-traffic", + "total-flows", g_ctx->stats.session_traffic_flows, + "verified-flows", g_ctx->stats.session_traffic_flows_verified); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } + return result; +} + +int +bbl_session_ctrl_monkey_start(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + if(!g_monkey) { + LOG_NOARG(INFO, "Start monkey\n"); + } + g_monkey = true; + return bbl_ctrl_status(fd, "ok", 200, NULL); +} + +int +bbl_session_ctrl_monkey_stop(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + if(g_monkey) { + LOG_NOARG(INFO, "Stop monkey\n"); + } + g_monkey = false; + return bbl_ctrl_status(fd, "ok", 200, NULL); +} + diff --git a/code/bngblaster/src/bbl_session.h b/code/bngblaster/src/bbl_session.h index 0e47213a..efeba4d4 100644 --- a/code/bngblaster/src/bbl_session.h +++ b/code/bngblaster/src/bbl_session.h @@ -401,4 +401,46 @@ bbl_session_id_from_broadcast(bbl_interface_s *interface, bbl_ethernet_header_s json_t * bbl_session_json(bbl_session_s *session); +int +bbl_session_ctrl_pending(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_counters(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_info(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_start(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_terminate(int fd, uint32_t session_id, json_t *arguments); + +int +bbl_session_ctrl_ipcp_open(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_ipcp_close(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_ip6cp_open(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_ip6cp_close(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_traffic_start(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_traffic_stop(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_traffic_stats(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_monkey_start(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +bbl_session_ctrl_monkey_stop(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + #endif \ No newline at end of file diff --git a/code/bngblaster/src/bbl_stream.c b/code/bngblaster/src/bbl_stream.c index 505e5400..1a7419d6 100644 --- a/code/bngblaster/src/bbl_stream.c +++ b/code/bngblaster/src/bbl_stream.c @@ -697,7 +697,7 @@ bbl_stream_build_l2tp_packet(bbl_stream_s *stream) bbl_stream_config_s *config = stream->config; bbl_l2tp_session_s *l2tp_session = stream->session->l2tp_session; - bbl_l2tp_sunnel_s *l2tp_tunnel = l2tp_session->tunnel; + bbl_l2tp_tunnel_s *l2tp_tunnel = l2tp_session->tunnel; bbl_network_interface_s *network_interface = l2tp_tunnel->interface; @@ -1960,6 +1960,40 @@ bbl_stream_rx(bbl_ethernet_header_s *eth, bbl_session_s *session) } } +static json_t * +bbl_stream_summary_json() +{ + struct dict_itor *itor; + bbl_stream_s *stream; + + json_t *jobj, *jobj_array; + + jobj_array = json_array(); + + itor = dict_itor_new(g_ctx->stream_flow_dict); + dict_itor_first(itor); + for (; dict_itor_valid(itor); dict_itor_next(itor)) { + stream = (bbl_stream_s*)*dict_itor_datum(itor); + if(stream) { + jobj = json_pack("{si ss* ss ss ss}", + "flow-id", stream->flow_id, + "name", stream->config->name, + "type", stream_type_string(stream), + "sub-type", stream_sub_type_string(stream), + "direction", stream->direction == BBL_DIRECTION_UP ? "upstream" : "downstream"); + if(jobj) { + if(stream->session) { + json_object_set(jobj, "session-id", json_integer(stream->session->session_id)); + json_object_set(jobj, "session-traffic", json_boolean(stream->session_traffic)); + } + json_array_append(jobj_array, jobj); + } + } + } + dict_itor_free(itor); + return jobj_array; +} + json_t * bbl_stream_json(bbl_stream_s *stream) { @@ -2052,36 +2086,193 @@ bbl_stream_json(bbl_stream_s *stream) return root; } -json_t * -bbl_stream_summary_json() +/* Control Socket Commands */ + +int +bbl_stream_ctrl_stats(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) { - struct dict_itor *itor; + int result = 0; + json_t *root = json_pack("{ss si s{si si}}", + "status", "ok", + "code", 200, + "stream-stats", + "total-flows", g_ctx->stats.stream_traffic_flows, + "verified-flows", g_ctx->stats.stream_traffic_flows_verified); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } + return result; +} + +int +bbl_stream_ctrl_info(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) +{ + int result = 0; + + json_t *root; + json_t *json_stream = NULL; + + bbl_stream_s *stream; + void **search = NULL; + + int number = 0; + uint64_t flow_id; + + /* Unpack further arguments */ + if (json_unpack(arguments, "{s:i}", "flow-id", &number) != 0) { + return bbl_ctrl_status(fd, "error", 400, "missing flow-id"); + } + + flow_id = number; + search = dict_search(g_ctx->stream_flow_dict, &flow_id); + if(search) { + stream = *search; + json_stream = bbl_stream_json(stream); + root = json_pack("{ss si so*}", + "status", "ok", + "code", 200, + "stream-info", json_stream); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(json_stream); + } + return result; + } else { + return bbl_ctrl_status(fd, "warning", 404, "stream not found"); + } +} + +int +bbl_stream_ctrl_summary(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + + json_t *root = json_pack("{ss si so*}", + "status", "ok", + "code", 200, + "stream-summary", bbl_stream_summary_json()); + + result = json_dumpfd(root, fd, 0); + json_decref(root); + return result; +} + +int +bbl_stream_ctrl_session(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + int result = 0; + json_t *root; + json_t *json_streams = NULL; + json_t *json_stream = NULL; + + bbl_session_s *session; bbl_stream_s *stream; - json_t *jobj, *jobj_array; + if(session_id == 0) { + /* session-id is mandatory */ + return bbl_ctrl_status(fd, "error", 400, "missing session-id"); + } - jobj_array = json_array(); + session = bbl_session_get(session_id); + if(session) { + stream = session->streams.head; + json_streams = json_array(); + while(stream) { + json_stream = bbl_stream_json(stream); + json_array_append(json_streams, json_stream); + stream = stream->session_next; + } + root = json_pack("{ss si s{si si si si si si si si si sf sf so*}}", + "status", "ok", + "code", 200, + "session-streams", + "session-id", session->session_id, + "rx-packets", session->stats.packets_rx, + "tx-packets", session->stats.packets_tx, + "rx-accounting-packets", session->stats.accounting_packets_rx, + "tx-accounting-packets", session->stats.accounting_packets_tx, + "rx-pps", session->stats.rate_packets_rx.avg, + "tx-pps", session->stats.rate_packets_tx.avg, + "rx-bps-l2", session->stats.rate_bytes_rx.avg * 8, + "tx-bps-l2", session->stats.rate_bytes_tx.avg * 8, + "rx-mbps-l2", (double)(session->stats.rate_bytes_rx.avg * 8) / 1000000.0, + "tx-mbps-l2", (double)(session->stats.rate_bytes_tx.avg * 8) / 1000000.0, + "streams", json_streams); + + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(json_streams); + } + return result; + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } +} + +static int +bbl_stream_ctrl_traffic_start_stop(int fd, uint32_t session_id, bool status) +{ + bbl_session_s *session; + uint32_t i; + + if(session_id) { + session = bbl_session_get(session_id); + if(session) { + session->streams.active = status; + return bbl_ctrl_status(fd, "ok", 200, NULL); + } else { + return bbl_ctrl_status(fd, "warning", 404, "session not found"); + } + } else { + /* Iterate over all sessions */ + for(i = 0; i < g_ctx->sessions; i++) { + session = &g_ctx->session_list[i]; + if(session) { + session->streams.active = status; + } + } + return bbl_ctrl_status(fd, "ok", 200, NULL); + } +} + +int +bbl_stream_ctrl_traffic_start(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_stream_ctrl_traffic_start_stop(fd, session_id, true); +} + +int +bbl_stream_ctrl_traffic_stop(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))) +{ + return bbl_stream_ctrl_traffic_start_stop(fd, session_id, false); +} + +int +bbl_stream_ctrl_reset(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + bbl_stream_s *stream; + struct dict_itor *itor; + + g_ctx->stats.stream_traffic_flows_verified = 0; + + /* Iterate over all traffic streams */ itor = dict_itor_new(g_ctx->stream_flow_dict); dict_itor_first(itor); for (; dict_itor_valid(itor); dict_itor_next(itor)) { stream = (bbl_stream_s*)*dict_itor_datum(itor); - if(stream) { - jobj = json_pack("{si ss* ss ss ss}", - "flow-id", stream->flow_id, - "name", stream->config->name, - "type", stream_type_string(stream), - "sub-type", stream_sub_type_string(stream), - "direction", stream->direction == BBL_DIRECTION_UP ? "upstream" : "downstream"); - if(jobj) { - if(stream->session) { - json_object_set(jobj, "session-id", json_integer(stream->session->session_id)); - json_object_set(jobj, "session-traffic", json_boolean(stream->session_traffic)); - } - json_array_append(jobj_array, jobj); - } + if(!stream) { + continue; } + bbl_stream_reset(stream); } dict_itor_free(itor); - return jobj_array; + return bbl_ctrl_status(fd, "ok", 200, NULL); } \ No newline at end of file diff --git a/code/bngblaster/src/bbl_stream.h b/code/bngblaster/src/bbl_stream.h index 630b065a..2d2d3a0d 100644 --- a/code/bngblaster/src/bbl_stream.h +++ b/code/bngblaster/src/bbl_stream.h @@ -176,7 +176,25 @@ bbl_stream_reset(bbl_stream_s *stream); json_t * bbl_stream_json(bbl_stream_s *stream); -json_t * -bbl_stream_summary_json(); +int +bbl_stream_ctrl_stats(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +bbl_stream_ctrl_info(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); + +int +bbl_stream_ctrl_summary(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +bbl_stream_ctrl_session(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_stream_ctrl_traffic_start(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_stream_ctrl_traffic_stop(int fd, uint32_t session_id, json_t *arguments __attribute__((unused))); + +int +bbl_stream_ctrl_reset(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); #endif \ No newline at end of file diff --git a/code/bngblaster/src/bgp/bgp_ctrl.c b/code/bngblaster/src/bgp/bgp_ctrl.c index d472d3bf..000563f3 100644 --- a/code/bngblaster/src/bgp/bgp_ctrl.c +++ b/code/bngblaster/src/bgp/bgp_ctrl.c @@ -77,7 +77,7 @@ bgp_ctrl_session_json(bgp_session_s *session) } int -bgp_ctrl_sessions(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments) +bgp_ctrl_sessions(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) { int result = 0; json_t *root, *sessions, *session; @@ -133,14 +133,14 @@ bgp_ctrl_sessions(int fd, uint32_t session_id __attribute__((unused)), json_t* a } int -bgp_ctrl_teardown(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) +bgp_ctrl_teardown(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) { bgp_teardown(); return bbl_ctrl_status(fd, "ok", 200, NULL); } int -bgp_ctrl_raw_update(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments) +bgp_ctrl_raw_update(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) { int result = 0; json_t *root; @@ -223,7 +223,7 @@ bgp_ctrl_raw_update(int fd, uint32_t session_id __attribute__((unused)), json_t* } int -bgp_ctrl_raw_update_list(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) +bgp_ctrl_raw_update_list(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) { int result = 0; bgp_raw_update_s *raw_update = g_ctx->bgp_raw_updates; @@ -256,7 +256,7 @@ bgp_ctrl_raw_update_list(int fd, uint32_t session_id __attribute__((unused)), js } int -bgp_ctrl_disconnect(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments) +bgp_ctrl_disconnect(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) { int result = 0; json_t *root; diff --git a/code/bngblaster/src/bgp/bgp_ctrl.h b/code/bngblaster/src/bgp/bgp_ctrl.h index 971c15b9..55b71a6f 100644 --- a/code/bngblaster/src/bgp/bgp_ctrl.h +++ b/code/bngblaster/src/bgp/bgp_ctrl.h @@ -10,18 +10,18 @@ #define __BBL_BGP_CTRL_H__ int -bgp_ctrl_sessions(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))); +bgp_ctrl_sessions(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); int -bgp_ctrl_teardown(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))); +bgp_ctrl_teardown(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); int -bgp_ctrl_raw_update(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments); +bgp_ctrl_raw_update(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); int -bgp_ctrl_raw_update_list(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))); +bgp_ctrl_raw_update_list(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); int -bgp_ctrl_disconnect(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments); +bgp_ctrl_disconnect(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); #endif \ No newline at end of file diff --git a/code/bngblaster/src/isis/isis_ctrl.c b/code/bngblaster/src/isis/isis_ctrl.c index c062110d..ea4acb60 100644 --- a/code/bngblaster/src/isis/isis_ctrl.c +++ b/code/bngblaster/src/isis/isis_ctrl.c @@ -67,7 +67,7 @@ isis_ctrl_adjacency_p2p(isis_adjacency_p2p_s *adjacency) } int -isis_ctrl_adjacencies(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) +isis_ctrl_adjacencies(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) { int result = 0; int level; @@ -167,7 +167,7 @@ isis_ctrl_database_entries(hb_tree *lsdb) } int -isis_ctrl_database(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments) +isis_ctrl_database(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) { int result = 0; json_t *root = NULL; @@ -225,7 +225,7 @@ isis_ctrl_database(int fd, uint32_t session_id __attribute__((unused)), json_t* } int -isis_ctrl_load_mrt(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments) +isis_ctrl_load_mrt(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) { char *file_path; int instance_id = 0; @@ -260,7 +260,7 @@ isis_ctrl_load_mrt(int fd, uint32_t session_id __attribute__((unused)), json_t* } int -isis_ctrl_lsp_update(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments) +isis_ctrl_lsp_update(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) { protocol_error_t result; @@ -327,7 +327,7 @@ isis_ctrl_lsp_update(int fd, uint32_t session_id __attribute__((unused)), json_t } int -isis_ctrl_teardown(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))) +isis_ctrl_teardown(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) { isis_teardown(); return bbl_ctrl_status(fd, "ok", 200, NULL); diff --git a/code/bngblaster/src/isis/isis_ctrl.h b/code/bngblaster/src/isis/isis_ctrl.h index 1ca7625d..dd67d4e4 100644 --- a/code/bngblaster/src/isis/isis_ctrl.h +++ b/code/bngblaster/src/isis/isis_ctrl.h @@ -10,18 +10,18 @@ #define __BBL_ISIS_CTRL_H__ int -isis_ctrl_adjacencies(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))); +isis_ctrl_adjacencies(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); int -isis_ctrl_database(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments); +isis_ctrl_database(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); int -isis_ctrl_load_mrt(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments); +isis_ctrl_load_mrt(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); int -isis_ctrl_lsp_update(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments); +isis_ctrl_lsp_update(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); int -isis_ctrl_teardown(int fd, uint32_t session_id __attribute__((unused)), json_t* arguments __attribute__((unused))); +isis_ctrl_teardown(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); #endif \ No newline at end of file diff --git a/code/common/src/utils.c b/code/common/src/utils.c index f3d5157e..cc76d164 100644 --- a/code/common/src/utils.c +++ b/code/common/src/utils.c @@ -632,4 +632,14 @@ replace_substring(const char* source, } *result_pos = '\0'; return result; +} + +char * +string_or_na(char *string) +{ + if(string) { + return string; + } else { + return "N/A"; + } } \ No newline at end of file diff --git a/code/common/src/utils.h b/code/common/src/utils.h index f8882636..926cfa2e 100644 --- a/code/common/src/utils.h +++ b/code/common/src/utils.h @@ -45,5 +45,6 @@ bool ipv6_addr_not_zero(ipv6addr_t *addr); bool ipv6_prefix_not_zero(ipv6_prefix *prefix); char *replace_substring(const char* s, const char* old, const char* new); +char *string_or_na(char *string); #endif \ No newline at end of file