aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2020-12-05 00:31:07 +0100
committerHarald Welte <laforge@osmocom.org>2020-12-05 13:49:37 +0100
commit78db244b42be1e2bf9726cb2d80150876c70dedc (patch)
treebd726b8a33fdf6d2249492774c1e0c24d4815888
parent0e1b791c818181f5b95aa55d71d6b2469fb95475 (diff)
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
-rw-r--r--TODO-RELEASE1
-rw-r--r--include/osmocom/sgsn/gb_proxy.h5
-rw-r--r--src/gbproxy/gb_proxy.c22
-rw-r--r--src/gbproxy/gb_proxy_ctrl.c9
-rw-r--r--src/gbproxy/gb_proxy_peer.c35
-rw-r--r--src/gbproxy/gb_proxy_vty.c15
-rw-r--r--tests/gbproxy/gbproxy_test.c4
7 files changed, 56 insertions, 35 deletions
diff --git a/TODO-RELEASE b/TODO-RELEASE
index 6b29a879b..1e409b59c 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -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
diff --git a/include/osmocom/sgsn/gb_proxy.h b/include/osmocom/sgsn/gb_proxy.h
index 27b47cf8e..b0ab83d7c 100644
--- a/include/osmocom/sgsn/gb_proxy.h
+++ b/include/osmocom/sgsn/gb_proxy.h
@@ -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;
diff --git a/src/gbproxy/gb_proxy.c b/src/gbproxy/gb_proxy.c
index 4c34941f7..c37b21ad4 100644
--- a/src/gbproxy/gb_proxy.c
+++ b/src/gbproxy/gb_proxy.c
@@ -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");
diff --git a/src/gbproxy/gb_proxy_ctrl.c b/src/gbproxy/gb_proxy_ctrl.c
index c3cfddf7f..829041296 100644
--- a/src/gbproxy/gb_proxy_ctrl.c
+++ b/src/gbproxy/gb_proxy_ctrl.c
@@ -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, "");
diff --git a/src/gbproxy/gb_proxy_peer.c b/src/gbproxy/gb_proxy_peer.c
index c48a78f2c..00bff2088 100644
--- a/src/gbproxy/gb_proxy_peer.c
+++ b/src/gbproxy/gb_proxy_peer.c
@@ -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;
}
diff --git a/src/gbproxy/gb_proxy_vty.c b/src/gbproxy/gb_proxy_vty.c
index e79297d5e..da8afdc19 100644
--- a/src/gbproxy/gb_proxy_vty.c
+++ b/src/gbproxy/gb_proxy_vty.c
@@ -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) {
diff --git a/tests/gbproxy/gbproxy_test.c b/tests/gbproxy/gbproxy_test.c
index 553808964..bd5c8b531 100644
--- a/tests/gbproxy/gbproxy_test.c
+++ b/tests/gbproxy/gbproxy_test.c
@@ -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;