Optimize subscr_conns lookup

It was found that, on a busy osmo-bsc (>1000 concurrent calls spread over
several BTS), the CPU consumption looking up for gsm_subscriber_conn
based on SCCP conn_id can take a considerable amount of time (>5% of
osmo-bsc already taking 70% of the CPU time on the core it is running on).

The huge CPU consumption happens because a linear search is done (llist)
over the entire list of SCCP connections every time an SCCP message is
handled.

In order to optimize this lookup, this patch introduces a new struct
bsc_sccp_inst which becomes associated to the libosmo-sccp
osmo_sccp_instance. Each of this strucs maintains an rbtree of
gsm_subscriber_conn ordered by conn_id.
As a result algorithmic complexity adds O(log(N)) during insert, lookup
and delete of SCCP conns, but gets rid of O(N) previous lookup.
As a plus, finding a new conn_id now takes generally O(log(N)), while
before it used to take O(N).

Related: SYS#6200
Change-Id: I667d3ec1dad0ab7bc0fa4799d9611f3a914d07e5
This commit is contained in:
Pau Espin 2023-03-13 12:21:57 +01:00 committed by pespin
parent 9c21dc3d16
commit 85062ccad3
6 changed files with 155 additions and 101 deletions

View File

@ -12,3 +12,4 @@
osmo-bsc CTRL,VTY osmo_fsm instance IDs now use new dynamic timeslot names 'DYNAMIC_OSMOCOM' and 'DYNAMIC_IPACCESS' osmo-bsc CTRL,VTY osmo_fsm instance IDs now use new dynamic timeslot names 'DYNAMIC_OSMOCOM' and 'DYNAMIC_IPACCESS'
libosmogsm >1.8.0 circuit switched data stuff (gsm0808_enc/dec_channel_type etc.) libosmogsm >1.8.0 circuit switched data stuff (gsm0808_enc/dec_channel_type etc.)
libosmo-abis >1.4.0 osmo_ortp.h: add RTP_PT_CSDATA libosmo-abis >1.4.0 osmo_ortp.h: add RTP_PT_CSDATA
libosmo-sccp >1.7.0 osmo_sccp_{get,set}_priv()

View File

