gbproxy: convert bss_nses from llist_head to hashtable

For the common lookup-by-nsei, this should reduce the computational
complexity significantly.

Depends: libosmocore.git I8ef73a62fe9846ce45058eb21cf999dd3eed5741
Change-Id: Idbb6a362332bb6e3ce22102e7409ae80d0980f44
This commit is contained in:
Harald Welte 2020-12-05 00:31:07 +01:00
parent 2b7b1bbbdc
commit d2fef95945
7 changed files with 56 additions and 35 deletions

View File

@ -1,2 +1,3 @@
#component what description / commit summary line
manual needs common chapter cs7-config.adoc, vty_cpu_sched.adoc from osmo-gsm-manuals > 0.3.0
configure.ac libosmocore depend on next released libosmocore after 1.4.x with hashtable support

View File

@ -4,6 +4,7 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/hashtable.h>
#include <osmocom/gsm/gsm23003.h>
#include <osmocom/gprs/gprs_ns2.h>
@ -102,7 +103,7 @@ struct gbproxy_config {
struct gprs_ns2_inst *nsi;
/* Linked list of all BSS side Gb peers */
struct llist_head bss_nses;
DECLARE_HASHTABLE(bss_nses, 8);
/* Counter */
struct rate_ctr_group *ctrg;
@ -176,7 +177,7 @@ struct gbproxy_bvc {
/* one NS Entity that we interact with (BSS/PCU) */
struct gbproxy_nse {
/* linked to gbproxy_config.bss_nses */
struct llist_head list;
struct hlist_node list;
/* point back to the config */
struct gbproxy_config *cfg;

View File

@ -31,6 +31,7 @@
#include <arpa/inet.h>
#include <time.h>
#include <osmocom/core/hashtable.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
@ -1183,6 +1184,7 @@ static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct
struct gbproxy_bvc *bvc;
unsigned int n_nses = 0;
int errctr = GBPROX_GLOB_CTR_PROTO_ERR_SGSN;
int i;
/* FIXME: Handle paging logic to only page each matching NSE */
@ -1203,7 +1205,7 @@ static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct
} else if (TLVP_PRES_LEN(tp, BSSGP_IE_ROUTEING_AREA, 6)) {
errctr = GBPROX_GLOB_CTR_INV_RAI;
/* iterate over all bvcs and dispatch the paging to each matching one */
llist_for_each_entry(nse, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, i, nse, list) {
llist_for_each_entry(bvc, &nse->bvcs, list) {
if (!memcmp(bvc->ra, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA), 6)) {
LOGPNSE(nse, LOGL_INFO, "routing to NSE (RAI match)\n");
@ -1217,7 +1219,7 @@ static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct
} else if (TLVP_PRES_LEN(tp, BSSGP_IE_LOCATION_AREA, 5)) {
errctr = GBPROX_GLOB_CTR_INV_LAI;
/* iterate over all bvcs and dispatch the paging to each matching one */
llist_for_each_entry(nse, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, i, nse, list) {
llist_for_each_entry(bvc, &nse->bvcs, list) {
if (!memcmp(bvc->ra, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {
LOGPNSE(nse, LOGL_INFO, "routing to NSE (LAI match)\n");
@ -1230,7 +1232,7 @@ static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct
}
} else if (TLVP_PRES_LEN(tp, BSSGP_IE_BSS_AREA_ID, 1)) {
/* iterate over all bvcs and dispatch the paging to each matching one */
llist_for_each_entry(nse, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, i, nse, list) {
llist_for_each_entry(bvc, &nse->bvcs, list) {
LOGPNSE(nse, LOGL_INFO, "routing to NSE (broadcast)\n");
gbprox_relay2nse(msg, nse, ns_bvci);
@ -1263,6 +1265,7 @@ static int rx_reset_from_sgsn(struct gbproxy_config *cfg,
struct gbproxy_nse *nse;
struct gbproxy_bvc *bvc;
uint16_t ptp_bvci;
int i;
if (!TLVP_PRES_LEN(tp, BSSGP_IE_BVCI, 2)) {
rate_ctr_inc(&cfg->ctrg->
@ -1291,7 +1294,7 @@ static int rx_reset_from_sgsn(struct gbproxy_config *cfg,
* from the SGSN. As the signalling BVCI is shared
* among all the BSS's that we multiplex, it needs to
* be relayed */
llist_for_each_entry(nse, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, i, nse, list) {
llist_for_each_entry(bvc, &nse->bvcs, list)
gbprox_relay2peer(msg, bvc, ns_bvci);
}
@ -1315,6 +1318,7 @@ static int gbprox_rx_sig_from_sgsn(struct gbproxy_config *cfg,
struct msgb *msg;
int rc = 0;
int cause;
int i;
if (ns_bvci != 0 && ns_bvci != 1) {
LOGP(DGPRS, LOGL_NOTICE, "NSE(%05u/SGSN) BVCI=%05u is not "
@ -1425,7 +1429,7 @@ static int gbprox_rx_sig_from_sgsn(struct gbproxy_config *cfg,
LOGP(DGPRS, LOGL_DEBUG,
"NSE(%05u/SGSN) BSSGP %s: broadcasting\n", nsei, bssgp_pdu_str(pdu_type));
/* broadcast to all BSS-side bvcs */
llist_for_each_entry(nse, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, i, nse, list) {
gbprox_relay2nse(msg, nse, 0);
}
break;
@ -1618,9 +1622,11 @@ int gprs_ns2_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
void gbprox_reset(struct gbproxy_config *cfg)
{
struct gbproxy_nse *nse, *ntmp;
struct gbproxy_nse *nse;
struct hlist_node *ntmp;
int i;
llist_for_each_entry_safe(nse, ntmp, &cfg->bss_nses, list) {
hash_for_each_safe(cfg->bss_nses, i, ntmp, nse, list) {
struct gbproxy_bvc *bvc, *tmp;
llist_for_each_entry_safe(bvc, tmp, &nse->bvcs, list)
gbproxy_bvc_free(bvc);
@ -1636,7 +1642,7 @@ int gbproxy_init_config(struct gbproxy_config *cfg)
{
struct timespec tp;
INIT_LLIST_HEAD(&cfg->bss_nses);
hash_init(cfg->bss_nses);
cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0);
if (!cfg->ctrg) {
LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n");

View File

@ -56,6 +56,7 @@ static int get_nsvc_state(struct ctrl_cmd *cmd, void *data)
struct gprs_ns2_inst *nsi = cfg->nsi;
struct gprs_ns2_nse *nse;
struct gbproxy_nse *nse_peer;
int i;
cmd->reply = talloc_strdup(cmd, "");
@ -69,7 +70,7 @@ static int get_nsvc_state(struct ctrl_cmd *cmd, void *data)
gprs_ns2_nse_foreach_nsvc(nse, &ctrl_nsvc_state_cb, cmd);
/* NS-VCs for BSS peers */
llist_for_each_entry(nse_peer, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, i, nse_peer, list) {
nse = gprs_ns2_nse_by_nsei(nsi, nse_peer->nsei);
if (nse)
gprs_ns2_nse_foreach_nsvc(nse, &ctrl_nsvc_state_cb, cmd);
@ -84,10 +85,11 @@ static int get_gbproxy_state(struct ctrl_cmd *cmd, void *data)
{
struct gbproxy_config *cfg = data;
struct gbproxy_nse *nse_peer;
int i;
cmd->reply = talloc_strdup(cmd, "");
llist_for_each_entry(nse_peer, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, i, nse_peer, list) {
struct gbproxy_bvc *bvc;
llist_for_each_entry(bvc, &nse_peer->bvcs, list) {
struct gprs_ra_id raid;
@ -111,8 +113,9 @@ static int get_num_peers(struct ctrl_cmd *cmd, void *data)
struct gbproxy_config *cfg = data;
struct gbproxy_nse *nse_peer;
uint32_t count = 0;
int i;
llist_for_each_entry(nse_peer, &cfg->bss_nses, list)
hash_for_each(cfg->bss_nses, i, nse_peer, list)
count += llist_count(&nse_peer->bvcs);
cmd->reply = talloc_strdup(cmd, "");

View File

@ -86,8 +86,9 @@ static const struct rate_ctr_group_desc bvc_ctrg_desc = {
struct gbproxy_bvc *gbproxy_bvc_by_bvci(struct gbproxy_config *cfg, uint16_t bvci)
{
struct gbproxy_nse *nse;
int i;
llist_for_each_entry(nse, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, i, nse, list) {
struct gbproxy_bvc *bvc;
llist_for_each_entry(bvc, &nse->bvcs, list) {
if (bvc->bvci == bvci)
@ -102,11 +103,11 @@ struct gbproxy_bvc *gbproxy_bvc_by_bvci(struct gbproxy_config *cfg, uint16_t bvc
struct gbproxy_bvc *gbproxy_bvc_by_nsei(struct gbproxy_config *cfg,
uint16_t nsei)
{
struct gbproxy_nse *nse;
llist_for_each_entry(nse, &cfg->bss_nses, list) {
if (nse->nsei == nsei && !llist_empty(&nse->bvcs))
return llist_first_entry(&nse->bvcs, struct gbproxy_bvc, list);
}
struct gbproxy_nse *nse = gbproxy_nse_by_nsei(cfg, nsei);
if (nse && !llist_empty(&nse->bvcs))
return llist_first_entry(&nse->bvcs, struct gbproxy_bvc, list);
return NULL;
}
@ -116,8 +117,9 @@ struct gbproxy_bvc *gbproxy_bvc_by_rai(struct gbproxy_config *cfg,
const uint8_t *ra)
{
struct gbproxy_nse *nse;
int i;
llist_for_each_entry(nse, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, i, nse, list) {
struct gbproxy_bvc *bvc;
llist_for_each_entry(bvc, &nse->bvcs, list) {
if (!memcmp(bvc->ra, ra, 6))
@ -134,8 +136,9 @@ struct gbproxy_bvc *gbproxy_bvc_by_lai(struct gbproxy_config *cfg,
const uint8_t *la)
{
struct gbproxy_nse *nse;
int i;
llist_for_each_entry(nse, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, i, nse, list) {
struct gbproxy_bvc *bvc;
llist_for_each_entry(bvc, &nse->bvcs, list) {
if (!memcmp(bvc->ra, la, 5))
@ -151,8 +154,9 @@ struct gbproxy_bvc *gbproxy_bvc_by_lac(struct gbproxy_config *cfg,
const uint8_t *la)
{
struct gbproxy_nse *nse;
int i;
llist_for_each_entry(nse, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, i, nse, list) {
struct gbproxy_bvc *bvc;
llist_for_each_entry(bvc, &nse->bvcs, list) {
if (!memcmp(bvc->ra + 3, la + 3, 2))
@ -268,11 +272,12 @@ void gbproxy_bvc_move(struct gbproxy_bvc *bvc, struct gbproxy_nse *nse)
* \param[in] bvci if 0: remove all BVCs; if != 0: BVCI of the single BVC to clean up */
int gbproxy_cleanup_bvcs(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci)
{
int counter = 0;
struct gbproxy_nse *nse, *ntmp;
int i, counter = 0;
struct gbproxy_nse *nse;
struct hlist_node *ntmp;
OSMO_ASSERT(cfg);
llist_for_each_entry_safe(nse, ntmp, &cfg->bss_nses, list) {
hash_for_each_safe(cfg->bss_nses, i, ntmp, nse, list) {
struct gbproxy_bvc *bvc, *tmp;
if (nse->nsei != nsei)
continue;
@ -300,7 +305,7 @@ struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei)
nse->nsei = nsei;
nse->cfg = cfg;
llist_add(&nse->list, &cfg->bss_nses);
hash_add(cfg->bss_nses, &nse->list, nsei);
INIT_LLIST_HEAD(&nse->bvcs);
@ -313,7 +318,7 @@ void gbproxy_nse_free(struct gbproxy_nse *nse)
if (!nse)
return;
llist_del(&nse->list);
hash_del(&nse->list);
llist_for_each_entry_safe(bvc, tmp, &nse->bvcs, list)
gbproxy_bvc_free(bvc);
@ -326,7 +331,7 @@ struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nse
struct gbproxy_nse *nse;
OSMO_ASSERT(cfg);
llist_for_each_entry(nse, &cfg->bss_nses, list) {
hash_for_each_possible(cfg->bss_nses, nse, list, nsei) {
if (nse->nsei == nsei)
return nse;
}

View File

@ -422,13 +422,14 @@ DEFUN(cfg_gbproxy_link_list_clean_stale_timer,
"Frequency at which the periodic timer is fired (in seconds)\n")
{
struct gbproxy_nse *nse;
int i;
g_cfg->clean_stale_timer_freq = (unsigned int) atoi(argv[0]);
/* Re-schedule running timers soon in case prev frequency was really big
and new frequency is desired to be lower. After initial run, periodic
time is used. Use random() to avoid firing timers for all bvcs at
the same time */
llist_for_each_entry(nse, &g_cfg->bss_nses, list) {
hash_for_each(g_cfg->bss_nses, i, nse, list) {
struct gbproxy_bvc *bvc;
llist_for_each_entry(bvc, &nse->bvcs, list)
osmo_timer_schedule(&bvc->clean_stale_timer,
@ -445,9 +446,10 @@ DEFUN(cfg_gbproxy_link_list_no_clean_stale_timer,
{
struct gbproxy_nse *nse;
int i;
g_cfg->clean_stale_timer_freq = 0;
llist_for_each_entry(nse, &g_cfg->bss_nses, list) {
hash_for_each(g_cfg->bss_nses, i, nse, list) {
struct gbproxy_bvc *bvc;
llist_for_each_entry(bvc, &nse->bvcs, list)
osmo_timer_del(&bvc->clean_stale_timer);
@ -580,11 +582,12 @@ DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy [stats]",
{
struct gbproxy_nse *nse;
int show_stats = argc >= 1;
int i;
if (show_stats)
vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
llist_for_each_entry(nse, &g_cfg->bss_nses, list) {
hash_for_each(g_cfg->bss_nses, i, nse, list) {
struct gbproxy_bvc *bvc;
llist_for_each_entry(bvc, &nse->bvcs, list) {
gbprox_vty_print_bvc(vty, bvc);
@ -602,11 +605,12 @@ DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
struct gbproxy_nse *nse;
time_t now;
struct timespec ts = {0,};
int i;
osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
now = ts.tv_sec;
llist_for_each_entry(nse, &g_cfg->bss_nses, list) {
hash_for_each(g_cfg->bss_nses, i, nse, list) {
struct gbproxy_bvc *bvc;
llist_for_each_entry(bvc, &nse->bvcs, list) {
struct gbproxy_link_info *link_info;
@ -703,8 +707,9 @@ DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
} else {
struct gbproxy_nse *nse;
struct gbproxy_bvc *bvc;
int i;
counter = 0;
llist_for_each_entry(nse, &g_cfg->bss_nses, list) {
hash_for_each(g_cfg->bss_nses, i, nse, list) {
if (nse->nsei != nsei)
continue;
llist_for_each_entry(bvc, &nse->bvcs, list) {

View File

@ -120,7 +120,7 @@ static int dump_peers(FILE *stream, int indent, time_t now,
{
struct gbproxy_nse *nse;
struct gprs_ra_id raid;
unsigned int i;
unsigned int i, _nse;
const struct rate_ctr_group_desc *desc;
int rc;
@ -129,7 +129,7 @@ static int dump_peers(FILE *stream, int indent, time_t now,
return rc;
llist_for_each_entry(nse, &cfg->bss_nses, list) {
hash_for_each(cfg->bss_nses, _nse, nse, list) {
struct gbproxy_bvc *peer;
llist_for_each_entry(peer, &nse->bvcs, list) {
struct gbproxy_link_info *link_info;