gtphub: first vty show commands.
Start adding VTY commands to show rate counters / statistics / cache dumps. Sponsored-by: On-Waves ehi
This commit is contained in:
parent
1ba50c6598
commit
4b2cbdab3e
|
@ -373,6 +373,7 @@ struct gtphub_peer_port {
|
|||
|
||||
struct gtphub_bind {
|
||||
struct gsn_addr local_addr;
|
||||
uint16_t local_port;
|
||||
struct osmo_fd ofd;
|
||||
|
||||
/* list of struct gtphub_peer */
|
||||
|
@ -428,7 +429,7 @@ struct gtp_packet_desc;
|
|||
|
||||
/* api */
|
||||
|
||||
int gtphub_vty_init(void);
|
||||
int gtphub_vty_init(struct gtphub *global_hub, struct gtphub_cfg *global_cfg);
|
||||
int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file);
|
||||
|
||||
/* Initialize and start gtphub: bind to ports, run expiry timers. */
|
||||
|
|
|
@ -101,13 +101,13 @@ enum gtphub_counters_io {
|
|||
static const struct rate_ctr_desc gtphub_counters_io_desc[] = {
|
||||
{ "packets.in", "Packets ( In)" },
|
||||
{ "packets.out", "Packets (Out)" },
|
||||
{ "bytes.in", "Packets ( In)" },
|
||||
{ "bytes.out", "Packets (Out)" },
|
||||
{ "bytes.in", "Bytes ( In)" },
|
||||
{ "bytes.out", "Bytes (Out)" },
|
||||
};
|
||||
|
||||
static const struct rate_ctr_group_desc gtphub_ctrg_io_desc = {
|
||||
.group_name_prefix = "gtphub.bind",
|
||||
.group_description = "Local address I/O statistics",
|
||||
.group_description = "I/O Statistics",
|
||||
.num_ctr = ARRAY_SIZE(gtphub_counters_io_desc),
|
||||
.ctr_desc = gtphub_counters_io_desc,
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
|
@ -833,6 +833,7 @@ static int gtphub_bind_start(struct gtphub_bind *b,
|
|||
return -1;
|
||||
if (gtphub_sock_init(&b->ofd, &cfg->bind, cb, cb_data, ofd_id) != 0)
|
||||
return -1;
|
||||
b->local_port = cfg->bind.port;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1419,6 +1420,12 @@ int gtphub_from_ggsns_handle_buf(struct gtphub *hub,
|
|||
/* It was an echo. Nothing left to do. */
|
||||
osmo_sockaddr_copy(to_addr, from_addr);
|
||||
*to_ofd = &from_bind->ofd;
|
||||
|
||||
rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
|
||||
rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT],
|
||||
reply_len);
|
||||
LOG(LOGL_DEBUG, "--> Echo response to GGSN: %d bytes to %s\n",
|
||||
(int)reply_len, osmo_sockaddr_to_str(to_addr));
|
||||
return reply_len;
|
||||
}
|
||||
if (reply_len < 0)
|
||||
|
@ -1578,6 +1585,12 @@ int gtphub_from_sgsns_handle_buf(struct gtphub *hub,
|
|||
/* It was an echo. Nothing left to do. */
|
||||
osmo_sockaddr_copy(to_addr, from_addr);
|
||||
*to_ofd = &from_bind->ofd;
|
||||
|
||||
rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
|
||||
rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT],
|
||||
reply_len);
|
||||
LOG(LOGL_DEBUG, "<-- Echo response to SGSN: %d bytes to %s\n",
|
||||
(int)reply_len, osmo_sockaddr_to_str(to_addr));
|
||||
return reply_len;
|
||||
}
|
||||
if (reply_len < 0)
|
||||
|
|
|
@ -217,6 +217,18 @@ int main(int argc, char **argv)
|
|||
{
|
||||
int rc;
|
||||
|
||||
struct cmdline_cfg _ccfg;
|
||||
struct cmdline_cfg *ccfg = &_ccfg;
|
||||
memset(ccfg, '\0', sizeof(*ccfg));
|
||||
ccfg->config_file = "./gtphub.conf";
|
||||
|
||||
struct gtphub_cfg _cfg;
|
||||
struct gtphub_cfg *cfg = &_cfg;
|
||||
memset(cfg, '\0', sizeof(*cfg));
|
||||
|
||||
struct gtphub _hub;
|
||||
struct gtphub *hub = &_hub;
|
||||
|
||||
osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub");
|
||||
|
||||
signal(SIGINT, &signal_handler);
|
||||
|
@ -230,25 +242,13 @@ int main(int argc, char **argv)
|
|||
vty_info.copyright = gtphub_copyright;
|
||||
vty_init(&vty_info);
|
||||
logging_vty_add_cmds(>phub_log_info);
|
||||
gtphub_vty_init();
|
||||
gtphub_vty_init(hub, cfg);
|
||||
|
||||
rate_ctr_init(osmo_gtphub_ctx);
|
||||
rc = telnet_init(osmo_gtphub_ctx, 0, OSMO_VTY_PORT_GTPHUB);
|
||||
if (rc < 0)
|
||||
exit(1);
|
||||
|
||||
struct cmdline_cfg _ccfg;
|
||||
struct cmdline_cfg *ccfg = &_ccfg;
|
||||
memset(ccfg, '\0', sizeof(*ccfg));
|
||||
ccfg->config_file = "./gtphub.conf";
|
||||
|
||||
struct gtphub_cfg _cfg;
|
||||
struct gtphub_cfg *cfg = &_cfg;
|
||||
memset(cfg, '\0', sizeof(*cfg));
|
||||
|
||||
struct gtphub _hub;
|
||||
struct gtphub *hub = &_hub;
|
||||
|
||||
handle_options(ccfg, argc, argv);
|
||||
|
||||
rc = gtphub_cfg_read(cfg, ccfg->config_file);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/vty/misc.h>
|
||||
|
||||
#include <openbsc/vty.h>
|
||||
#include <openbsc/gtphub.h>
|
||||
|
@ -36,6 +37,7 @@
|
|||
#include <openbsc/sgsn.h>
|
||||
extern struct sgsn_instance *sgsn;
|
||||
|
||||
static struct gtphub *g_hub = 0;
|
||||
static struct gtphub_cfg *g_cfg = 0;
|
||||
|
||||
static struct cmd_node gtphub_node = {
|
||||
|
@ -244,17 +246,186 @@ DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
|
|||
}
|
||||
|
||||
|
||||
DEFUN(show_gtphub, show_gtphub_cmd, "show gtphub",
|
||||
/*
|
||||
(show gtphub all, show gtphub stats, show gtphub teidmap,
|
||||
show gtphub peers, ...)
|
||||
*/
|
||||
|
||||
static void show_bind_stats_all(struct vty *vty)
|
||||
{
|
||||
int plane_idx;
|
||||
for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) {
|
||||
vty_out(vty, "- %s Plane:%s",
|
||||
gtphub_plane_idx_names[plane_idx], VTY_NEWLINE);
|
||||
|
||||
struct gtphub_bind *b = &g_hub->to_ggsns[plane_idx];
|
||||
vty_out(vty, " - to/from GGSNs: %s port %d%s",
|
||||
gsn_addr_to_str(&b->local_addr), (int)b->local_port,
|
||||
VTY_NEWLINE);
|
||||
vty_out_rate_ctr_group(vty, " ", b->counters_io);
|
||||
|
||||
b = &g_hub->to_sgsns[plane_idx];
|
||||
vty_out(vty, " - to/from SGSNs: %s port %d%s",
|
||||
gsn_addr_to_str(&b->local_addr), (int)b->local_port,
|
||||
VTY_NEWLINE);
|
||||
vty_out_rate_ctr_group(vty, " ", b->counters_io);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static void show_peers_summary(struct vty *vty)
|
||||
{
|
||||
int c
|
||||
int plane_idx;
|
||||
}
|
||||
*/
|
||||
|
||||
static void show_tei_maps_summary(struct vty *vty)
|
||||
{
|
||||
time_t now = gtphub_now();
|
||||
|
||||
unsigned long long int count_all = 0; /* ...just joking. */
|
||||
|
||||
const int w = 36;
|
||||
int max_expiry = g_hub->expire_tei_maps.expiry_in_seconds;
|
||||
float seconds_per_step = ((float)max_expiry) / w;
|
||||
|
||||
/* Print TEI mapping expiry in an ASCII histogram, like:
|
||||
TEI map summary
|
||||
Legend: '_'=0 '.'<=1% ':'<=2% '|'<=10% '#'>10% (10.0 m/step)
|
||||
CTRL: 30 mappings, valid for 360m[#__:.____|___.____:__.______________]1m
|
||||
USER: 30 mappings, valid for 360m[#__:.____|___.____:__.______________]1m
|
||||
4 TEI mappings in total, last expiry in 359.4 min
|
||||
*/
|
||||
vty_out(vty,
|
||||
"TEI map summary%s"
|
||||
" Legend: '_'=0 '.'<=1%% ':'<=2%% '|'<=10%% '#'>10%% (%.1f m/step)%s",
|
||||
VTY_NEWLINE,
|
||||
seconds_per_step / 60.,
|
||||
VTY_NEWLINE);
|
||||
|
||||
int last_expiry = 0;
|
||||
int plane_idx;
|
||||
for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) {
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
int histogram[w];
|
||||
memset(histogram, 0, sizeof(histogram));
|
||||
|
||||
struct nr_mapping *m;
|
||||
llist_for_each_entry(m, &g_hub->tei_map[plane_idx].mappings, entry) {
|
||||
count ++;
|
||||
int expiry = m->expiry_entry.expiry - now;
|
||||
last_expiry = (last_expiry > expiry) ? last_expiry : expiry;
|
||||
|
||||
int hi = ((float)expiry) / seconds_per_step;
|
||||
if (hi < 0)
|
||||
hi = 0;
|
||||
if (hi > (w - 1))
|
||||
hi = w - 1;
|
||||
histogram[hi] ++;
|
||||
}
|
||||
|
||||
vty_out(vty,
|
||||
" %4s: %u mappings, valid for %dm[",
|
||||
gtphub_plane_idx_names[plane_idx],
|
||||
count, max_expiry / 60);
|
||||
|
||||
int i;
|
||||
for (i = w - 1; i >= 0; i--) {
|
||||
char c;
|
||||
int val = histogram[i];
|
||||
int percent = 100. * val / count;
|
||||
if (!val)
|
||||
c = '_';
|
||||
else if (percent <= 1)
|
||||
c = '.';
|
||||
else if (percent <= 2)
|
||||
c = ':';
|
||||
else if (percent <= 10)
|
||||
c = '|';
|
||||
else c = '#';
|
||||
vty_out(vty, "%c", c);
|
||||
}
|
||||
vty_out(vty, "]1m%s", VTY_NEWLINE);
|
||||
|
||||
count_all += count;
|
||||
}
|
||||
vty_out(vty, " %llu TEI mappings in total, last expiry in %.1f min%s",
|
||||
count_all,
|
||||
((float)last_expiry) / 60.,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static void show_tei_maps_all(struct vty *vty)
|
||||
{
|
||||
time_t now = gtphub_now();
|
||||
|
||||
unsigned long long int count_all = 0; /* ...just joking. */
|
||||
|
||||
vty_out(vty, "All TEI mappings:%s", VTY_NEWLINE);
|
||||
int plane_idx;
|
||||
for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) {
|
||||
vty_out(vty,
|
||||
"- %s Plane:%s"
|
||||
" (timeout) replaced-TEI <--> original-TEI from-peer%s",
|
||||
gtphub_plane_idx_names[plane_idx],
|
||||
VTY_NEWLINE, VTY_NEWLINE);
|
||||
|
||||
unsigned int count = 0;
|
||||
struct nr_mapping *m;
|
||||
llist_for_each_entry(m, &g_hub->tei_map[plane_idx].mappings, entry) {
|
||||
struct gtphub_peer_port *pp = m->origin;
|
||||
vty_out(vty,
|
||||
" (%4dm) %8x <--> %8x %s",
|
||||
-(int)((m->expiry_entry.expiry - now) / 60),
|
||||
(uint32_t)m->repl,
|
||||
(uint32_t)m->orig,
|
||||
gsn_addr_to_str(&pp->peer_addr->addr));
|
||||
if (pp->port != gtphub_plane_idx_default_port[plane_idx])
|
||||
vty_out(vty, " port %d", (int)pp->port);
|
||||
vty_out(vty, VTY_NEWLINE);
|
||||
count ++;
|
||||
}
|
||||
vty_out(vty, " (%u %s TEI mappings)%s", count,
|
||||
gtphub_plane_idx_names[plane_idx], VTY_NEWLINE);
|
||||
count_all += count;
|
||||
}
|
||||
vty_out(vty, "- %llu TEI mappings in total%s", count_all, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(show_gtphub_tei_summary, show_gtphub_tei_summary_cmd, "show gtphub tei summary",
|
||||
SHOW_STR "TEI mappings summary")
|
||||
{
|
||||
show_tei_maps_summary(vty);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(show_gtphub_tei_dump, show_gtphub_tei_dump_cmd, "show gtphub tei dump",
|
||||
SHOW_STR "Dump all current TEI mappings")
|
||||
{
|
||||
show_tei_maps_all(vty);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(show_gtphub, show_gtphub_cmd, "show gtphub all",
|
||||
SHOW_STR "Display information about the GTP hub")
|
||||
{
|
||||
vty_out(vty, "gtphub has nothing to say yet%s", VTY_NEWLINE);
|
||||
show_bind_stats_all(vty);
|
||||
show_tei_maps_summary(vty);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int gtphub_vty_init(void)
|
||||
int gtphub_vty_init(struct gtphub *global_hub, struct gtphub_cfg *global_cfg)
|
||||
{
|
||||
g_hub = global_hub;
|
||||
g_cfg = global_cfg;
|
||||
|
||||
install_element_ve(&show_gtphub_cmd);
|
||||
install_element_ve(&show_gtphub_tei_summary_cmd);
|
||||
install_element_ve(&show_gtphub_tei_dump_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &cfg_gtphub_cmd);
|
||||
install_node(>phub_node, config_write_gtphub);
|
||||
|
@ -277,8 +448,6 @@ int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file)
|
|||
{
|
||||
int rc;
|
||||
|
||||
g_cfg = cfg;
|
||||
|
||||
rc = vty_read_config_file(config_file, NULL);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
|
||||
|
|
Loading…
Reference in New Issue