@ -19,6 +19,8 @@
#include <osmocom/core/fsm.h> #include <osmocom/core/fsm.h>
#include <osmocom/core/tdef.h> #include <osmocom/core/tdef.h>
#include <osmocom/core/time_cc.h> #include <osmocom/core/time_cc.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/linuxrbtree.h>
#include <osmocom/crypt/auth.h> #include <osmocom/crypt/auth.h>
@ -331,6 +333,9 @@ struct gsm_subscriber_connection {
/* SCCP connection related */ /* SCCP connection related */
struct bsc_msc_data *msc; struct bsc_msc_data *msc;
/* entry in (struct bsc_sccp_inst)->connections */
struct rb_node node;
/* Sigtran connection ID: /* Sigtran connection ID:
* if set: Range (0..SCCP_CONN_ID_MAX) (24 bit) * if set: Range (0..SCCP_CONN_ID_MAX) (24 bit)
* if unset: SCCP_CONN_ID_UNSET (-1) if unset */ * if unset: SCCP_CONN_ID_UNSET (-1) if unset */
@ -871,6 +876,19 @@ struct all_allocated {
struct osmo_time_cc static_tch; struct osmo_time_cc static_tch;
}; };
struct bsc_sccp_inst {
struct osmo_sccp_instance *sccp; /* backpointer */
/* rbtree root of 'sstruct gsm_subscriber_connection' in this instance, ordered by conn_id */
struct rb_root connections;
uint32_t next_id; /* next id to allocate */
};
struct bsc_sccp_inst *bsc_sccp_inst_alloc(void *ctx);
uint32_t bsc_sccp_inst_next_conn_id(struct bsc_sccp_inst *bsc_sccp);
int bsc_sccp_inst_register_gscon(struct bsc_sccp_inst *bsc_sccp, struct gsm_subscriber_connection *conn);
void bsc_sccp_inst_unregister_gscon(struct bsc_sccp_inst *bsc_sccp, struct gsm_subscriber_connection *conn);
struct gsm_subscriber_connection *bsc_sccp_inst_get_gscon_by_conn_id(const struct bsc_sccp_inst *bsc_sccp, uint32_t conn_id);
struct gsm_network { struct gsm_network {
struct osmo_plmn_id plmn; struct osmo_plmn_id plmn;
@ -1030,8 +1048,6 @@ enum gsm_phys_chan_config gsm_pchan_by_lchan_type(enum gsm_chan_t type);
enum gsm48_rr_cause bsc_gsm48_rr_cause_from_gsm0808_cause(enum gsm0808_cause c); enum gsm48_rr_cause bsc_gsm48_rr_cause_from_gsm0808_cause(enum gsm0808_cause c);
enum gsm48_rr_cause bsc_gsm48_rr_cause_from_rsl_cause(uint8_t c); enum gsm48_rr_cause bsc_gsm48_rr_cause_from_rsl_cause(uint8_t c);
uint32_t bsc_sccp_inst_next_conn_id(struct osmo_sccp_instance *sccp);
/* Interference Measurement Parameters */ /* Interference Measurement Parameters */
struct gsm_interf_meas_params { struct gsm_interf_meas_params {
/* Intave: Interference Averaging period (see 3GPP TS 45.008, table A.1) */ /* Intave: Interference Averaging period (see 3GPP TS 45.008, table A.1) */

View File

@ -27,11 +27,82 @@
#include <osmocom/bsc/bsc_msc_data.h> #include <osmocom/bsc/bsc_msc_data.h>
#include <osmocom/bsc/lb.h> #include <osmocom/bsc/lb.h>
/* We need an unused SCCP conn_id across all SCCP users. */ struct bsc_sccp_inst *bsc_sccp_inst_alloc(void *ctx)
uint32_t bsc_sccp_inst_next_conn_id(struct osmo_sccp_instance *sccp)
{ {
static uint32_t next_id = 1; struct bsc_sccp_inst *bsc_sccp;
int i;
bsc_sccp = talloc_zero(ctx, struct bsc_sccp_inst);
OSMO_ASSERT(bsc_sccp);
bsc_sccp->next_id = 1;
return bsc_sccp;
}
int bsc_sccp_inst_register_gscon(struct bsc_sccp_inst *bsc_sccp, struct gsm_subscriber_connection *conn)
{
struct rb_node **n = &(bsc_sccp->connections.rb_node);
struct rb_node *parent = NULL;
uint32_t conn_id = conn->sccp.conn_id;
OSMO_ASSERT(conn_id != SCCP_CONN_ID_UNSET);
while (*n) {
struct gsm_subscriber_connection *it;
it = container_of(*n, struct gsm_subscriber_connection, sccp.node);
parent = *n;
if (conn_id < it->sccp.conn_id) {
n = &((*n)->rb_left);
} else if (conn_id > it->sccp.conn_id) {
n = &((*n)->rb_right);
} else {
LOGP(DMSC, LOGL_ERROR,
"Trying to reserve already reserved conn_id %u\n", conn_id);
return -EEXIST;
}
}
rb_link_node(&conn->sccp.node, parent, n);
rb_insert_color(&conn->sccp.node, &bsc_sccp->connections);
return 0;
}
void bsc_sccp_inst_unregister_gscon(struct bsc_sccp_inst *bsc_sccp, struct gsm_subscriber_connection *conn)
{
OSMO_ASSERT(conn->sccp.conn_id != SCCP_CONN_ID_UNSET);
rb_erase(&conn->sccp.node, &bsc_sccp->connections);
}
/* Helper function to Check if the given connection id is already assigned */
struct gsm_subscriber_connection *bsc_sccp_inst_get_gscon_by_conn_id(const struct bsc_sccp_inst *bsc_sccp, uint32_t conn_id)
{
const struct rb_node *node = bsc_sccp->connections.rb_node;
struct gsm_subscriber_connection *conn;
OSMO_ASSERT(conn_id != SCCP_CONN_ID_UNSET);
/* Range (0..SCCP_CONN_ID_MAX) expected, see bsc_sccp_inst_next_conn_id() */
OSMO_ASSERT(conn_id <= SCCP_CONN_ID_MAX);
while (node) {
conn = container_of(node, struct gsm_subscriber_connection, sccp.node);
if (conn_id < conn->sccp.conn_id)
node = node->rb_left;
else if (conn_id > conn->sccp.conn_id)
node = node->rb_right;
else
return conn;
}
return NULL;
}
/* We need an unused SCCP conn_id across all SCCP users. */
uint32_t bsc_sccp_inst_next_conn_id(struct bsc_sccp_inst *bsc_sccp)
{
uint32_t first_id, test_id;
first_id = test_id = bsc_sccp->next_id;
/* SUA: RFC3868 sec 3.10.4: /* SUA: RFC3868 sec 3.10.4:
* The source reference number is a 4 octet long integer. * The source reference number is a 4 octet long integer.
@ -41,59 +112,26 @@ uint32_t bsc_sccp_inst_next_conn_id(struct osmo_sccp_instance *sccp)
* reference number which is generated and used by the local node to identify the * reference number which is generated and used by the local node to identify the
* connection section after the connection section is set up. * connection section after the connection section is set up.
* The coding "all ones" is reserved for future use. * The coding "all ones" is reserved for future use.
* Hence, let's simply use 24 bit ids to fit all link types (excluding 0x00ffffff). *Hence, as we currently use the connection ID also as local reference,
*let's simply use 24 bit ids to fit all link types (excluding 0x00ffffff).
*/ */
/* This looks really suboptimal, but in most cases the static next_id should indicate exactly the next unused while (bsc_sccp_inst_get_gscon_by_conn_id(bsc_sccp, test_id)) {
* conn_id, and we only iterate all conns once to make super sure that it is not already in use. */
/* SCCP towards SMLC: */
if (bsc_gsmnet->smlc->sccp == sccp) {
for (i = 0; i < SCCP_CONN_ID_MAX; i++) {
struct gsm_subscriber_connection *conn;
uint32_t conn_id = next_id;
bool conn_id_already_used = false;
/* Optimized modulo operation (% SCCP_CONN_ID_MAX) using bitwise AND plus CMP: */
next_id = (next_id + 1) & 0x00FFFFFF;
if (OSMO_UNLIKELY(next_id == 0x00FFFFFF))
next_id = 0;
llist_for_each_entry(conn, &bsc_gsmnet->subscr_conns, entry) {
if (conn->lcs.lb.state != SUBSCR_SCCP_ST_NONE &&
conn->lcs.lb.conn_id == conn_id) {
conn_id_already_used = true;
break;
}
}
if (!conn_id_already_used)
return conn_id;
}
return 0xFFFFFFFF;
}
/* SCCP towards MSC: */
for (i = 0; i < SCCP_CONN_ID_MAX; i++) {
struct gsm_subscriber_connection *conn;
uint32_t conn_id = next_id;
bool conn_id_already_used = false;
/* Optimized modulo operation (% SCCP_CONN_ID_MAX) using bitwise AND plus CMP: */ /* Optimized modulo operation (% SCCP_CONN_ID_MAX) using bitwise AND plus CMP: */
next_id = (next_id + 1) & 0x00FFFFFF; test_id = (test_id + 1) & 0x00FFFFFF;
if (OSMO_UNLIKELY(next_id == 0x00FFFFFF)) if (OSMO_UNLIKELY(test_id == 0x00FFFFFF))
next_id = 0; test_id = 0;
llist_for_each_entry(conn, &bsc_gsmnet->subscr_conns, entry) { /* Did a whole loop, all used, fail */
if (conn->sccp.msc && conn->sccp.msc->a.sccp == sccp && if (OSMO_UNLIKELY(test_id == first_id))
conn->sccp.conn_id == conn_id) { return SCCP_CONN_ID_UNSET;
conn_id_already_used = true;
break;
}
}
if (!conn_id_already_used)
return conn_id;
} }
return SCCP_CONN_ID_UNSET;
bsc_sccp->next_id = test_id;
/* Optimized modulo operation (% SCCP_CONN_ID_MAX) using bitwise AND plus CMP: */
bsc_sccp->next_id = (bsc_sccp->next_id + 1) & 0x00FFFFFF;
if (OSMO_UNLIKELY(bsc_sccp->next_id == 0x00FFFFFF))
bsc_sccp->next_id = 0;
return test_id;
} }

View File

@ -1111,6 +1111,11 @@ static void gscon_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cau
osmo_sccp_tx_disconn(msc->a.sccp_user, conn->sccp.conn_id, &msc->a.bsc_addr, 0); osmo_sccp_tx_disconn(msc->a.sccp_user, conn->sccp.conn_id, &msc->a.bsc_addr, 0);
conn->sccp.state = SUBSCR_SCCP_ST_NONE; conn->sccp.state = SUBSCR_SCCP_ST_NONE;
} }
if (conn->sccp.conn_id != SCCP_CONN_ID_UNSET && conn->sccp.msc) {
struct bsc_sccp_inst *bsc_sccp = osmo_sccp_get_priv(conn->sccp.msc->a.sccp);
bsc_sccp_inst_unregister_gscon(bsc_sccp, conn);
conn->sccp.conn_id = SCCP_CONN_ID_UNSET;
}
if (conn->bsub) { if (conn->bsub) {
LOGPFSML(fi, LOGL_DEBUG, "Putting bsc_subscr\n"); LOGPFSML(fi, LOGL_DEBUG, "Putting bsc_subscr\n");

View File

@ -31,22 +31,7 @@
#include <osmocom/bsc/osmo_bsc_sigtran.h> #include <osmocom/bsc/osmo_bsc_sigtran.h>
#include <osmocom/bsc/lcs_loc_req.h> #include <osmocom/bsc/lcs_loc_req.h>
#include <osmocom/bsc/bssmap_reset.h> #include <osmocom/bsc/bssmap_reset.h>
#include <osmocom/bsc/gsm_data.h>
static struct gsm_subscriber_connection *get_bsc_conn_by_lb_conn_id(uint32_t conn_id)
{
struct gsm_subscriber_connection *conn;
/* Range (0..SCCP_CONN_ID_MAX) expected, see bsc_sccp_inst_next_conn_id() */
OSMO_ASSERT(conn_id <= SCCP_CONN_ID_MAX);
llist_for_each_entry(conn, &bsc_gsmnet->subscr_conns, entry) {
if (conn->lcs.lb.state != SUBSCR_SCCP_ST_NONE
&& conn->lcs.lb.conn_id == conn_id)
return conn;
}
return NULL;
}
/* Send reset to SMLC */ /* Send reset to SMLC */
int bssmap_le_tx_reset(void) int bssmap_le_tx_reset(void)
@ -150,6 +135,8 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
{ {
struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph; struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph;
struct osmo_sccp_user *scu = _scu; struct osmo_sccp_user *scu = _scu;
struct osmo_sccp_instance *sccp = osmo_sccp_get_sccp(scu);
struct bsc_sccp_inst *bsc_sccp = osmo_sccp_get_priv(sccp);
struct gsm_subscriber_connection *conn; struct gsm_subscriber_connection *conn;
int rc = 0; int rc = 0;
@ -172,7 +159,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM): case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
/* Handle inbound confirmation of outbound connection */ /* Handle inbound confirmation of outbound connection */
DEBUGP(DLCS, "N-CONNECT.cnf(%u)\n", scu_prim->u.connect.conn_id); DEBUGP(DLCS, "N-CONNECT.cnf(%u)\n", scu_prim->u.connect.conn_id);
conn = get_bsc_conn_by_lb_conn_id(scu_prim->u.connect.conn_id); conn = bsc_sccp_inst_get_gscon_by_conn_id(bsc_sccp, scu_prim->u.connect.conn_id);
if (conn) { if (conn) {
conn->lcs.lb.state = SUBSCR_SCCP_ST_CONNECTED; conn->lcs.lb.state = SUBSCR_SCCP_ST_CONNECTED;
if (msgb_l2len(oph->msg) > 0) { if (msgb_l2len(oph->msg) > 0) {
@ -188,7 +175,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
/* Handle incoming connection oriented data */ /* Handle incoming connection oriented data */
DEBUGP(DLCS, "N-DATA.ind(%u)\n", scu_prim->u.data.conn_id); DEBUGP(DLCS, "N-DATA.ind(%u)\n", scu_prim->u.data.conn_id);
conn = get_bsc_conn_by_lb_conn_id(scu_prim->u.data.conn_id); conn = bsc_sccp_inst_get_gscon_by_conn_id(bsc_sccp, scu_prim->u.data.conn_id);
if (!conn) { if (!conn) {
LOGP(DLCS, LOGL_ERROR, "N-DATA.ind(%u) for unknown conn_id\n", scu_prim->u.data.conn_id); LOGP(DLCS, LOGL_ERROR, "N-DATA.ind(%u) for unknown conn_id\n", scu_prim->u.data.conn_id);
rc = -EINVAL; rc = -EINVAL;
@ -206,7 +193,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)), osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)),
scu_prim->u.disconnect.cause); scu_prim->u.disconnect.cause);
/* indication of disconnect */ /* indication of disconnect */
conn = get_bsc_conn_by_lb_conn_id(scu_prim->u.disconnect.conn_id); conn = bsc_sccp_inst_get_gscon_by_conn_id(bsc_sccp, scu_prim->u.disconnect.conn_id);
if (!conn) { if (!conn) {
LOGP(DLCS, LOGL_ERROR, "N-DISCONNECT.ind for unknown conn_id %u\n", LOGP(DLCS, LOGL_ERROR, "N-DISCONNECT.ind for unknown conn_id %u\n",
scu_prim->u.disconnect.conn_id); scu_prim->u.disconnect.conn_id);
@ -234,6 +221,7 @@ static int lb_open_conn(struct gsm_subscriber_connection *conn, struct msgb *msg
struct osmo_ss7_instance *ss7; struct osmo_ss7_instance *ss7;
uint32_t conn_id; uint32_t conn_id;
int rc; int rc;
struct bsc_sccp_inst *bsc_sccp = osmo_sccp_get_priv(bsc_gsmnet->smlc->sccp);
OSMO_ASSERT(conn); OSMO_ASSERT(conn);
OSMO_ASSERT(msg); OSMO_ASSERT(msg);
@ -244,7 +232,7 @@ static int lb_open_conn(struct gsm_subscriber_connection *conn, struct msgb *msg
return -EINVAL; return -EINVAL;
} }
conn_id = bsc_sccp_inst_next_conn_id(bsc_gsmnet->smlc->sccp); conn_id = bsc_sccp_inst_next_conn_id(bsc_sccp);
if (conn_id == SCCP_CONN_ID_UNSET) { if (conn_id == SCCP_CONN_ID_UNSET) {
LOGPFSMSL(conn->fi, DLCS, LOGL_ERROR, "Unable to allocate SCCP Connection ID for BSSMAP-LE to SMLC\n"); LOGPFSMSL(conn->fi, DLCS, LOGL_ERROR, "Unable to allocate SCCP Connection ID for BSSMAP-LE to SMLC\n");
return -ENOSPC; return -ENOSPC;
@ -421,6 +409,7 @@ static int lb_start(void)
enum osmo_ss7_asp_protocol used_proto = OSMO_SS7_ASP_PROT_M3UA; enum osmo_ss7_asp_protocol used_proto = OSMO_SS7_ASP_PROT_M3UA;
char inst_name[32]; char inst_name[32];
const char *smlc_name = "smlc"; const char *smlc_name = "smlc";
struct bsc_sccp_inst *bsc_sccp;
/* Already set up? */ /* Already set up? */
if (bsc_gsmnet->smlc->sccp_user) if (bsc_gsmnet->smlc->sccp_user)
@ -454,6 +443,9 @@ static int lb_start(void)
if (!sccp) if (!sccp)
return -EINVAL; return -EINVAL;
bsc_gsmnet->smlc->sccp = sccp; bsc_gsmnet->smlc->sccp = sccp;
bsc_sccp = bsc_sccp_inst_alloc(tall_bsc_ctx);
bsc_sccp->sccp = sccp;
osmo_sccp_set_priv(sccp, bsc_sccp);
/* If unset, use default local SCCP address */ /* If unset, use default local SCCP address */
if (!bsc_gsmnet->smlc->bsc_addr.presence) if (!bsc_gsmnet->smlc->bsc_addr.presence)

View File

@ -45,26 +45,6 @@ static struct llist_head *msc_list;
#define DEFAULT_ASP_LOCAL_IP "localhost" #define DEFAULT_ASP_LOCAL_IP "localhost"
#define DEFAULT_ASP_REMOTE_IP "localhost" #define DEFAULT_ASP_REMOTE_IP "localhost"
/* Helper function to Check if the given connection id is already assigned */
static struct gsm_subscriber_connection *get_bsc_conn_by_conn_id(const struct osmo_sccp_user *scu, uint32_t conn_id)
{
struct gsm_subscriber_connection *conn;
const struct osmo_sccp_instance *sccp = osmo_sccp_get_sccp(scu);
/* Range (0..SCCP_CONN_ID_MAX) expected, see bsc_sccp_inst_next_conn_id() */
OSMO_ASSERT(conn_id <= SCCP_CONN_ID_MAX);
llist_for_each_entry(conn, &bsc_gsmnet->subscr_conns, entry) {
if (conn->sccp.msc && conn->sccp.msc->a.sccp != sccp)
continue;
if (conn->sccp.conn_id != conn_id)
continue;
return conn;
}
return NULL;
}
struct gsm_subscriber_connection *bsc_conn_by_bsub(const struct bsc_subscr *bsub) struct gsm_subscriber_connection *bsc_conn_by_bsub(const struct bsc_subscr *bsub)
{ {
struct gsm_subscriber_connection *conn; struct gsm_subscriber_connection *conn;
@ -170,10 +150,12 @@ static int handle_unitdata_from_msc(const struct osmo_sccp_addr *msc_addr, struc
static int handle_n_connect_from_msc(struct osmo_sccp_user *scu, struct osmo_scu_prim *scu_prim) static int handle_n_connect_from_msc(struct osmo_sccp_user *scu, struct osmo_scu_prim *scu_prim)
{ {
struct bsc_msc_data *msc = get_msc_by_addr(&scu_prim->u.connect.calling_addr); struct bsc_msc_data *msc = get_msc_by_addr(&scu_prim->u.connect.calling_addr);
struct osmo_sccp_instance *sccp = osmo_sccp_get_sccp(scu);
struct bsc_sccp_inst *bsc_sccp = osmo_sccp_get_priv(sccp);
struct gsm_subscriber_connection *conn; struct gsm_subscriber_connection *conn;
int rc = 0; int rc = 0;
conn = get_bsc_conn_by_conn_id(scu, scu_prim->u.connect.conn_id); conn = bsc_sccp_inst_get_gscon_by_conn_id(bsc_sccp, scu_prim->u.connect.conn_id);
if (conn) { if (conn) {
LOGP(DMSC, LOGL_NOTICE, LOGP(DMSC, LOGL_NOTICE,
"(calling_addr=%s conn_id=%u) N-CONNECT.ind with already used conn_id, ignoring\n", "(calling_addr=%s conn_id=%u) N-CONNECT.ind with already used conn_id, ignoring\n",
@ -202,6 +184,13 @@ static int handle_n_connect_from_msc(struct osmo_sccp_user *scu, struct osmo_scu
return -ENOMEM; return -ENOMEM;
conn->sccp.msc = msc; conn->sccp.msc = msc;
conn->sccp.conn_id = scu_prim->u.connect.conn_id; conn->sccp.conn_id = scu_prim->u.connect.conn_id;
if (bsc_sccp_inst_register_gscon(bsc_sccp, conn) < 0) {
LOGP(DMSC, LOGL_NOTICE, "(calling_addr=%s conn_id=%u) N-CONNECT.ind failed registering conn\n",
osmo_sccp_addr_dump(&scu_prim->u.connect.calling_addr), scu_prim->u.connect.conn_id);
osmo_fsm_inst_term(conn->fi, OSMO_FSM_TERM_REQUEST, NULL);
rc = -ENOENT;
goto refuse;
}
/* Take actions asked for by the enclosed PDU */ /* Take actions asked for by the enclosed PDU */
osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_IND, scu_prim); osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_IND, scu_prim);
@ -217,6 +206,8 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
{ {
struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph; struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph;
struct osmo_sccp_user *scu = _scu; struct osmo_sccp_user *scu = _scu;
struct osmo_sccp_instance *sccp = osmo_sccp_get_sccp(scu);
struct bsc_sccp_inst *bsc_sccp = osmo_sccp_get_priv(sccp);
struct gsm_subscriber_connection *conn; struct gsm_subscriber_connection *conn;
int rc = 0; int rc = 0;
@ -237,7 +228,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
/* Handle outbound connection confirmation */ /* Handle outbound connection confirmation */
DEBUGP(DMSC, "N-CONNECT.cnf(%u, %s)\n", scu_prim->u.connect.conn_id, DEBUGP(DMSC, "N-CONNECT.cnf(%u, %s)\n", scu_prim->u.connect.conn_id,
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
conn = get_bsc_conn_by_conn_id(scu, scu_prim->u.connect.conn_id); conn = bsc_sccp_inst_get_gscon_by_conn_id(bsc_sccp, scu_prim->u.connect.conn_id);
if (conn) { if (conn) {
osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_CFM, scu_prim); osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_CFM, scu_prim);
conn->sccp.state = SUBSCR_SCCP_ST_CONNECTED; conn->sccp.state = SUBSCR_SCCP_ST_CONNECTED;
@ -256,7 +247,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
/* Incoming data is a sign of a vital connection */ /* Incoming data is a sign of a vital connection */
conn = get_bsc_conn_by_conn_id(scu, scu_prim->u.data.conn_id); conn = bsc_sccp_inst_get_gscon_by_conn_id(bsc_sccp, scu_prim->u.data.conn_id);
if (conn) { if (conn) {
a_reset_conn_success(conn->sccp.msc); a_reset_conn_success(conn->sccp.msc);
handle_data_from_msc(conn, oph->msg); handle_data_from_msc(conn, oph->msg);
@ -268,7 +259,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)), osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)),
scu_prim->u.disconnect.cause); scu_prim->u.disconnect.cause);
/* indication of disconnect */ /* indication of disconnect */
conn = get_bsc_conn_by_conn_id(scu, scu_prim->u.disconnect.conn_id); conn = bsc_sccp_inst_get_gscon_by_conn_id(bsc_sccp, scu_prim->u.disconnect.conn_id);
if (conn) { if (conn) {
conn->sccp.state = SUBSCR_SCCP_ST_NONE; conn->sccp.state = SUBSCR_SCCP_ST_NONE;
if (msgb_l2len(oph->msg) > 0) if (msgb_l2len(oph->msg) > 0)
@ -323,6 +314,7 @@ __attribute__((weak)) int osmo_bsc_sigtran_open_conn(struct gsm_subscriber_conne
{ {
struct osmo_ss7_instance *ss7; struct osmo_ss7_instance *ss7;
struct bsc_msc_data *msc; struct bsc_msc_data *msc;
struct bsc_sccp_inst *bsc_sccp;
uint32_t conn_id; uint32_t conn_id;
int rc; int rc;
@ -338,11 +330,16 @@ __attribute__((weak)) int osmo_bsc_sigtran_open_conn(struct gsm_subscriber_conne
return -EINVAL; return -EINVAL;
} }
conn->sccp.conn_id = conn_id = bsc_sccp_inst_next_conn_id(conn->sccp.msc->a.sccp); bsc_sccp = osmo_sccp_get_priv(msc->a.sccp);
conn->sccp.conn_id = conn_id = bsc_sccp_inst_next_conn_id(bsc_sccp);
if (conn->sccp.conn_id == SCCP_CONN_ID_UNSET) { if (conn->sccp.conn_id == SCCP_CONN_ID_UNSET) {
LOGP(DMSC, LOGL_ERROR, "Unable to allocate SCCP Connection ID\n"); LOGP(DMSC, LOGL_ERROR, "Unable to allocate SCCP Connection ID\n");
return -1; return -1;
} }
if (bsc_sccp_inst_register_gscon(bsc_sccp, conn) < 0) {
LOGP(DMSC, LOGL_ERROR, "Unable to register SCCP connection (id=%u)\n", conn->sccp.conn_id);
return -1;
}
LOGP(DMSC, LOGL_DEBUG, "Allocated new connection id: %u\n", conn->sccp.conn_id); LOGP(DMSC, LOGL_DEBUG, "Allocated new connection id: %u\n", conn->sccp.conn_id);
ss7 = osmo_ss7_instance_find(msc->a.cs7_instance); ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
OSMO_ASSERT(ss7); OSMO_ASSERT(ss7);
@ -520,6 +517,7 @@ int osmo_bsc_sigtran_init(struct llist_head *mscs)
int prev_msc_nr; int prev_msc_nr;
struct osmo_sccp_instance *sccp; struct osmo_sccp_instance *sccp;
struct bsc_sccp_inst *bsc_sccp;
llist_for_each_entry(msc, msc_list, entry) { llist_for_each_entry(msc, msc_list, entry) {
/* An MSC with invalid cs7 instance id defaults to cs7 instance 0 */ /* An MSC with invalid cs7 instance id defaults to cs7 instance 0 */
@ -563,6 +561,10 @@ int osmo_bsc_sigtran_init(struct llist_head *mscs)
if (!sccp) if (!sccp)
return -EINVAL; return -EINVAL;
bsc_sccp = bsc_sccp_inst_alloc(tall_bsc_ctx);
bsc_sccp->sccp = sccp;
osmo_sccp_set_priv(sccp, bsc_sccp);
/* Now that the SCCP client is set up, configure all MSCs on this cs7 instance to use it */ /* Now that the SCCP client is set up, configure all MSCs on this cs7 instance to use it */
llist_for_each_entry(msc, msc_list, entry) { llist_for_each_entry(msc, msc_list, entry) {
char msc_name[32]; char msc_name[32];