From 78db244b42be1e2bf9726cb2d80150876c70dedc Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 5 Dec 2020 00:31:07 +0100 Subject: 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 --- src/gbproxy/gb_proxy.c | 22 ++++++++++++++-------- src/gbproxy/gb_proxy_ctrl.c | 9 ++++++--- src/gbproxy/gb_proxy_peer.c | 35 ++++++++++++++++++++--------------- src/gbproxy/gb_proxy_vty.c | 15 ++++++++++----- 4 files changed, 50 insertions(+), 31 deletions(-) (limited to 'src') 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 #include +#include #include #include #include @@ -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) { -- cgit v1.2.3