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:
parent
9c21dc3d16
commit
85062ccad3
|
@ -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()
|
|
@ -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) */
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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];
|
||||||
|
|
Loading…
Reference in New Issue