mirror of
https://github.com/rtbrick/bngblaster.git
synced 2024-05-06 15:54:57 +00:00
restructure control commands
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
+52
-1591
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
+367
-46
@@ -14,7 +14,7 @@
|
||||
#include <openssl/rand.h>
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user