neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-hnbgw/+/33136 )
Change subject: cnpool: select CN link from pool by NRI or round robin
......................................................................
cnpool: select CN link from pool by NRI or round robin
This is the bulk of the CN pooling logic but is not working properly
without these future patches:
- detect in/active CN links by RANAP RESET
Id3eefdea889a736fd5957b80280fa45b9547b792
- return Paging Resp to the exact CN link that Paged
I907dbcaeb442ca5630146f8cad40601c448fc40e
Change-Id: I66fba27cfbe6e2b27ee3443718846ecfbbd8a974
---
M src/osmo-hnbgw/hnbgw_cn.c
1 file changed, 162 insertions(+), 10 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-hnbgw refs/changes/36/33136/1
diff --git a/src/osmo-hnbgw/hnbgw_cn.c b/src/osmo-hnbgw/hnbgw_cn.c
index 486d30a..f33023e 100644
--- a/src/osmo-hnbgw/hnbgw_cn.c
+++ b/src/osmo-hnbgw/hnbgw_cn.c
@@ -702,21 +702,155 @@
return NULL;
}
+static bool is_cnlink_usable(struct hnbgw_cnlink *cnlink, bool is_emerg)
+{
+ if (is_emerg && !cnlink->allow_emerg)
+ return false;
+ if (!cnlink->hnbgw_sccp_user || !cnlink->hnbgw_sccp_user->sccp_user)
+ return false;
+ // TODO indicator whether the CN link is actually active, akin to bssmap_reset_is_conn_ready()
+ return true;
+}
+
+/* Decide which MSC/SGSN to forward this Complete Layer 3 request to. The current Layer 3 Info is passed in map->l3.
+ * a) If the subscriber was previously paged from a particular CN link, that CN link shall receive the Paging Response.
+ * b) If the message contains an NRI indicating a particular CN link that is currently connected, that CN link shall
+ * handle this conn.
+ * c) All other cases distribute the messages across connected CN links in a round-robin fashion.
+ */
struct hnbgw_cnlink *hnbgw_cnlink_select(struct hnbgw_context_map *map)
{
struct hnbgw_cnpool *cnpool = map->is_ps ? &g_hnbgw->sccp.cnpool_iups : &g_hnbgw->sccp.cnpool_iucs;
struct hnbgw_cnlink *cnlink;
- /* FUTURE: soon we will pick one of many configurable CN peers from a pool. There will be more input arguments
- * (MI, or TMSI, or NRI decoded from RANAP) and this function will do round robin for new subscribers. */
- llist_for_each_entry(cnlink, &cnpool->cnlinks, entry) {
- if (!cnlink->hnbgw_sccp_user || !cnlink->hnbgw_sccp_user->sccp_user)
- continue;
- LOG_MAP(map, DCN, LOGL_INFO, "Selected %s / %s\n",
- cnlink->name,
- cnlink->hnbgw_sccp_user->name);
- return cnlink;
+ struct hnbgw_cnlink *round_robin_next = NULL;
+ struct hnbgw_cnlink *round_robin_first = NULL;
+ unsigned int round_robin_next_nr;
+ int16_t nri_v = -1;
+ bool is_null_nri = false;
+ uint8_t nri_bitlen = cnpool->use.nri_bitlen;
+
+#define LOG_NRI(LOGLEVEL, FORMAT, ARGS...) \
+ LOG_MAP(map, DCN, LOGLEVEL, "%s NRI(%dbit)=0x%x=%d: " FORMAT, osmo_mobile_identity_to_str_c(OTC_SELECT, &map->l3.mi), \
+ nri_bitlen, nri_v, nri_v, ##ARGS)
+
+ /* Get the NRI bits either from map->l3.nri, or extract NRI bits from TMSI.
+ * The NRI possibly indicates which MSC is responsible. */
+ if (map->l3.gmm_nri_container >= 0) {
+ nri_v = map->l3.gmm_nri_container;
+ /* The 'TMSI based NRI container' is always 10 bits long. If the relevant NRI length is configured to be
+ * less than that, ignore the lower bits. */
+ if (nri_bitlen < 10)
+ nri_v >>= 10 - nri_bitlen;
+ } else if (map->l3.mi.type == GSM_MI_TYPE_TMSI) {
+ if (osmo_tmsi_nri_v_get(&nri_v, map->l3.mi.tmsi, nri_bitlen)) {
+ LOG_NRI(LOGL_ERROR, "Unable to retrieve NRI from TMSI 0x%x, nri_bitlen == %u\n", map->l3.mi.tmsi,
+ nri_bitlen);
+ nri_v = -1;
+ }
}
- return NULL;
+
+ if (map->l3.from_other_plmn && nri_v >= 0) {
+ /* If a subscriber was previously attached to a different PLMN, it might still send the other
+ * PLMN's TMSI identity in an IMSI Attach. The LU sends a LAI indicating the previous PLMN. If
+ * it mismatches our PLMN, ignore the NRI. */
+ LOG_NRI(LOGL_DEBUG,
+ "This Complete Layer 3 message indicates a switch from another PLMN. Ignoring the NRI.\n");
+ nri_v = -1;
+ }
+
+ if (nri_v >= 0)
+ is_null_nri = osmo_nri_v_matches_ranges(nri_v, cnpool->use.null_nri_ranges);
+ if (is_null_nri)
+ LOG_NRI(LOGL_DEBUG, "this is a NULL-NRI\n");
+
+ /* Iterate CN links to find one that matches the extracted NRI, and the next round-robin target for the case no
+ * NRI match is found. */
+ round_robin_next_nr = (map->l3.is_emerg ? cnpool->round_robin_next_emerg_nr : cnpool->round_robin_next_nr);
+ llist_for_each_entry(cnlink, &cnpool->cnlinks, entry) {
+ bool nri_matches_cnlink = (nri_v >= 0 && osmo_nri_v_matches_ranges(nri_v, cnlink->use.nri_ranges));
+
+ if (!is_cnlink_usable(cnlink, map->l3.is_emerg)) {
+ if (nri_matches_cnlink) {
+ LOG_NRI(LOGL_DEBUG, "NRI matches %s %d, but this %s is currently not connected\n",
+ cnpool->peer_name, cnlink->nr, cnpool->peer_name);
+ rate_ctr_inc(rate_ctr_group_get_ctr(cnlink->ctrs, CNLINK_CTR_CNPOOL_SUBSCR_ATTACH_LOST));
+ }
+ continue;
+ }
+
+ /* Return CN link if it matches this NRI, with some debug logging. */
+ if (nri_matches_cnlink) {
+ if (is_null_nri) {
+ LOG_NRI(LOGL_DEBUG, "NRI matches %s %d, but this NRI is also configured as NULL-NRI\n",
+ cnpool->peer_name, cnlink->nr);
+ } else {
+ LOG_NRI(LOGL_INFO, "NRI match selects %s %d\n", cnpool->peer_name, cnlink->nr);
+ rate_ctr_inc(rate_ctr_group_get_ctr(cnlink->ctrs, CNLINK_CTR_CNPOOL_SUBSCR_KNOWN));
+ if (map->l3.is_emerg) {
+ rate_ctr_inc(rate_ctr_group_get_ctr(cnlink->ctrs, CNLINK_CTR_CNPOOL_EMERG_FORWARDED));
+ rate_ctr_inc(rate_ctr_group_get_ctr(cnpool->ctrs, CNPOOL_CTR_EMERG_FORWARDED));
+ }
+ return cnlink;
+ }
+ }
+
+ /* Figure out the next round-robin MSC. The MSCs may appear unsorted in net->mscs. Make sure to linearly
+ * round robin the MSCs by number: pick the lowest msc->nr >= round_robin_next_nr, and also remember the
+ * lowest available msc->nr to wrap back to that in case no next MSC is left.
+ *
+ * MSCs configured with `no allow-attach` do not accept new subscribers and hence must not be picked by
+ * round-robin. Such an MSC still provides service for already attached subscribers: those that
+ * successfully performed IMSI-Attach and have a TMSI with an NRI pointing at that MSC. We only avoid
+ * adding IMSI-Attach of new subscribers. The idea is that the MSC is in a mode of off-loading
+ * subscribers, and the MSC decides when each subscriber is off-loaded, by assigning the NULL-NRI in a
+ * new TMSI (at the next periodical LU). So until the MSC decides to offload, an attached subscriber
+ * remains attached to that MSC and is free to use its services.
+ */
+ if (!cnlink->allow_attach)
+ continue;
+ /* Find the allowed cnlink with the lowest nr */
+ if (!round_robin_first || cnlink->nr < round_robin_first->nr)
+ round_robin_first = cnlink;
+ /* Find the allowed cnlink with the lowest nr >= round_robin_next_nr */
+ if (cnlink->nr >= round_robin_next_nr
+ && (!round_robin_next || cnlink->nr < round_robin_next->nr))
+ round_robin_next = cnlink;
+ }
+
+ if (nri_v >= 0 && !is_null_nri)
+ LOG_NRI(LOGL_DEBUG, "No %s found for this NRI, doing round-robin\n", cnpool->peer_name);
+
+ /* No dedicated CN link found. Choose by round-robin.
+ * If round_robin_next is NULL, there are either no more CN links at/after round_robin_next_nr, or none of
+ * them are usable -- wrap to the start. */
+ cnlink = round_robin_next ? : round_robin_first;
+ if (!cnlink) {
+ rate_ctr_inc(rate_ctr_group_get_ctr(cnpool->ctrs, CNPOOL_CTR_SUBSCR_NO_CNLINK));
+ if (map->l3.is_emerg)
+ rate_ctr_inc(rate_ctr_group_get_ctr(cnpool->ctrs, CNPOOL_CTR_EMERG_LOST));
+ return NULL;
+ }
+
+ LOGP(DCN, LOGL_DEBUG, "New subscriber MI=%s: CN link round-robin selects %s %d\n",
+ osmo_mobile_identity_to_str_c(OTC_SELECT, &map->l3.mi), cnpool->peer_name, cnlink->nr);
+
+ if (is_null_nri)
+ rate_ctr_inc(rate_ctr_group_get_ctr(cnlink->ctrs, CNLINK_CTR_CNPOOL_SUBSCR_REATTACH));
+ else
+ rate_ctr_inc(rate_ctr_group_get_ctr(cnlink->ctrs, CNLINK_CTR_CNPOOL_SUBSCR_NEW));
+
+ if (map->l3.is_emerg) {
+ rate_ctr_inc(rate_ctr_group_get_ctr(cnlink->ctrs, CNLINK_CTR_CNPOOL_EMERG_FORWARDED));
+ rate_ctr_inc(rate_ctr_group_get_ctr(cnpool->ctrs, CNPOOL_CTR_EMERG_FORWARDED));
+ }
+
+ /* A CN link was picked by round-robin, so update the next round-robin nr to pick */
+ if (map->l3.is_emerg)
+ cnpool->round_robin_next_emerg_nr = cnlink->nr + 1;
+ else
+ cnpool->round_robin_next_nr = cnlink->nr + 1;
+ return cnlink;
+#undef LOG_NRI
}
char *cnlink_sccp_addr_to_str(struct hnbgw_cnlink *cnlink, const struct osmo_sccp_addr *addr)
--
To view, visit https://gerrit.osmocom.org/c/osmo-hnbgw/+/33136
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-hnbgw
Gerrit-Branch: master
Gerrit-Change-Id: I66fba27cfbe6e2b27ee3443718846ecfbbd8a974
Gerrit-Change-Number: 33136
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: newchange
Jenkins Builder has posted comments on this change. ( https://gerrit.osmocom.org/c/osmo-hnbgw/+/33130 )
Change subject: cnpool: make NRI mappings VTY configurable
......................................................................
Patch Set 1:
(6 comments)
File src/osmo-hnbgw/hnbgw_vty.c:
Robot Comment from checkpatch (run ID jenkins-gerrit-lint-7702):
https://gerrit.osmocom.org/c/osmo-hnbgw/+/33130/comment/d7a5cf79_b5dec2f7
PS1, Line 357: #define NRI_ARGS_TO_STR_ARGS(ARGC, ARGV) ARGV[0], (ARGC>1)? ".." : "", (ARGC>1)? ARGV[1] : ""
spaces required around that '>' (ctx:VxV)
Robot Comment from checkpatch (run ID jenkins-gerrit-lint-7702):
https://gerrit.osmocom.org/c/osmo-hnbgw/+/33130/comment/112bce24_6df75d80
PS1, Line 357: #define NRI_ARGS_TO_STR_ARGS(ARGC, ARGV) ARGV[0], (ARGC>1)? ".." : "", (ARGC>1)? ARGV[1] : ""
spaces required around that '?' (ctx:VxW)
Robot Comment from checkpatch (run ID jenkins-gerrit-lint-7702):
https://gerrit.osmocom.org/c/osmo-hnbgw/+/33130/comment/5c6cd2eb_4a6f9cd9
PS1, Line 357: #define NRI_ARGS_TO_STR_ARGS(ARGC, ARGV) ARGV[0], (ARGC>1)? ".." : "", (ARGC>1)? ARGV[1] : ""
spaces required around that '>' (ctx:VxV)
Robot Comment from checkpatch (run ID jenkins-gerrit-lint-7702):
https://gerrit.osmocom.org/c/osmo-hnbgw/+/33130/comment/9811da44_2752ca42
PS1, Line 357: #define NRI_ARGS_TO_STR_ARGS(ARGC, ARGV) ARGV[0], (ARGC>1)? ".." : "", (ARGC>1)? ARGV[1] : ""
spaces required around that '?' (ctx:VxW)
Robot Comment from checkpatch (run ID jenkins-gerrit-lint-7702):
https://gerrit.osmocom.org/c/osmo-hnbgw/+/33130/comment/86fa6295_23be62a4
PS1, Line 518: if (message) {
braces {} are not necessary for single statement blocks
Robot Comment from checkpatch (run ID jenkins-gerrit-lint-7702):
https://gerrit.osmocom.org/c/osmo-hnbgw/+/33130/comment/235f054c_728cc61b
PS1, Line 558: if (message) {
braces {} are not necessary for single statement blocks
--
To view, visit https://gerrit.osmocom.org/c/osmo-hnbgw/+/33130
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-hnbgw
Gerrit-Branch: master
Gerrit-Change-Id: Ifb87e01e5971962e5cfe5e127871af4a67806de1
Gerrit-Change-Number: 33130
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-CC: Jenkins Builder
Gerrit-Comment-Date: Thu, 01 Jun 2023 02:42:27 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Gerrit-MessageType: comment
neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-hnbgw/+/33128 )
Change subject: cnpool prep: add SCCP_EV_USER_ABORT
......................................................................
cnpool prep: add SCCP_EV_USER_ABORT
To ease patch review, I decided to submit this separately from the
caller, which follows in subsequent patch
I5479eded786ec26062d49403a8be12967f113cdb
The new event will be dispatched when there are SCCP config changes
pending, and the human user types 'apply sccp' on the telnet VTY. The
aim is to disconnect all connections so we can create a new SCCP User.
Related: SYS#6412
Change-Id: Idff8e09b5328c904b175e4d4df7d4044a34f4a20
---
M include/osmocom/hnbgw/context_map.h
M src/osmo-hnbgw/context_map_sccp.c
2 files changed, 38 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-hnbgw refs/changes/28/33128/1
diff --git a/include/osmocom/hnbgw/context_map.h b/include/osmocom/hnbgw/context_map.h
index 55d96ea..bcc3238 100644
--- a/include/osmocom/hnbgw/context_map.h
+++ b/include/osmocom/hnbgw/context_map.h
@@ -55,6 +55,9 @@
MAP_SCCP_EV_RAN_LINK_LOST,
/* Receiving an SCCP RLSD from CN, or libosmo-sigtran tells us about SCCP connection timeout. All done. */
MAP_SCCP_EV_RX_RELEASED,
+ /* The human admin asks to drop the current SCCP connection, by telnet VTY 'apply sccp' in presence of SCCP
+ * config changes. */
+ MAP_SCCP_EV_USER_ABORT,
};
/* For context_map_get_state(), to combine the RUA and SCCP states, for VTY reporting only. */
diff --git a/src/osmo-hnbgw/context_map_sccp.c b/src/osmo-hnbgw/context_map_sccp.c
index 00b24f2..cc65b6e 100644
--- a/src/osmo-hnbgw/context_map_sccp.c
+++ b/src/osmo-hnbgw/context_map_sccp.c
@@ -54,6 +54,7 @@
OSMO_VALUE_STRING(MAP_SCCP_EV_RAN_DISC),
OSMO_VALUE_STRING(MAP_SCCP_EV_RAN_LINK_LOST),
OSMO_VALUE_STRING(MAP_SCCP_EV_RX_RELEASED),
+ OSMO_VALUE_STRING(MAP_SCCP_EV_USER_ABORT),
{}
};
@@ -281,6 +282,7 @@
case MAP_SCCP_EV_RAN_LINK_LOST:
case MAP_SCCP_EV_RAN_DISC:
+ case MAP_SCCP_EV_USER_ABORT:
/* No CR has been sent yet, just go to disconnected state. */
if (msg_has_l2_data(ranap_msg))
LOG_MAP(map, DLSCCP, LOGL_ERROR, "SCCP not connected, cannot dispatch RANAP message\n");
@@ -317,6 +319,7 @@
case MAP_SCCP_EV_RAN_LINK_LOST:
case MAP_SCCP_EV_RAN_DISC:
+ case MAP_SCCP_EV_USER_ABORT:
/* RUA connection was terminated. First wait for the CC before releasing the SCCP conn. */
if (msg_has_l2_data(ranap_msg))
LOGPFSML(fi, LOGL_ERROR, "Connection not yet confirmed, cannot forward RANAP to CN\n");
@@ -373,6 +376,9 @@
case MAP_SCCP_EV_RAN_LINK_LOST:
/* RUA has disconnected ungracefully, so there is no Iu Release that told the CN to disconnect.
* Disconnect on the SCCP layer, ungracefully. */
+ case MAP_SCCP_EV_USER_ABORT:
+ /* The user is asking for disconnection, so there is no Iu Release in progress. Disconnect now. */
+
/* There won't be any ranap_msg, but if a caller wants to dispatch a msg, forward it before
* disconnecting. */
tx_sccp_df1(fi, ranap_msg);
@@ -440,6 +446,12 @@
handle_rx_sccp(fi, ranap_msg);
return;
+ case MAP_SCCP_EV_USER_ABORT:
+ /* Stop waiting for RLSD, send RLSD now. */
+ tx_sccp_rlsd(fi);
+ map_sccp_fsm_state_chg(MAP_SCCP_ST_DISCONNECTED);
+ return;
+
default:
OSMO_ASSERT(false);
}
@@ -511,6 +523,7 @@
| S(MAP_SCCP_EV_RAN_DISC)
| S(MAP_SCCP_EV_RAN_LINK_LOST)
| S(MAP_SCCP_EV_RX_RELEASED)
+ | S(MAP_SCCP_EV_USER_ABORT)
,
.out_state_mask = 0
| S(MAP_SCCP_ST_INIT)
@@ -527,6 +540,7 @@
| S(MAP_SCCP_EV_RAN_DISC)
| S(MAP_SCCP_EV_RAN_LINK_LOST)
| S(MAP_SCCP_EV_RX_RELEASED)
+ | S(MAP_SCCP_EV_USER_ABORT)
,
.out_state_mask = 0
| S(MAP_SCCP_ST_CONNECTED)
@@ -543,6 +557,7 @@
| S(MAP_SCCP_EV_RAN_LINK_LOST)
| S(MAP_SCCP_EV_RX_RELEASED)
| S(MAP_SCCP_EV_RX_CONNECTION_CONFIRM)
+ | S(MAP_SCCP_EV_USER_ABORT)
,
.out_state_mask = 0
| S(MAP_SCCP_ST_WAIT_RLSD)
@@ -560,6 +575,7 @@
| S(MAP_SCCP_EV_RAN_DISC)
| S(MAP_SCCP_EV_RAN_LINK_LOST)
| S(MAP_SCCP_EV_RX_CONNECTION_CONFIRM)
+ | S(MAP_SCCP_EV_USER_ABORT)
,
.out_state_mask = 0
| S(MAP_SCCP_ST_DISCONNECTED)
@@ -573,6 +589,7 @@
| S(MAP_SCCP_EV_TX_DATA_REQUEST)
| S(MAP_SCCP_EV_RAN_DISC)
| S(MAP_SCCP_EV_RAN_LINK_LOST)
+ | S(MAP_SCCP_EV_USER_ABORT)
,
.onenter = map_sccp_disconnected_onenter,
.action = map_sccp_disconnected_action,
--
To view, visit https://gerrit.osmocom.org/c/osmo-hnbgw/+/33128
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-hnbgw
Gerrit-Branch: master
Gerrit-Change-Id: Idff8e09b5328c904b175e4d4df7d4044a34f4a20
Gerrit-Change-Number: 33128
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: newchange