libosmocore/tests/stats/stats_test.c

504 lines
14 KiB
C
Raw Permalink Normal View History

/* tests for statistics */
/*
* (C) 2015 sysmocom - s.m.f.c. GmbH
*
* All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/stat_item.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <stdio.h>
#include <inttypes.h>
enum test_ctr {
TEST_A_CTR,
TEST_B_CTR,
};
static const struct rate_ctr_desc ctr_description[] = {
[TEST_A_CTR] = { "ctr:a", "The A counter value"},
[TEST_B_CTR] = { "ctr:b", "The B counter value"},
};
static const struct rate_ctr_group_desc ctrg_desc = {
.group_name_prefix = "ctr-test:one",
.group_description = "Counter test number 1",
.num_ctr = ARRAY_SIZE(ctr_description),
.ctr_desc = ctr_description,
.class_id = OSMO_STATS_CLASS_SUBSCRIBER,
};
static const struct rate_ctr_desc ctr_description_dot[] = {
[TEST_A_CTR] = { "ctr.a", "The A counter value with ."},
[TEST_B_CTR] = { "ctr.b", "The B counter value with ."},
};
static const struct rate_ctr_group_desc ctrg_desc_dot = {
.group_name_prefix = "ctr-test.one_dot",
.group_description = "Counter test number 1dot",
.num_ctr = ARRAY_SIZE(ctr_description_dot),
.ctr_desc = ctr_description_dot,
.class_id = OSMO_STATS_CLASS_SUBSCRIBER,
};
enum test_items {
TEST_A_ITEM,
TEST_B_ITEM,
};
static const struct osmo_stat_item_desc item_description[] = {
[TEST_A_ITEM] = { "item.a", "The A value", "ma", 4, -1 },
[TEST_B_ITEM] = { "item.b", "The B value", "kb", 7, -1 },
};
static const struct osmo_stat_item_group_desc statg_desc = {
.group_name_prefix = "test.one",
.group_description = "Test number 1",
.num_items = ARRAY_SIZE(item_description),
.item_desc = item_description,
.class_id = OSMO_STATS_CLASS_PEER,
};
static void stat_test(void)
{
struct osmo_stat_item_group *statg =
osmo_stat_item_group_alloc(NULL, &statg_desc, 0);
struct osmo_stat_item_group *sgrp2;
const struct osmo_stat_item *sitem1, *sitem2;
int rc;
int32_t value;
int32_t rd_a = 0;
int32_t rd_b = 0;
int i;
OSMO_ASSERT(statg != NULL);
sgrp2 = osmo_stat_item_get_group_by_name_idx("test.one", 0);
OSMO_ASSERT(sgrp2 == statg);
sgrp2 = osmo_stat_item_get_group_by_name_idx("test.one", 1);
OSMO_ASSERT(sgrp2 == NULL);
sgrp2 = osmo_stat_item_get_group_by_name_idx("test.two", 0);
OSMO_ASSERT(sgrp2 == NULL);
sitem1 = osmo_stat_item_get_by_name(statg, "item.c");
OSMO_ASSERT(sitem1 == NULL);
sitem1 = osmo_stat_item_get_by_name(statg, "item.a");
OSMO_ASSERT(sitem1 != NULL);
OSMO_ASSERT(sitem1 == statg->items[TEST_A_ITEM]);
sitem2 = osmo_stat_item_get_by_name(statg, "item.b");
OSMO_ASSERT(sitem2 != NULL);
OSMO_ASSERT(sitem2 != sitem1);
OSMO_ASSERT(sitem2 == statg->items[TEST_B_ITEM]);
value = osmo_stat_item_get_last(statg->items[TEST_A_ITEM]);
OSMO_ASSERT(value == -1);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc == 0);
osmo_stat_item_set(statg->items[TEST_A_ITEM], 1);
value = osmo_stat_item_get_last(statg->items[TEST_A_ITEM]);
OSMO_ASSERT(value == 1);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 1);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc == 0);
for (i = 2; i <= 32; i++) {
osmo_stat_item_set(statg->items[TEST_A_ITEM], i);
osmo_stat_item_set(statg->items[TEST_B_ITEM], 1000 + i);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == i);
rc = osmo_stat_item_get_next(statg->items[TEST_B_ITEM], &rd_b, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 1000 + i);
}
/* check if dec & inc is working */
osmo_stat_item_set(statg->items[TEST_A_ITEM], 42);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 42);
osmo_stat_item_dec(statg->items[TEST_A_ITEM], 21);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 21);
osmo_stat_item_inc(statg->items[TEST_A_ITEM], 21);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 42);
/* Keep 2 in FIFO */
osmo_stat_item_set(statg->items[TEST_A_ITEM], 33);
osmo_stat_item_set(statg->items[TEST_B_ITEM], 1000 + 33);
for (i = 34; i <= 64; i++) {
osmo_stat_item_set(statg->items[TEST_A_ITEM], i);
osmo_stat_item_set(statg->items[TEST_B_ITEM], 1000 + i);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == i-1);
rc = osmo_stat_item_get_next(statg->items[TEST_B_ITEM], &rd_b, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 1000 + i-1);
}
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 64);
rc = osmo_stat_item_get_next(statg->items[TEST_B_ITEM], &rd_b, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 1000 + 64);
/* Overrun FIFOs */
for (i = 65; i <= 96; i++) {
osmo_stat_item_set(statg->items[TEST_A_ITEM], i);
osmo_stat_item_set(statg->items[TEST_B_ITEM], 1000 + i);
}
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 93);
for (i = 94; i <= 96; i++) {
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == i);
}
rc = osmo_stat_item_get_next(statg->items[TEST_B_ITEM], &rd_b, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 1000 + 90);
for (i = 91; i <= 96; i++) {
rc = osmo_stat_item_get_next(statg->items[TEST_B_ITEM], &rd_b, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 1000 + i);
}
/* Test Discard (single item) */
osmo_stat_item_set(statg->items[TEST_A_ITEM], 97);
rc = osmo_stat_item_discard(statg->items[TEST_A_ITEM], &rd_a);
OSMO_ASSERT(rc > 0);
rc = osmo_stat_item_discard(statg->items[TEST_A_ITEM], &rd_a);
OSMO_ASSERT(rc == 0);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc == 0);
osmo_stat_item_set(statg->items[TEST_A_ITEM], 98);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc > 0);
OSMO_ASSERT(value == 98);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc == 0);
/* Test Discard (all items) */
osmo_stat_item_set(statg->items[TEST_A_ITEM], 99);
osmo_stat_item_set(statg->items[TEST_A_ITEM], 100);
osmo_stat_item_set(statg->items[TEST_A_ITEM], 101);
osmo_stat_item_set(statg->items[TEST_B_ITEM], 99);
osmo_stat_item_set(statg->items[TEST_B_ITEM], 100);
rc = osmo_stat_item_discard_all(&rd_a);
rc = osmo_stat_item_discard_all(&rd_b);
rc = osmo_stat_item_get_next(statg->items[TEST_A_ITEM], &rd_a, &value);
OSMO_ASSERT(rc == 0);
rc = osmo_stat_item_get_next(statg->items[TEST_B_ITEM], &rd_b, &value);
OSMO_ASSERT(rc == 0);
osmo_stat_item_group_free(statg);
sgrp2 = osmo_stat_item_get_group_by_name_idx("test.one", 0);
OSMO_ASSERT(sgrp2 == NULL);
}
/*** stats reporter tests ***/
/* define a special stats reporter for testing */
static int send_count;
enum {
OSMO_STATS_REPORTER_TEST = OSMO_STATS_REPORTER_LOG + 1,
};
static int stats_reporter_test_send_counter(struct osmo_stats_reporter *srep,
const struct rate_ctr_group *ctrg,
const struct rate_ctr_desc *desc,
int64_t value, int64_t delta)
{
const char *group_name = ctrg ? ctrg->desc->group_name_prefix : "";
printf(" %s: counter p=%s g=%s i=%u n=%s v=%lld d=%lld\n",
srep->name,
srep->name_prefix ? srep->name_prefix : "",
group_name, ctrg ? ctrg->idx : 0,
desc->name, (long long)value, (long long)delta);
send_count += 1;
return 0;
}
static int stats_reporter_test_send_item(struct osmo_stats_reporter *srep,
const struct osmo_stat_item_group *statg,
const struct osmo_stat_item_desc *desc, int64_t value)
{
printf(" %s: item p=%s g=%s i=%u n=%s v=%"PRId64" u=%s\n",
srep->name,
srep->name_prefix ? srep->name_prefix : "",
statg->desc->group_name_prefix, statg->idx,
desc->name, value, desc->unit ? desc->unit : "");
send_count += 1;
return 0;
}
static int stats_reporter_test_open(struct osmo_stats_reporter *srep)
{
printf(" %s: open\n", srep->name);
return 0;
}
static int stats_reporter_test_close(struct osmo_stats_reporter *srep)
{
printf(" %s: close\n", srep->name);
return 0;
}
static struct osmo_stats_reporter *stats_reporter_create_test(const char *name)
{
struct osmo_stats_reporter *srep;
srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_TEST, name);
srep->have_net_config = 0;
srep->open = stats_reporter_test_open;
srep->close = stats_reporter_test_close;
srep->send_counter = stats_reporter_test_send_counter;
srep->send_item = stats_reporter_test_send_item;
return srep;
}
static void test_reporting()
{
struct osmo_stats_reporter *srep1, *srep2, *srep;
struct osmo_stat_item_group *statg1, *statg2;
struct rate_ctr_group *ctrg1, *ctrg2, *ctrg3, *ctrg_dup;
void *stats_ctx = talloc_named_const(NULL, 1, "stats test context");
int rc;
printf("Start test: %s\n", __func__);
/* Allocate counters and items */
statg1 = osmo_stat_item_group_alloc(stats_ctx, &statg_desc, 1);
OSMO_ASSERT(statg1 != NULL);
statg2 = osmo_stat_item_group_alloc(stats_ctx, &statg_desc, 2);
OSMO_ASSERT(statg2 != NULL);
ctrg1 = rate_ctr_group_alloc(stats_ctx, &ctrg_desc, 1);
rate_ctr: fix osmo-sgsn DoS: don't return NULL on already used index Recent patch I563764af1d28043e909234ebb048239125ce6ecd introduced returning NULL from rate_ctr_group_alloc() when the index passed already exists. Instead of returning NULL, find an unused group index and use that, adjust the error message. In stats_test.c, adjust, and also assert allocated counter group indexes everywhere. Rationale: The original patch causes osmo-sgsn to crash as soon as the second subscriber attempts to establish an MM context. Of course osmo-sgsn is wrong to a) fail to check a NULL return value and crash and b) to fail to allocate an MM context just because the rate counter group could not be allocated (it still rejects the MM context completely if rate_ctr_group_alloc() fails). Nevertheless, the price we pay for rate counter correctness is, at least in this instance, way too high: osmo-sgsn becomes completely unusable for more than one subscriber. Numerous other places exist where rate_ctr_group_alloc() is called with a constant index number; from a quick grep magic I found these possible breaking points: osmo-sgsn/src/gprs/gb_proxy.c:1431: cfg->ctrg = rate_ctr_group_alloc(tall_bsc_ctx, &global_ctrg_desc, 0); osmo-sgsn/src/gprs/gprs_sgsn.c:139: sgsn->rate_ctrs = rate_ctr_group_alloc(tall_bsc_ctx, &sgsn_ctrg_desc, 0); osmo-sgsn/src/gprs/gprs_sgsn.c:270: ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0); osmo-sgsn/src/gprs/gtphub.c:888: b->counters_io = rate_ctr_group_alloc(osmo_gtphub_ctx, &gtphub_ctrg_io_desc, 0); osmo-bsc/src/libfilter/bsc_msg_acc.c:87: lst->stats = rate_ctr_group_alloc(lst, &bsc_cfg_acc_list_desc, 0); osmo-pcu/src/bts.cpp:228: m_ratectrs = rate_ctr_group_alloc(tall_pcu_ctx, &bts_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:793: tbf->m_ctrs = rate_ctr_group_alloc(tbf, &tbf_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:879: tbf->m_ul_egprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_ul_egprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:880: tbf->m_ul_gprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_ul_gprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:970: tbf->m_dl_egprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_dl_egprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:977: tbf->m_dl_gprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_dl_gprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:1475: ul_tbf->m_ctrs = rate_ctr_group_alloc(ul_tbf, &tbf_ctrg_desc, 0); osmo-pcu/src/bts.cpp:226: m_ratectrs = rate_ctr_group_alloc(tall_pcu_ctx, &bts_ctrg_desc, 1); We can fix all of these callers and then reconsider returning NULL, but IMO even into the future, rate counter group indexes are not something worth failing to provide service for. For future bugs we should keep the automatic index picking in case of index collisions. We will get an error message barfed and can fix the issue in our own time, while the application remains completely usable, and even the rate counters can still be queried (at wrong indexes, but life is tough). Related: I49aa95b610f2faec52dede2e4816da47ca1dfb14 (osmo-sgsn's segfault) Change-Id: Iba6e41b8eeaea5ff6ed862bab3f34a62ab976914
2017-12-20 00:14:31 +00:00
OSMO_ASSERT(ctrg1 && ctrg1->idx == 1);
ctrg2 = rate_ctr_group_alloc(stats_ctx, &ctrg_desc, 2);
rate_ctr: fix osmo-sgsn DoS: don't return NULL on already used index Recent patch I563764af1d28043e909234ebb048239125ce6ecd introduced returning NULL from rate_ctr_group_alloc() when the index passed already exists. Instead of returning NULL, find an unused group index and use that, adjust the error message. In stats_test.c, adjust, and also assert allocated counter group indexes everywhere. Rationale: The original patch causes osmo-sgsn to crash as soon as the second subscriber attempts to establish an MM context. Of course osmo-sgsn is wrong to a) fail to check a NULL return value and crash and b) to fail to allocate an MM context just because the rate counter group could not be allocated (it still rejects the MM context completely if rate_ctr_group_alloc() fails). Nevertheless, the price we pay for rate counter correctness is, at least in this instance, way too high: osmo-sgsn becomes completely unusable for more than one subscriber. Numerous other places exist where rate_ctr_group_alloc() is called with a constant index number; from a quick grep magic I found these possible breaking points: osmo-sgsn/src/gprs/gb_proxy.c:1431: cfg->ctrg = rate_ctr_group_alloc(tall_bsc_ctx, &global_ctrg_desc, 0); osmo-sgsn/src/gprs/gprs_sgsn.c:139: sgsn->rate_ctrs = rate_ctr_group_alloc(tall_bsc_ctx, &sgsn_ctrg_desc, 0); osmo-sgsn/src/gprs/gprs_sgsn.c:270: ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0); osmo-sgsn/src/gprs/gtphub.c:888: b->counters_io = rate_ctr_group_alloc(osmo_gtphub_ctx, &gtphub_ctrg_io_desc, 0); osmo-bsc/src/libfilter/bsc_msg_acc.c:87: lst->stats = rate_ctr_group_alloc(lst, &bsc_cfg_acc_list_desc, 0); osmo-pcu/src/bts.cpp:228: m_ratectrs = rate_ctr_group_alloc(tall_pcu_ctx, &bts_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:793: tbf->m_ctrs = rate_ctr_group_alloc(tbf, &tbf_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:879: tbf->m_ul_egprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_ul_egprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:880: tbf->m_ul_gprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_ul_gprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:970: tbf->m_dl_egprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_dl_egprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:977: tbf->m_dl_gprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_dl_gprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:1475: ul_tbf->m_ctrs = rate_ctr_group_alloc(ul_tbf, &tbf_ctrg_desc, 0); osmo-pcu/src/bts.cpp:226: m_ratectrs = rate_ctr_group_alloc(tall_pcu_ctx, &bts_ctrg_desc, 1); We can fix all of these callers and then reconsider returning NULL, but IMO even into the future, rate counter group indexes are not something worth failing to provide service for. For future bugs we should keep the automatic index picking in case of index collisions. We will get an error message barfed and can fix the issue in our own time, while the application remains completely usable, and even the rate counters can still be queried (at wrong indexes, but life is tough). Related: I49aa95b610f2faec52dede2e4816da47ca1dfb14 (osmo-sgsn's segfault) Change-Id: Iba6e41b8eeaea5ff6ed862bab3f34a62ab976914
2017-12-20 00:14:31 +00:00
OSMO_ASSERT(ctrg2 && ctrg2->idx == 2);
ctrg_dup = rate_ctr_group_alloc(stats_ctx, &ctrg_desc, 2);
rate_ctr: fix osmo-sgsn DoS: don't return NULL on already used index Recent patch I563764af1d28043e909234ebb048239125ce6ecd introduced returning NULL from rate_ctr_group_alloc() when the index passed already exists. Instead of returning NULL, find an unused group index and use that, adjust the error message. In stats_test.c, adjust, and also assert allocated counter group indexes everywhere. Rationale: The original patch causes osmo-sgsn to crash as soon as the second subscriber attempts to establish an MM context. Of course osmo-sgsn is wrong to a) fail to check a NULL return value and crash and b) to fail to allocate an MM context just because the rate counter group could not be allocated (it still rejects the MM context completely if rate_ctr_group_alloc() fails). Nevertheless, the price we pay for rate counter correctness is, at least in this instance, way too high: osmo-sgsn becomes completely unusable for more than one subscriber. Numerous other places exist where rate_ctr_group_alloc() is called with a constant index number; from a quick grep magic I found these possible breaking points: osmo-sgsn/src/gprs/gb_proxy.c:1431: cfg->ctrg = rate_ctr_group_alloc(tall_bsc_ctx, &global_ctrg_desc, 0); osmo-sgsn/src/gprs/gprs_sgsn.c:139: sgsn->rate_ctrs = rate_ctr_group_alloc(tall_bsc_ctx, &sgsn_ctrg_desc, 0); osmo-sgsn/src/gprs/gprs_sgsn.c:270: ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0); osmo-sgsn/src/gprs/gtphub.c:888: b->counters_io = rate_ctr_group_alloc(osmo_gtphub_ctx, &gtphub_ctrg_io_desc, 0); osmo-bsc/src/libfilter/bsc_msg_acc.c:87: lst->stats = rate_ctr_group_alloc(lst, &bsc_cfg_acc_list_desc, 0); osmo-pcu/src/bts.cpp:228: m_ratectrs = rate_ctr_group_alloc(tall_pcu_ctx, &bts_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:793: tbf->m_ctrs = rate_ctr_group_alloc(tbf, &tbf_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:879: tbf->m_ul_egprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_ul_egprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:880: tbf->m_ul_gprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_ul_gprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:970: tbf->m_dl_egprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_dl_egprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:977: tbf->m_dl_gprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_dl_gprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:1475: ul_tbf->m_ctrs = rate_ctr_group_alloc(ul_tbf, &tbf_ctrg_desc, 0); osmo-pcu/src/bts.cpp:226: m_ratectrs = rate_ctr_group_alloc(tall_pcu_ctx, &bts_ctrg_desc, 1); We can fix all of these callers and then reconsider returning NULL, but IMO even into the future, rate counter group indexes are not something worth failing to provide service for. For future bugs we should keep the automatic index picking in case of index collisions. We will get an error message barfed and can fix the issue in our own time, while the application remains completely usable, and even the rate counters can still be queried (at wrong indexes, but life is tough). Related: I49aa95b610f2faec52dede2e4816da47ca1dfb14 (osmo-sgsn's segfault) Change-Id: Iba6e41b8eeaea5ff6ed862bab3f34a62ab976914
2017-12-20 00:14:31 +00:00
OSMO_ASSERT(ctrg_dup && ctrg_dup->idx == 3);
rate_ctr_group_free(ctrg_dup);
ctrg3 = rate_ctr_group_alloc(stats_ctx, &ctrg_desc_dot, 3);
rate_ctr: fix osmo-sgsn DoS: don't return NULL on already used index Recent patch I563764af1d28043e909234ebb048239125ce6ecd introduced returning NULL from rate_ctr_group_alloc() when the index passed already exists. Instead of returning NULL, find an unused group index and use that, adjust the error message. In stats_test.c, adjust, and also assert allocated counter group indexes everywhere. Rationale: The original patch causes osmo-sgsn to crash as soon as the second subscriber attempts to establish an MM context. Of course osmo-sgsn is wrong to a) fail to check a NULL return value and crash and b) to fail to allocate an MM context just because the rate counter group could not be allocated (it still rejects the MM context completely if rate_ctr_group_alloc() fails). Nevertheless, the price we pay for rate counter correctness is, at least in this instance, way too high: osmo-sgsn becomes completely unusable for more than one subscriber. Numerous other places exist where rate_ctr_group_alloc() is called with a constant index number; from a quick grep magic I found these possible breaking points: osmo-sgsn/src/gprs/gb_proxy.c:1431: cfg->ctrg = rate_ctr_group_alloc(tall_bsc_ctx, &global_ctrg_desc, 0); osmo-sgsn/src/gprs/gprs_sgsn.c:139: sgsn->rate_ctrs = rate_ctr_group_alloc(tall_bsc_ctx, &sgsn_ctrg_desc, 0); osmo-sgsn/src/gprs/gprs_sgsn.c:270: ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0); osmo-sgsn/src/gprs/gtphub.c:888: b->counters_io = rate_ctr_group_alloc(osmo_gtphub_ctx, &gtphub_ctrg_io_desc, 0); osmo-bsc/src/libfilter/bsc_msg_acc.c:87: lst->stats = rate_ctr_group_alloc(lst, &bsc_cfg_acc_list_desc, 0); osmo-pcu/src/bts.cpp:228: m_ratectrs = rate_ctr_group_alloc(tall_pcu_ctx, &bts_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:793: tbf->m_ctrs = rate_ctr_group_alloc(tbf, &tbf_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:879: tbf->m_ul_egprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_ul_egprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:880: tbf->m_ul_gprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_ul_gprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:970: tbf->m_dl_egprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_dl_egprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:977: tbf->m_dl_gprs_ctrs = rate_ctr_group_alloc(tbf, &tbf_dl_gprs_ctrg_desc, 0); osmo-pcu/src/tbf.cpp:1475: ul_tbf->m_ctrs = rate_ctr_group_alloc(ul_tbf, &tbf_ctrg_desc, 0); osmo-pcu/src/bts.cpp:226: m_ratectrs = rate_ctr_group_alloc(tall_pcu_ctx, &bts_ctrg_desc, 1); We can fix all of these callers and then reconsider returning NULL, but IMO even into the future, rate counter group indexes are not something worth failing to provide service for. For future bugs we should keep the automatic index picking in case of index collisions. We will get an error message barfed and can fix the issue in our own time, while the application remains completely usable, and even the rate counters can still be queried (at wrong indexes, but life is tough). Related: I49aa95b610f2faec52dede2e4816da47ca1dfb14 (osmo-sgsn's segfault) Change-Id: Iba6e41b8eeaea5ff6ed862bab3f34a62ab976914
2017-12-20 00:14:31 +00:00
OSMO_ASSERT(ctrg3 && ctrg3->idx == 3);
srep1 = stats_reporter_create_test("test1");
OSMO_ASSERT(srep1 != NULL);
srep2 = stats_reporter_create_test("test2");
OSMO_ASSERT(srep2 != NULL);
srep = osmo_stats_reporter_find(OSMO_STATS_REPORTER_TEST, "test1");
OSMO_ASSERT(srep == srep1);
srep = osmo_stats_reporter_find(OSMO_STATS_REPORTER_TEST, "test2");
OSMO_ASSERT(srep == srep2);
rc = osmo_stats_reporter_enable(srep1);
OSMO_ASSERT(rc >= 0);
OSMO_ASSERT(srep1->force_single_flush);
rc = osmo_stats_reporter_set_max_class(srep1, OSMO_STATS_CLASS_SUBSCRIBER);
OSMO_ASSERT(rc >= 0);
rc = osmo_stats_reporter_enable(srep2);
OSMO_ASSERT(rc >= 0);
OSMO_ASSERT(srep2->force_single_flush);
rc = osmo_stats_reporter_set_max_class(srep2, OSMO_STATS_CLASS_SUBSCRIBER);
OSMO_ASSERT(rc >= 0);
printf("report (initial):\n");
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 20);
printf("report (srep1 global):\n");
/* force single flush */
osmo_stats_reporter_set_max_class(srep1, OSMO_STATS_CLASS_GLOBAL);
srep1->force_single_flush = 1;
srep2->force_single_flush = 1;
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 10);
printf("report (srep1 peer):\n");
/* force single flush */
osmo_stats_reporter_set_max_class(srep1, OSMO_STATS_CLASS_PEER);
srep1->force_single_flush = 1;
srep2->force_single_flush = 1;
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 14);
printf("report (srep1 subscriber):\n");
/* force single flush */
osmo_stats_reporter_set_max_class(srep1, OSMO_STATS_CLASS_SUBSCRIBER);
srep1->force_single_flush = 1;
srep2->force_single_flush = 1;
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 20);
printf("report (srep2 disabled):\n");
/* force single flush */
srep1->force_single_flush = 1;
srep2->force_single_flush = 1;
rc = osmo_stats_reporter_disable(srep2);
OSMO_ASSERT(rc >= 0);
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 10);
printf("report (srep2 enabled, no flush forced):\n");
rc = osmo_stats_reporter_enable(srep2);
OSMO_ASSERT(rc >= 0);
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 10);
printf("report (should be empty):\n");
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 0);
printf("report (group 1, counter 1 update):\n");
rate_ctr_inc(&ctrg1->ctr[TEST_A_CTR]);
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 2);
printf("report (group 1, item 1 update):\n");
osmo_stat_item_set(statg1->items[TEST_A_ITEM], 10);
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 2);
printf("report (remove statg1, ctrg1):\n");
/* force single flush */
srep1->force_single_flush = 1;
srep2->force_single_flush = 1;
osmo_stat_item_group_free(statg1);
rate_ctr_group_free(ctrg1);
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 12);
printf("report (remove srep1):\n");
/* force single flush */
srep1->force_single_flush = 1;
srep2->force_single_flush = 1;
osmo_stats_reporter_free(srep1);
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 6);
printf("report (remove statg2):\n");
/* force single flush */
srep2->force_single_flush = 1;
osmo_stat_item_group_free(statg2);
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 4);
printf("report (remove srep2):\n");
/* force single flush */
srep2->force_single_flush = 1;
osmo_stats_reporter_free(srep2);
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 0);
printf("report (remove ctrg2, should be empty):\n");
rate_ctr_group_free(ctrg2);
send_count = 0;
osmo_stats_report();
OSMO_ASSERT(send_count == 0);
rate_ctr_group_free(ctrg3);
/* Leak check */
OSMO_ASSERT(talloc_total_blocks(stats_ctx) == 1);
talloc_free(stats_ctx);
printf("End test: %s\n", __func__);
}
int main(int argc, char **argv)
{
static const struct log_info log_info = {};
log_init(&log_info, NULL);
osmo_stat_item_init(NULL);
stat_test();
test_reporting();
return 0;
}