gerrit-log
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
March 2025
- 1 participants
- 1378 discussions
[XS] Change in pysim[master]: .gitignore: smdpp-data/sm-dp-sessions from running osmo-smdpp.py
by neels 06 Mar '25
by neels 06 Mar '25
06 Mar '25
neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/39728?usp=email )
Change subject: .gitignore: smdpp-data/sm-dp-sessions from running osmo-smdpp.py
......................................................................
.gitignore: smdpp-data/sm-dp-sessions from running osmo-smdpp.py
Change-Id: I02a4ad4bc8e612e64111b16bc11c8c3d4dd41c45
---
M .gitignore
1 file changed, 1 insertion(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/28/39728/1
diff --git a/.gitignore b/.gitignore
index 610d725..e9fa1d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,5 +7,6 @@
/.local
/build
/pySim.egg-info
+/smdpp-data/sm-dp-sessions
dist
tags
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/39728?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I02a4ad4bc8e612e64111b16bc11c8c3d4dd41c45
Gerrit-Change-Number: 39728
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
1
0
[M] Change in libosmo-sigtran[master]: ASP loadsharing: Pass ownership of Rx xua_msg up the stack [2/2]
by pespin 06 Mar '25
by pespin 06 Mar '25
06 Mar '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/39397?usp=email )
(
11 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: ASP loadsharing: Pass ownership of Rx xua_msg up the stack [2/2]
......................................................................
ASP loadsharing: Pass ownership of Rx xua_msg up the stack [2/2]
This is the second step patch where we also pass ownership on Rx path so
that forwarded xua_msgs can be passed back to the Tx path without
freeing them.
For SUA there's no change needed and we keep freeing the rx xua_msg
right at the end of sua_rx_msg() since there's no actual path forwarding
a xua_msg object back into Tx path, it always goes through upper layers
using newly allocated primitives.
Related: SYS#7112
Change-Id: Icf3b4dda550637f722a9fe56d0313f49c8a2964e
---
M src/ipa.c
M src/m3ua.c
M src/xua_rkm.c
3 files changed, 58 insertions(+), 34 deletions(-)
Approvals:
laforge: Looks good to me, but someone else must approve
osmith: Looks good to me, but someone else must approve
pespin: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/src/ipa.c b/src/ipa.c
index 47ddc0d..bbe94d1 100644
--- a/src/ipa.c
+++ b/src/ipa.c
@@ -302,9 +302,9 @@
/* Update xua->mtp with values from data_hdr */
m3ua_dh_to_xfer_param(&xua->mtp, &data_hdr);
- /* Pass on as if we had received it from an M3UA ASP */
+ /* Pass on as if we had received it from an M3UA ASP.
+ * xua ownership is passed here: */
rc = m3ua_hmdc_rx_from_l2(asp->inst, xua);
- xua_msg_free(xua);
return rc;
}
diff --git a/src/m3ua.c b/src/m3ua.c
index cdbfc48..8232d7b 100644
--- a/src/m3ua.c
+++ b/src/m3ua.c
@@ -579,6 +579,7 @@
return data_hdr;
}
+/* This function takes ownership of xua msg passed to it. */
static int m3ua_rx_xfer(struct osmo_ss7_asp *asp, struct xua_msg *xua)
{
struct xua_msg_part *na_ie = xua_msg_find_tag(xua, M3UA_IEI_NET_APPEAR);
@@ -594,7 +595,8 @@
"%s(): unsupported message type: %s\n",
__func__,
get_value_string(m3ua_xfer_msgt_names, xua->hdr.msg_type));
- return M3UA_ERR_UNSUPP_MSG_TYPE;
+ rc = M3UA_ERR_UNSUPP_MSG_TYPE;
+ goto ret_free;
}
/* Reject unsupported Network Appearance IE. */
@@ -605,13 +607,15 @@
"Unsupported 'Network Appearance' IE '0x%08x' in message type '%s', sending 'Error'.\n",
na, get_value_string(m3ua_xfer_msgt_names, xua->hdr.msg_type));
if (na_ie->len != 4)
- return M3UA_ERR_PARAM_FIELD_ERR;
- return M3UA_ERR_INVAL_NET_APPEAR;
+ rc = M3UA_ERR_PARAM_FIELD_ERR;
+ else
+ rc = M3UA_ERR_INVAL_NET_APPEAR;
+ goto ret_free;
}
rc = xua_find_as_for_asp(&as, asp, rctx_ie);
if (rc)
- return rc;
+ goto ret_free;
rate_ctr_inc2(as->ctrg, SS7_AS_CTR_RX_MSU_TOTAL);
@@ -635,8 +639,12 @@
xua_msg_free_tag(xua, M3UA_IEI_ROUTE_CTX);
}
+ /* xua ownership is passed here: */
return m3ua_hmdc_rx_from_l2(asp->inst, xua);
- /* xua will be freed by caller m3ua_rx_msg() */
+
+ret_free:
+ xua_msg_free(xua);
+ return rc;
}
static int m3ua_rx_mgmt_err(struct osmo_ss7_asp *asp, struct xua_msg *xua)
@@ -683,16 +691,24 @@
return 0;
}
+/* This function takes ownership of xua msg passed to it. */
static int m3ua_rx_mgmt(struct osmo_ss7_asp *asp, struct xua_msg *xua)
{
+ int rc;
+
switch (xua->hdr.msg_type) {
case M3UA_MGMT_ERR:
- return m3ua_rx_mgmt_err(asp, xua);
+ rc = m3ua_rx_mgmt_err(asp, xua);
+ break;
case M3UA_MGMT_NTFY:
- return m3ua_rx_mgmt_ntfy(asp, xua);
+ rc = m3ua_rx_mgmt_ntfy(asp, xua);
+ break;
default:
- return M3UA_ERR_UNSUPP_MSG_TYPE;
+ rc = M3UA_ERR_UNSUPP_MSG_TYPE;
}
+
+ xua_msg_free(xua);
+ return rc;
}
/* map from M3UA ASPSM/ASPTM to xua_asp_fsm event */
@@ -709,23 +725,26 @@
{ M3UA_MSGC_ASPTM, M3UA_ASPTM_INACTIVE_ACK, XUA_ASP_E_ASPTM_ASPIA_ACK },
};
-
+/* This function takes ownership of xua msg passed to it. */
static int m3ua_rx_asp(struct osmo_ss7_asp *asp, struct xua_msg *xua)
{
int event;
+ int rc = 0;
/* map from the M3UA message class and message type to the XUA
* ASP FSM event number */
event = xua_msg_event_map(xua, m3ua_aspxm_map,
ARRAY_SIZE(m3ua_aspxm_map));
- if (event < 0)
- return M3UA_ERR_UNSUPP_MSG_TYPE;
+ if (event < 0) {
+ rc = M3UA_ERR_UNSUPP_MSG_TYPE;
+ goto ret_free;
+ }
/* deliver that event to the ASP FSM */
- if (osmo_fsm_inst_dispatch(asp->fi, event, xua) < 0)
- return M3UA_ERR_UNEXPECTED_MSG;
-
- return 0;
+ rc = osmo_fsm_inst_dispatch(asp->fi, event, xua);
+ret_free:
+ xua_msg_free(xua);
+ return rc;
}
static int m3ua_rx_snm(struct osmo_ss7_asp *asp, struct xua_msg *xua);
@@ -753,9 +772,9 @@
"M3UA message\n");
if (hdr->version != M3UA_VERSION)
- err = m3ua_gen_error_msg(M3UA_ERR_INVALID_VERSION, msg);
+ rc = M3UA_ERR_INVALID_VERSION;
else
- err = m3ua_gen_error_msg(M3UA_ERR_PARAM_FIELD_ERR, msg);
+ rc = M3UA_ERR_PARAM_FIELD_ERR;
goto out;
}
@@ -763,7 +782,8 @@
xua_hdr_dump(xua, &xua_dialect_m3ua));
if (!xua_dialect_check_all_mand_ies(&xua_dialect_m3ua, xua)) {
- err = m3ua_gen_error_msg(M3UA_ERR_MISSING_PARAM, msg);
+ rc = M3UA_ERR_MISSING_PARAM;
+ xua_msg_free(xua);
goto out;
}
@@ -775,7 +795,8 @@
/* The DATA message MUST NOT be sent on stream 0. */
if (msgb_sctp_stream(msg) == 0) {
rc = M3UA_ERR_INVAL_STREAM_ID;
- break;
+ xua_msg_free(xua);
+ goto out;
}
rc = m3ua_rx_xfer(asp, xua);
break;
@@ -795,19 +816,16 @@
default:
LOGPASP(asp, DLM3UA, LOGL_NOTICE, "Received unknown M3UA "
"Message Class %u\n", xua->hdr.msg_class);
- err = m3ua_gen_error_msg(M3UA_ERR_UNSUPP_MSG_CLASS, msg);
- break;
+ rc = M3UA_ERR_UNSUPP_MSG_CLASS;
+ xua_msg_free(xua);
+ goto out;
}
+out:
if (rc > 0)
err = m3ua_gen_error_msg(rc, msg);
-
-out:
if (err)
m3ua_tx_xua_asp(asp, err);
-
- xua_msg_free(xua);
-
return rc;
}
@@ -957,7 +975,8 @@
m3ua_tx_xua_asp(asp, xua);
}
-/* received SNM message on ASP side */
+/* received SNM message on ASP side
+ * This function takes ownership of xua msg passed to it. */
static int m3ua_rx_snm_asp(struct osmo_ss7_asp *asp, struct xua_msg *xua)
{
struct osmo_ss7_as *as = NULL;
@@ -966,7 +985,7 @@
rc = xua_find_as_for_asp(&as, asp, rctx_ie);
if (rc)
- return rc;
+ goto ret_free;
/* report those up the stack so both other ASPs and local SCCP users can be notified */
switch (xua->hdr.msg_type) {
@@ -996,14 +1015,16 @@
xua_snm_rx_daud(asp, xua);
} else {
LOGPASP(asp, DLM3UA, LOGL_ERROR, "DAUD not permitted in ASP role\n");
- return M3UA_ERR_UNSUPP_MSG_TYPE;
+ rc = M3UA_ERR_UNSUPP_MSG_TYPE;
}
break;
default:
- return M3UA_ERR_UNSUPP_MSG_TYPE;
+ rc = M3UA_ERR_UNSUPP_MSG_TYPE;
}
- return 0;
+ret_free:
+ xua_msg_free(xua);
+ return rc;
}
/* received SNM message on SG side */
diff --git a/src/xua_rkm.c b/src/xua_rkm.c
index 8fa8c3b..1ae5ea6 100644
--- a/src/xua_rkm.c
+++ b/src/xua_rkm.c
@@ -548,7 +548,8 @@
return 0;
}
-/* process an incoming RKM message in xua format */
+/* process an incoming RKM message in xua format
+ * This function takes ownership of xua msg passed to it. */
int m3ua_rx_rkm(struct osmo_ss7_asp *asp, struct xua_msg *xua)
{
int rc;
@@ -578,6 +579,8 @@
rc = -1;
break;
}
+
+ xua_msg_free(xua);
return rc;
}
--
To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/39397?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: Icf3b4dda550637f722a9fe56d0313f49c8a2964e
Gerrit-Change-Number: 39397
Gerrit-PatchSet: 12
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
[M] Change in libosmo-sigtran[master]: ASP loadsharing: Pass xua_msg down to xua_as_transmit_msg
by pespin 06 Mar '25
by pespin 06 Mar '25
06 Mar '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/39398?usp=email )
(
11 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: ASP loadsharing: Pass xua_msg down to xua_as_transmit_msg
......................................................................
ASP loadsharing: Pass xua_msg down to xua_as_transmit_msg
This finally allows having access to msg values such as OPC and SLS at
the point in code where decision is taken to route the message to one
ASP inside the AS.
This will be needed to properly implemented ASP loadsharing within an
AS.
Related: SYS#7112
Change-Id: I70e5d33c7537dc0b72b5abced876e69018cc0829
---
M src/ipa.c
M src/m3ua.c
M src/sua.c
M src/xua_as_fsm.c
M src/xua_as_fsm.h
M src/xua_internal.h
M src/xua_msg.h
7 files changed, 60 insertions(+), 51 deletions(-)
Approvals:
Jenkins Builder: Verified
pespin: Looks good to me, approved
osmith: Looks good to me, but someone else must approve
laforge: Looks good to me, but someone else must approve
diff --git a/src/ipa.c b/src/ipa.c
index bbe94d1..c04b476 100644
--- a/src/ipa.c
+++ b/src/ipa.c
@@ -52,7 +52,7 @@
#include "ss7_internal.h"
#include "xua_asp_fsm.h"
-static struct msgb *ipa_to_msg(struct xua_msg *xua)
+struct msgb *ipa_to_msg(struct xua_msg *xua)
{
struct xua_msg_part *data_ie;
struct m3ua_data_hdr *data_hdr;
@@ -100,17 +100,9 @@
*/
int ipa_tx_xua_as(struct osmo_ss7_as *as, struct xua_msg *xua)
{
- struct msgb *msg;
OSMO_ASSERT(as->cfg.proto == OSMO_SS7_ASP_PROT_IPA);
- msg = ipa_to_msg(xua);
- xua_msg_free(xua);
- if (!msg) {
- LOGPAS(as, DLSS7, LOGL_ERROR, "Error encoding IPA Msg\n");
- return -1;
- }
-
- return xua_as_transmit_msg(as, msg);
+ return xua_as_transmit_msg(as, xua);
}
static int ipa_rx_msg_ccm(struct osmo_ss7_asp *asp, struct msgb *msg)
diff --git a/src/m3ua.c b/src/m3ua.c
index 8232d7b..39c799e 100644
--- a/src/m3ua.c
+++ b/src/m3ua.c
@@ -486,7 +486,7 @@
***********************************************************************/
/* Convert M3UA from xua_msg to msgb and set PPID/stream */
-static struct msgb *m3ua_to_msg(struct xua_msg *xua)
+struct msgb *m3ua_to_msg(struct xua_msg *xua)
{
struct msgb *msg = xua_to_msg(M3UA_VERSION, xua);
@@ -533,7 +533,6 @@
*/
int m3ua_tx_xua_as(struct osmo_ss7_as *as, struct xua_msg *xua)
{
- struct msgb *msg;
int rc;
OSMO_ASSERT(as->cfg.proto == OSMO_SS7_ASP_PROT_M3UA);
@@ -542,18 +541,11 @@
if (as->cfg.routing_key.context)
xua_msg_add_u32(xua, M3UA_IEI_ROUTE_CTX, as->cfg.routing_key.context);
- msg = m3ua_to_msg(xua);
- xua_msg_free(xua);
- if (!msg) {
- LOGPAS(as, DLM3UA, LOGL_ERROR, "Error encoding M3UA Msg\n");
- return -1;
- }
-
/* send the msg to the AS for transmission. The AS FSM might
* (depending on its state) enqueue it before transmission */
- rc = osmo_fsm_inst_dispatch(as->fi, XUA_AS_E_TRANSFER_REQ, msg);
+ rc = osmo_fsm_inst_dispatch(as->fi, XUA_AS_E_TRANSFER_REQ, xua);
if (rc < 0)
- msgb_free(msg);
+ xua_msg_free(xua);
return rc;
}
diff --git a/src/sua.c b/src/sua.c
index 4d90f9b..41bea1b 100644
--- a/src/sua.c
+++ b/src/sua.c
@@ -310,7 +310,6 @@
* \return 0 on success; negative on error */
int sua_tx_xua_as(struct osmo_ss7_as *as, struct xua_msg *xua)
{
- struct msgb *msg;
int rc;
OSMO_ASSERT(as->cfg.proto == OSMO_SS7_ASP_PROT_SUA);
@@ -319,18 +318,11 @@
if (as->cfg.routing_key.context)
xua_msg_add_u32(xua, SUA_IEI_ROUTE_CTX, as->cfg.routing_key.context);
- msg = sua_to_msg(xua);
- xua_msg_free(xua);
- if (!msg) {
- LOGPAS(as, DLSUA, LOGL_ERROR, "Error encoding SUA Msg\n");
- return -1;
- }
-
/* send the msg to the AS for transmission. The AS FSM might
* (depending on its state) enqueue it before transmission */
- rc = osmo_fsm_inst_dispatch(as->fi, XUA_AS_E_TRANSFER_REQ, msg);
+ rc = osmo_fsm_inst_dispatch(as->fi, XUA_AS_E_TRANSFER_REQ, xua);
if (rc < 0)
- msgb_free(msg);
+ xua_msg_free(xua);
return rc;
}
diff --git a/src/xua_as_fsm.c b/src/xua_as_fsm.c
index c4a167c..d0bc019 100644
--- a/src/xua_as_fsm.c
+++ b/src/xua_as_fsm.c
@@ -121,13 +121,29 @@
return -1;
}
-int xua_as_transmit_msg_broadcast(struct osmo_ss7_as *as, struct msgb *msg)
+static struct msgb *xua_as_encode_msg(const struct osmo_ss7_as *as, struct xua_msg *xua)
+{
+ switch (as->cfg.proto) {
+ case OSMO_SS7_ASP_PROT_M3UA:
+ return m3ua_to_msg(xua);
+ case OSMO_SS7_ASP_PROT_IPA:
+ return ipa_to_msg(xua);
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+int xua_as_transmit_msg_broadcast(struct osmo_ss7_as *as, struct xua_msg *xua)
{
struct osmo_ss7_asp *asp;
unsigned int i;
+ struct msgb *msg;
struct msgb *msg_cpy;
bool sent = false;
+ msg = xua_as_encode_msg(as, xua);
+ OSMO_ASSERT(msg);
+
for (i = 0; i < ARRAY_SIZE(as->cfg.asps); i++) {
asp = as->cfg.asps[i];
if (!asp || !osmo_ss7_asp_active(asp))
@@ -138,35 +154,41 @@
}
msgb_free(msg);
+ xua_msg_free(xua);
return sent ? 0 : -1;
}
/* actually transmit a message through this AS */
-int xua_as_transmit_msg(struct osmo_ss7_as *as, struct msgb *msg)
+int xua_as_transmit_msg(struct osmo_ss7_as *as, struct xua_msg *xua)
{
struct osmo_ss7_asp *asp = NULL;
+ struct msgb *msg;
switch (as->cfg.mode) {
case OSMO_SS7_AS_TMOD_OVERRIDE:
case OSMO_SS7_AS_TMOD_LOADSHARE:
/* TODO: OSMO_SS7_AS_TMOD_LOADSHARE: actually use the SLS value
- * to ensure same SLS goes through same ASP. Not strictly
- * required by M3UA RFC, but would fit the overall principle. */
+ * in xua->mtp.sls to ensure same SLS goes through same ASP. Not
+ * strictly required by M3UA RFC, but would fit the overall
+ * principle. */
case OSMO_SS7_AS_TMOD_ROUNDROBIN:
asp = osmo_ss7_as_select_asp(as);
break;
case OSMO_SS7_AS_TMOD_BCAST:
- return xua_as_transmit_msg_broadcast(as, msg);
+ return xua_as_transmit_msg_broadcast(as, xua);
case _NUM_OSMO_SS7_ASP_TMOD:
OSMO_ASSERT(false);
}
if (!asp) {
LOGPFSM(as->fi, "No ASP in AS, dropping message\n");
- msgb_free(msg);
+ xua_msg_free(xua);
return -1;
}
+ msg = xua_as_encode_msg(as, xua);
+ OSMO_ASSERT(msg);
+ xua_msg_free(xua);
return osmo_ss7_asp_send(asp, msg);
}
@@ -192,7 +214,7 @@
struct osmo_ss7_as *as;
struct {
struct osmo_timer_list t_r;
- struct llist_head queued_msgs;
+ struct llist_head queued_xua_msgs;
} recovery;
bool ipa_route_created;
};
@@ -481,7 +503,7 @@
struct xua_as_fsm_priv *xafp = (struct xua_as_fsm_priv *) fi->priv;
struct osmo_ss7_asp *asp;
struct xua_as_event_asp_inactive_ind_pars *inact_ind_pars;
- struct msgb *msg;
+ struct xua_msg *xua;
struct osmo_xlm_prim_notify npar;
switch (event) {
@@ -510,8 +532,8 @@
break;
case XUA_AS_E_TRANSFER_REQ:
/* message for transmission */
- msg = data;
- xua_as_transmit_msg(xafp->as, msg);
+ xua = data;
+ xua_as_transmit_msg(xafp->as, xua);
break;
}
}
@@ -520,7 +542,7 @@
{
struct xua_as_fsm_priv *xafp = (struct xua_as_fsm_priv *) fi->priv;
struct xua_as_event_asp_inactive_ind_pars *inact_ind_pars;
- struct msgb *msg;
+ struct xua_msg *xua;
struct osmo_xlm_prim_notify npar;
switch (event) {
@@ -529,8 +551,12 @@
osmo_timer_del(&xafp->recovery.t_r);
osmo_fsm_inst_state_chg(fi, XUA_AS_S_ACTIVE, 0, 0);
/* push out any pending queued messages */
- while ((msg = msgb_dequeue(&xafp->recovery.queued_msgs)))
- xua_as_transmit_msg(xafp->as, msg);
+ while (!llist_empty(&xafp->recovery.queued_xua_msgs)) {
+ struct xua_msg *xua;
+ xua = llist_first_entry(&xafp->recovery.queued_xua_msgs, struct xua_msg, entry);
+ llist_del(&xua->entry);
+ xua_as_transmit_msg(xafp->as, xua);
+ }
break;
case XUA_ASPAS_ASP_INACTIVE_IND:
inact_ind_pars = data;
@@ -544,8 +570,12 @@
break;
case XUA_AS_E_RECOVERY_EXPD:
LOGPFSM(fi, "T(r) expired; dropping queued messages\n");
- while ((msg = msgb_dequeue(&xafp->recovery.queued_msgs)))
- talloc_free(msg);
+ while (!llist_empty(&xafp->recovery.queued_xua_msgs)) {
+ struct xua_msg *xua;
+ xua = llist_first_entry(&xafp->recovery.queued_xua_msgs, struct xua_msg, entry);
+ llist_del(&xua->entry);
+ xua_msg_free(xua);
+ }
if (check_any_other_asp_not_down(xafp->as, NULL))
osmo_fsm_inst_state_chg(fi, XUA_AS_S_INACTIVE, 0, 0);
else
@@ -553,8 +583,8 @@
break;
case XUA_AS_E_TRANSFER_REQ:
/* enqueue the to-be-transferred message */
- msg = data;
- msgb_enqueue(&xafp->recovery.queued_msgs, msg);
+ xua = data;
+ llist_add_tail(&xua->entry, &xafp->recovery.queued_xua_msgs);
break;
}
}
@@ -642,7 +672,7 @@
xafp->as = as;
xafp->recovery.t_r.cb = t_r_callback;
xafp->recovery.t_r.data = fi;
- INIT_LLIST_HEAD(&xafp->recovery.queued_msgs);
+ INIT_LLIST_HEAD(&xafp->recovery.queued_xua_msgs);
fi->priv = xafp;
diff --git a/src/xua_as_fsm.h b/src/xua_as_fsm.h
index cf897e2..08f626b 100644
--- a/src/xua_as_fsm.h
+++ b/src/xua_as_fsm.h
@@ -24,7 +24,7 @@
XUA_ASPAS_ASP_DOWN_IND,
XUA_ASPAS_ASP_ACTIVE_IND,
XUA_AS_E_RECOVERY_EXPD,
- XUA_AS_E_TRANSFER_REQ,
+ XUA_AS_E_TRANSFER_REQ, /* param: struct xua_msg*, ownership transferred. */
};
extern struct osmo_fsm xua_as_fsm;
diff --git a/src/xua_internal.h b/src/xua_internal.h
index 3e9c15b..4d99231 100644
--- a/src/xua_internal.h
+++ b/src/xua_internal.h
@@ -33,6 +33,7 @@
struct osmo_mtp_prim *m3ua_to_xfer_ind(struct xua_msg *xua);
int m3ua_hmdc_rx_from_l2(struct osmo_ss7_instance *inst, struct xua_msg *xua);
+struct msgb *m3ua_to_msg(struct xua_msg *xua);
int m3ua_tx_xua_as(struct osmo_ss7_as *as, struct xua_msg *xua);
void m3ua_tx_snm_available(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
const uint32_t *aff_pc, unsigned int num_aff_pc,
@@ -114,11 +115,12 @@
#define PC_STR "Point Code\n"
#define INST_STR "An instance of the SS7 stack\n"
-int xua_as_transmit_msg(struct osmo_ss7_as *as, struct msgb *msg);
+int xua_as_transmit_msg(struct osmo_ss7_as *as, struct xua_msg *xua);
int xua_find_as_for_asp(struct osmo_ss7_as **as, const struct osmo_ss7_asp *asp,
const struct xua_msg_part *rctx_ie);
+struct msgb *ipa_to_msg(struct xua_msg *xua);
int ipa_tx_xua_as(struct osmo_ss7_as *as, struct xua_msg *xua);
int ipa_rx_msg(struct osmo_ss7_asp *asp, struct msgb *msg, uint8_t sls);
struct osmo_ss7_as *ipa_find_as_for_asp(struct osmo_ss7_asp *asp);
diff --git a/src/xua_msg.h b/src/xua_msg.h
index 5f877ed..79af86f 100644
--- a/src/xua_msg.h
+++ b/src/xua_msg.h
@@ -29,6 +29,7 @@
struct osmo_sccp_gt;
struct xua_msg {
+ struct llist_head entry; /* Allows queueing a xua_msg into a llist */
struct xua_common_hdr hdr;
struct osmo_mtp_transfer_param mtp;
--
To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/39398?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I70e5d33c7537dc0b72b5abced876e69018cc0829
Gerrit-Change-Number: 39398
Gerrit-PatchSet: 12
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
[L] Change in libosmo-sigtran[master]: ASP loadsharing: Implement based on VTY configuration
by pespin 06 Mar '25
by pespin 06 Mar '25
06 Mar '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/39408?usp=email )
(
10 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: ASP loadsharing: Implement based on VTY configuration
......................................................................
ASP loadsharing: Implement based on VTY configuration
Calculate AS Extended SLS (7 bit) out of OPC (12 bits) and SLS (4 bits)
based on VTY configuration.
Assign a normal destination ASP for each AS-eSLS and try to use it
whenever possible; fallback to an alternative ASP when normal ASP is not
available.
Related: SYS#7112
Change-Id: I5f47e40b70ed566034cd1533b71e21fc03e94f6c
---
M src/osmo_ss7_as.c
M src/osmo_ss7_vty.c
M src/ss7_as.h
M src/xua_as_fsm.c
M tests/vty/osmo_stp_test.vty
5 files changed, 247 insertions(+), 11 deletions(-)
Approvals:
laforge: Looks good to me, but someone else must approve
pespin: Looks good to me, approved
osmith: Looks good to me, but someone else must approve
Jenkins Builder: Verified
diff --git a/src/osmo_ss7_as.c b/src/osmo_ss7_as.c
index ab40080..35a2650 100644
--- a/src/osmo_ss7_as.c
+++ b/src/osmo_ss7_as.c
@@ -33,6 +33,7 @@
#include <osmocom/sigtran/osmo_ss7.h>
#include <osmocom/sigtran/protocol/m3ua.h>
+#include <osmocom/sigtran/mtp_sap.h>
#include "ss7_as.h"
#include "ss7_asp.h"
@@ -198,6 +199,14 @@
LOGPAS(as, DLSS7, LOGL_INFO, "Removing ASP %s from AS\n", asp->cfg.name);
+ /* Remove route from AS-eSLS table: */
+ for (unsigned int i = 0; i < ARRAY_SIZE(as->aesls_table); i++) {
+ if (as->aesls_table[i].normal_asp == asp)
+ as->aesls_table[i].normal_asp = NULL;
+ if (as->aesls_table[i].alt_asp == asp)
+ as->aesls_table[i].alt_asp = NULL;
+ }
+
for (i = 0; i < ARRAY_SIZE(as->cfg.asps); i++) {
if (as->cfg.asps[i] == asp) {
as->cfg.asps[i] = NULL;
@@ -314,6 +323,106 @@
return asp;
}
+static as_ext_sls_t osmo_ss7_instance_calc_itu_as_ext_sls(const struct osmo_ss7_as *as, uint32_t opc, uint8_t sls)
+{
+ uint16_t opc12;
+ uint8_t opc3;
+ as_ext_sls_t as_ext_sls;
+
+ if (as->cfg.loadshare.opc_sls) {
+ /* Take 12 bits from OPC according to config: */
+ opc12 = (uint16_t)((opc >> as->cfg.loadshare.opc_shift) & 0x3fff);
+
+ /* Derivate 3-bit value from 12-bit value: */
+ opc3 = ((opc12 >> 9) & 0x07) ^
+ ((opc12 >> 6) & 0x07) ^
+ ((opc12 >> 3) & 0x07) ^
+ (opc12 & 0x07);
+ opc3 &= 0x07;
+
+ /* Generate 7 bit AS-extended-SLS: 3-bit OPC + 4 bit SLS: */
+ as_ext_sls = (opc3 << 4) | ((sls) & 0x0f);
+ OSMO_ASSERT(as_ext_sls < NUM_AS_EXT_SLS);
+ } else {
+ as_ext_sls = sls;
+ }
+
+ /* Pick extended-SLS bits according to config: */
+ as_ext_sls = as_ext_sls >> as->cfg.loadshare.sls_shift;
+ return as_ext_sls;
+}
+
+/* ITU Q.704 4.2.1: "current signalling link". Pick available already selected ASP */
+static struct osmo_ss7_asp *current_asp(const struct osmo_ss7_as *as, const struct osmo_ss7_as_esls_entry *aeslse)
+{
+ if (aeslse->normal_asp && osmo_ss7_asp_active(aeslse->normal_asp))
+ return aeslse->normal_asp;
+ if (aeslse->alt_asp && osmo_ss7_asp_active(aeslse->alt_asp))
+ return aeslse->alt_asp;
+ return NULL;
+}
+
+static struct osmo_ss7_asp *ss7_as_select_asp_loadshare(struct osmo_ss7_as *as, const struct osmo_mtp_transfer_param *mtp)
+{
+ as_ext_sls_t as_ext_sls;
+ struct osmo_ss7_asp *asp;
+
+ as_ext_sls = osmo_ss7_instance_calc_itu_as_ext_sls(as, mtp->opc, mtp->sls);
+ struct osmo_ss7_as_esls_entry *aeslse = &as->aesls_table[as_ext_sls];
+
+ /* First check if we have a cached route for this ESLS */
+ asp = current_asp(as, aeslse);
+ if (asp) {
+ if (asp == aeslse->normal_asp) {
+ /* We can transmit over normal ASP.
+ * Clean up alternative ASP since it's not needed anymore */
+ if (aeslse->alt_asp) {
+ LOGPAS(as, DLSS7, LOGL_NOTICE, "Tx Loadshare: OPC=%u=%s,SLS=%u -> eSLS=%u: "
+ "Normal ASP '%s' became available, drop use of Alternative ASP '%s'\n",
+ mtp->opc, osmo_ss7_pointcode_print(as->inst, mtp->opc),
+ mtp->sls, as_ext_sls, asp->cfg.name, aeslse->alt_asp->cfg.name);
+ aeslse->alt_asp = NULL;
+ }
+ LOGPAS(as, DLSS7, LOGL_DEBUG, "Tx Loadshare: OPC=%u=%s,SLS=%u -> eSLS=%u: use Normal ASP '%s'\n",
+ mtp->opc, osmo_ss7_pointcode_print(as->inst, mtp->opc),
+ mtp->sls, as_ext_sls, asp->cfg.name);
+ return asp;
+ }
+ /* We can transmit over alternative ASP: */
+ LOGPAS(as, DLSS7, LOGL_INFO, "Tx Loadshare: OPC=%u=%s,SLS=%u -> eSLS=%u: use Alternative ASP '%s'\n",
+ mtp->opc, osmo_ss7_pointcode_print(as->inst, mtp->opc),
+ mtp->sls, as_ext_sls, asp->cfg.name);
+ return asp;
+ }
+
+ /* No current ASP available, try to find a new current ASP: */
+
+ /* No normal route selected yet: */
+ if (!aeslse->normal_asp) {
+ asp = ss7_as_select_asp_roundrobin(as);
+ /* Either a normal route was selected or none found: */
+ aeslse->normal_asp = asp;
+ if (asp)
+ LOGPAS(as, DLSS7, LOGL_DEBUG, "Tx Loadshare: OPC=%u=%s,SLS=%u -> eSLS=%u: "
+ "picked Normal ASP '%s' round-robin style\n",
+ mtp->opc, osmo_ss7_pointcode_print(as->inst, mtp->opc),
+ mtp->sls, as_ext_sls, asp->cfg.name);
+ return asp;
+ }
+
+ /* Normal ASP unavailable and no alternative ASP (or unavailable too).
+ * start ITU Q.704 section 7 "forced rerouting" procedure: */
+ asp = ss7_as_select_asp_roundrobin(as);
+ if (asp) {
+ aeslse->alt_asp = asp;
+ LOGPAS(as, DLSS7, LOGL_NOTICE, "Tx Loadshare: OPC=%u=%s,SLS=%u -> eSLS=%u: "
+ "Normal ASP '%s' unavailable, picked Alternative ASP '%s' round-robin style\n",
+ mtp->opc, osmo_ss7_pointcode_print(as->inst, mtp->opc),
+ mtp->sls, as_ext_sls, aeslse->normal_asp->cfg.name, asp->cfg.name);
+ }
+ return asp;
+}
+
/* returns NULL if multiple ASPs would need to be selected. */
static struct osmo_ss7_asp *ss7_as_select_asp_broadcast(struct osmo_ss7_as *as)
{
@@ -338,7 +447,7 @@
* This function returns NULL too if multiple ASPs would be selected, ie. AS is
* configured in broadcast mode and more than one ASP is configured.
*/
-struct osmo_ss7_asp *osmo_ss7_as_select_asp(struct osmo_ss7_as *as)
+struct osmo_ss7_asp *ss7_as_select_asp(struct osmo_ss7_as *as, const struct osmo_mtp_transfer_param *mtp)
{
struct osmo_ss7_asp *asp = NULL;
@@ -347,9 +456,46 @@
asp = ss7_as_select_asp_override(as);
break;
case OSMO_SS7_AS_TMOD_LOADSHARE:
- /* TODO: actually use the SLS value to ensure same SLS goes
- * through same ASP. Not strictly required by M3UA RFC, but
- * would fit the overall principle. */
+ asp = ss7_as_select_asp_loadshare(as, mtp);
+ break;
+ case OSMO_SS7_AS_TMOD_ROUNDROBIN:
+ asp = ss7_as_select_asp_roundrobin(as);
+ break;
+ case OSMO_SS7_AS_TMOD_BCAST:
+ return ss7_as_select_asp_broadcast(as);
+ case _NUM_OSMO_SS7_ASP_TMOD:
+ OSMO_ASSERT(false);
+ }
+
+ if (!asp) {
+ LOGPFSM(as->fi, "No selectable ASP in AS\n");
+ return NULL;
+ }
+ return asp;
+}
+/*! Select an AS to transmit a message, according to AS configuration and ASP availability.
+ * \param[in] as Application Server.
+ * \returns asp to send the message to, NULL if no possible asp found
+ *
+ * This function returns NULL too if multiple ASPs would be selected, ie. AS is
+ * configured in broadcast mode and more than one ASP is configured.
+ */
+struct osmo_ss7_asp *osmo_ss7_as_select_asp(struct osmo_ss7_as *as)
+{
+ struct osmo_ss7_asp *asp = NULL;
+ struct osmo_mtp_transfer_param mtp;
+
+ switch (as->cfg.mode) {
+ case OSMO_SS7_AS_TMOD_OVERRIDE:
+ asp = ss7_as_select_asp_override(as);
+ break;
+ case OSMO_SS7_AS_TMOD_LOADSHARE:
+ /* We don't have OPC and SLS information in this API (which is
+ actually only used to route IPA msgs nowadays by osmo-bsc, so we
+ don't care. Use hardcoded value to provide some fallback for this scenario: */
+ mtp = (struct osmo_mtp_transfer_param){0};
+ asp = ss7_as_select_asp_loadshare(as, &mtp);
+ break;
case OSMO_SS7_AS_TMOD_ROUNDROBIN:
asp = ss7_as_select_asp_roundrobin(as);
break;
diff --git a/src/osmo_ss7_vty.c b/src/osmo_ss7_vty.c
index 81ce0ce..83890b8 100644
--- a/src/osmo_ss7_vty.c
+++ b/src/osmo_ss7_vty.c
@@ -2033,10 +2033,9 @@
DEFUN_USRATTR(as_traf_mode, as_traf_mode_cmd,
OSMO_SCCP_LIB_ATTR_RSTRT_ASP,
- "traffic-mode (broadcast | loadshare | roundrobin | override)",
+ "traffic-mode (broadcast | roundrobin | override)",
"Specifies traffic mode of operation of the ASP within the AS\n"
"Broadcast to all ASP within AS\n"
- "Share Load among all ASP within AS\n"
"Round-Robin between all ASP within AS\n"
"Override\n")
{
@@ -2047,6 +2046,36 @@
return CMD_SUCCESS;
}
+DEFUN_USRATTR(as_traf_mode_loadshare, as_traf_mode_loadshare_cmd,
+ OSMO_SCCP_LIB_ATTR_RSTRT_ASP,
+ "traffic-mode loadshare [bindings] [sls] [opc-sls] [opc-shift] [<0-2>]",
+ "Specifies traffic mode of operation of the ASP within the AS\n"
+ "Share Load among all ASP within AS\n"
+ "Configure Loadshare parameters\n"
+ "Configure Loadshare SLS generation parameters\n"
+ "Generate extended SLS with OPC information\n"
+ "Shift OPC bits used during routing decision\n"
+ "How many bits from ITU OPC field (starting from least-significant-bit) to skip (default=0). 6 bits are always used\n"
+ )
+{
+ struct osmo_ss7_as *as = vty->index;
+
+ as->cfg.mode = OSMO_SS7_AS_TMOD_LOADSHARE;
+ as->cfg.mode_set_by_vty = true;
+ if (argc < 3) {
+ as->cfg.loadshare.opc_sls = false;
+ as->cfg.loadshare.opc_shift = 0;
+ return CMD_SUCCESS;
+ }
+ as->cfg.loadshare.opc_sls = true;
+ if (argc < 5) {
+ as->cfg.loadshare.opc_shift = 0;
+ return CMD_SUCCESS;
+ }
+ as->cfg.loadshare.opc_shift = atoi(argv[4]);
+ return CMD_SUCCESS;
+}
+
DEFUN_USRATTR(as_no_traf_mode, as_no_traf_mode_cmd,
OSMO_SCCP_LIB_ATTR_RSTRT_ASP,
"no traffic-mode",
@@ -2056,6 +2085,22 @@
as->cfg.mode = 0;
as->cfg.mode_set_by_vty = false;
+
+ as->cfg.loadshare.sls_shift = 0;
+ as->cfg.loadshare.opc_sls = false;
+ as->cfg.loadshare.opc_shift = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(as_sls_shift, as_sls_shift_cmd,
+ "sls-shift <0-3>",
+ "Shift SLS bits used during routing decision\n"
+ "How many bits from SLS field (starting from least-significant-bit) to skip\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_as *as = vty->index;
+ as->cfg.loadshare.sls_shift = atoi(argv[0]);
+
return CMD_SUCCESS;
}
@@ -2274,9 +2319,21 @@
continue;
vty_out(vty, " asp %s%s", asp->cfg.name, VTY_NEWLINE);
}
- if (as->cfg.mode_set_by_vty)
- vty_out(vty, " traffic-mode %s%s",
- osmo_ss7_as_traffic_mode_name(as->cfg.mode), VTY_NEWLINE);
+ if (as->cfg.mode_set_by_vty) {
+ vty_out(vty, " traffic-mode %s%s", osmo_ss7_as_traffic_mode_name(as->cfg.mode), VTY_NEWLINE);
+ if (as->cfg.mode == OSMO_SS7_AS_TMOD_LOADSHARE) {
+ if (as->cfg.loadshare.opc_sls) {
+ vty_out(vty, " bindings sls opc-sls");
+ if (as->cfg.loadshare.opc_shift != 0)
+ vty_out(vty, " opc-shift %u", as->cfg.loadshare.opc_shift);
+ }
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+
+ if (as->cfg.loadshare.sls_shift != 0)
+ vty_out(vty, " sls-shift %u%s", as->cfg.loadshare.sls_shift, VTY_NEWLINE);
+ }
+
if (as->cfg.recovery_timeout_msec != 2000) {
vty_out(vty, " recovery-timeout %u%s",
as->cfg.recovery_timeout_msec, VTY_NEWLINE);
@@ -3218,7 +3275,9 @@
install_lib_element(L_CS7_AS_NODE, &as_asp_cmd);
install_lib_element(L_CS7_AS_NODE, &as_no_asp_cmd);
install_lib_element(L_CS7_AS_NODE, &as_traf_mode_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_traf_mode_loadshare_cmd);
install_lib_element(L_CS7_AS_NODE, &as_no_traf_mode_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_sls_shift_cmd);
install_lib_element(L_CS7_AS_NODE, &as_recov_tout_cmd);
install_lib_element(L_CS7_AS_NODE, &as_qos_class_cmd);
install_lib_element(L_CS7_AS_NODE, &as_rout_key_cmd);
diff --git a/src/ss7_as.h b/src/ss7_as.h
index 6a2b649..c4dfdf6 100644
--- a/src/ss7_as.h
+++ b/src/ss7_as.h
@@ -17,6 +17,7 @@
struct osmo_ss7_instance;
struct osmo_ss7_asp;
+struct osmo_mtp_transfer_param;
enum osmo_ss7_as_patch_sccp_mode {
OSMO_SS7_PATCH_NONE, /* no patching of SCCP */
@@ -60,6 +61,15 @@
SS7_AS_CTR_TX_MSU_SLS_15,
};
+#define NUM_AS_EXT_SLS 128
+typedef uint8_t as_ext_sls_t; /* range: 0-127, 7 bit */
+struct osmo_ss7_as_esls_entry {
+ /* ITU Q.704 4.2.1: "normal signallink link" */
+ struct osmo_ss7_asp *normal_asp;
+ /* ITU Q.704 4.2.1: "alternative signallink link" */
+ struct osmo_ss7_asp *alt_asp;
+};
+
struct osmo_ss7_as {
/*! entry in 'ref osmo_ss7_instance.as_list */
struct llist_head list;
@@ -77,6 +87,9 @@
/*! Rate Counter Group */
struct rate_ctr_group *ctrg;
+ /* ASP loadshare: */
+ struct osmo_ss7_as_esls_entry aesls_table[NUM_AS_EXT_SLS];
+
struct {
char *name;
char *description;
@@ -96,9 +109,24 @@
struct osmo_ss7_asp *asps[16];
uint8_t last_asp_idx_sent; /* used for load-sharing traffic mode (round robin implementation) */
+
+ struct {
+ /* How many bits from ITU SLS field (starting from least-significant-bit)
+ * to skip for routing decisions.
+ * range 0-3, defaults to 0, which means take all 4 bits. */
+ uint8_t sls_shift;
+ /* Whether to generate a extended-SLS with OPC information, see opc_shift below. */
+ bool opc_sls;
+ /* How many bits from ITU OPC field (starting from least-significant-bit)
+ * to skip for routing decisions (always takes 12 bits).
+ * range 0-2, defaults to 0, which means take least significant 12 bits. */
+ uint8_t opc_shift;
+ } loadshare;
} cfg;
};
+struct osmo_ss7_asp *ss7_as_select_asp(struct osmo_ss7_as *as, const struct osmo_mtp_transfer_param *mtp);
+
unsigned int osmo_ss7_as_count_asp(const struct osmo_ss7_as *as);
int ss7_as_add_asp(struct osmo_ss7_as *as, struct osmo_ss7_asp *asp);
diff --git a/src/xua_as_fsm.c b/src/xua_as_fsm.c
index d0bc019..2034659 100644
--- a/src/xua_as_fsm.c
+++ b/src/xua_as_fsm.c
@@ -172,7 +172,7 @@
* strictly required by M3UA RFC, but would fit the overall
* principle. */
case OSMO_SS7_AS_TMOD_ROUNDROBIN:
- asp = osmo_ss7_as_select_asp(as);
+ asp = ss7_as_select_asp(as, &xua->mtp);
break;
case OSMO_SS7_AS_TMOD_BCAST:
return xua_as_transmit_msg_broadcast(as, xua);
diff --git a/tests/vty/osmo_stp_test.vty b/tests/vty/osmo_stp_test.vty
index 200fff8..58a1ee0 100644
--- a/tests/vty/osmo_stp_test.vty
+++ b/tests/vty/osmo_stp_test.vty
@@ -351,8 +351,10 @@
description .TEXT
asp NAME
no asp NAME
- traffic-mode (broadcast | loadshare | roundrobin | override)
+ traffic-mode (broadcast | roundrobin | override)
+ traffic-mode loadshare [bindings] [sls] [opc-sls] [opc-shift] [<0-2>]
no traffic-mode
+ sls-shift <0-3>
recovery-timeout <1-2000>
qos-class <0-7>
routing-key RCONTEXT DPC
@@ -368,6 +370,7 @@
asp Specify that a given ASP is part of this AS
no Negate a command or set its defaults
traffic-mode Specifies traffic mode of operation of the ASP within the AS
+ sls-shift Shift SLS bits used during routing decision
recovery-timeout Specifies the recovery timeout value in milliseconds
qos-class Specity QoS Class of AS
routing-key Define a routing key
--
To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/39408?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I5f47e40b70ed566034cd1533b71e21fc03e94f6c
Gerrit-Change-Number: 39408
Gerrit-PatchSet: 11
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
[S] Change in libosmo-sigtran[master]: sccp: Apply SLS on locally-originated transmitted Connection-Oriented...
by pespin 06 Mar '25
by pespin 06 Mar '25
06 Mar '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/39689?usp=email )
(
1 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: sccp: Apply SLS on locally-originated transmitted Connection-Oriented messages
......................................................................
sccp: Apply SLS on locally-originated transmitted Connection-Oriented messages
Change-Id: I1956acf631867b12b647d14c10057ded20d7fa2f
---
M src/sccp_scoc.c
1 file changed, 34 insertions(+), 3 deletions(-)
Approvals:
pespin: Looks good to me, approved
osmith: Looks good to me, but someone else must approve
Jenkins Builder: Verified
laforge: Looks good to me, but someone else must approve
diff --git a/src/sccp_scoc.c b/src/sccp_scoc.c
index c11dddf..8222bde 100644
--- a/src/sccp_scoc.c
+++ b/src/sccp_scoc.c
@@ -102,6 +102,11 @@
uint32_t sccp_class;
uint32_t release_cause; /* WAIT_CONN_CONF */
+ /* SLS to be used to transmit all Connection-oriented messages
+ * (ITU-T Q.714 1.1.2.3 Protocol class 2).
+ * SLS is 4 bits, as described in ITU Q.704 Figure 3 */
+ uint8_t tx_co_mtp_sls;
+
struct msgb *opt_data_cache;
/* incoming (true) or outgoing (false) */
@@ -450,6 +455,26 @@
#define INIT_TIMER(x, fn, priv) do { (x)->cb = fn; (x)->data = priv; } while (0)
+/* Generate an SLS to be used for Connection-oriented messages on this SCCP connection.
+ * SLS is 4 bits, as described in ITU Q.704 Figure 3.
+ * ITU-T Q.714 1.1.2.3 Protocol class 2:
+ * "Messages belonging to a given signalling connection shall contain the same
+ * value of the SLS field to ensure sequencing as described in 1.1.2.2"
+ */
+static uint8_t sccp_conn_gen_tx_co_mtp_sls(const struct sccp_connection *conn)
+{
+ /* Implementation: Derive the SLS from conn->conn_id. */
+ const uint32_t id = conn->conn_id;
+ uint8_t sls;
+
+ /* First shrink it to 1 byte: */
+ sls = ((id >> (3*8)) ^ (id >> (2*8)) ^ (id >> (1*8)) ^ (id)) & 0xff;
+ /* Now shrink it 8 -> 4 bits: */
+ sls = ((sls >> 4) ^ sls) & 0x0f;
+
+ return sls;
+}
+
/* allocate + init a SCCP Connection with given ID */
static struct sccp_connection *conn_create_id(struct osmo_sccp_user *user, uint32_t conn_id)
{
@@ -472,6 +497,8 @@
INIT_TIMER(&conn->t_int, int_tmr_cb, conn);
INIT_TIMER(&conn->t_rep_rel, rep_rel_tmr_cb, conn);
+ conn->tx_co_mtp_sls = sccp_conn_gen_tx_co_mtp_sls(conn);
+
/* this might change at runtime, as it is not a constant :/ */
sccp_scoc_fsm.log_subsys = DLSCCP;
@@ -715,6 +742,13 @@
if (!xua)
return NULL;
+ /* amend this with point code information; Many CO msgs
+ * includes neither called nor calling party address! */
+ xua->mtp.dpc = conn->remote_pc;
+
+ /* Apply SLS calculated for the connection (ITU-T Q.714 1.1.2.3). */
+ xua->mtp.sls = conn->tx_co_mtp_sls;
+
switch (msg_type) {
case SUA_CO_CORE: /* Connect Request == SCCP CR */
xua->hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_CORE);
@@ -835,9 +869,6 @@
if (!xua)
return -ENOMEM;
- /* amend this with point code information; Many CO msgs
- * includes neither called nor calling party address! */
- xua->mtp.dpc = conn->remote_pc;
sccp_scrc_rx_scoc_conn_msg(conn->inst, xua);
xua_msg_free(xua);
return 0;
--
To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/39689?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I1956acf631867b12b647d14c10057ded20d7fa2f
Gerrit-Change-Number: 39689
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
[L] Change in libosmo-sigtran[master]: AS loadsharing: Initial routing implementation based on extended-SLS
by pespin 06 Mar '25
by pespin 06 Mar '25
06 Mar '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/39377?usp=email )
Change subject: AS loadsharing: Initial routing implementation based on extended-SLS
......................................................................
AS loadsharing: Initial routing implementation based on extended-SLS
This commit adds a new set of APIs and structs to support routing based
on OPC,DPC,SLS fields and hence to support AS-loadshare.
The routing decision is still actually left as beforehand, ie. the first
AS/linkset in the combined_linkset is selected.
This will allow future work, i.e to:
- Check if data can be sent over the combined link (at least one
AS/linkset is ACTIVE), and otherwise try using a combined link with a
less specific match (shorter prefix mask or/and lower priority).
- Select one of the AS/linksets in the combined link based on a
round robin approach.
Related: SYS#7112
Change-Id: I0fb4ca4959096f748a23082efa0481300de56436
---
M include/osmocom/sigtran/osmo_ss7.h
M src/osmo_ss7_combined_linkset.c
M src/osmo_ss7_hmrt.c
M src/osmo_ss7_instance.c
M src/osmo_ss7_route.c
M src/osmo_ss7_route_table.c
M src/osmo_ss7_vty.c
M src/sccp_scrc.c
M src/ss7_combined_linkset.h
M src/ss7_instance.h
M src/ss7_route_table.h
M src/xua_rkm.c
M src/xua_snm.c
M tests/ss7/ss7_test.c
M tests/vty/osmo_stp_test.vty
15 files changed, 293 insertions(+), 48 deletions(-)
Approvals:
Jenkins Builder: Verified
osmith: Looks good to me, but someone else must approve
laforge: Looks good to me, but someone else must approve
pespin: Looks good to me, approved
diff --git a/include/osmocom/sigtran/osmo_ss7.h b/include/osmocom/sigtran/osmo_ss7.h
index 66cbfe6..264507b 100644
--- a/include/osmocom/sigtran/osmo_ss7.h
+++ b/include/osmocom/sigtran/osmo_ss7.h
@@ -125,7 +125,8 @@
struct osmo_ss7_route;
struct osmo_ss7_route *
-osmo_ss7_route_lookup(struct osmo_ss7_instance *inst, uint32_t dpc);
+osmo_ss7_route_lookup(struct osmo_ss7_instance *inst, uint32_t dpc)
+ OSMO_DEPRECATED("Use internal ss7_instance_lookup_route() instead");
const char *osmo_ss7_route_print(const struct osmo_ss7_route *rt);
const char *osmo_ss7_route_name(struct osmo_ss7_route *rt, bool list_asps);
struct osmo_ss7_as *
diff --git a/src/osmo_ss7_combined_linkset.c b/src/osmo_ss7_combined_linkset.c
index 2e068b4..90a54f6 100644
--- a/src/osmo_ss7_combined_linkset.c
+++ b/src/osmo_ss7_combined_linkset.c
@@ -126,9 +126,86 @@
void ss7_combined_linkset_del_route(struct osmo_ss7_route *rt)
{
struct osmo_ss7_combined_linkset *clset = rt->clset;
+
+ /* Remove route from eSLS table: */
+ for (unsigned int i = 0; i < ARRAY_SIZE(clset->esls_table); i++) {
+ if (clset->esls_table[i].normal_rt == rt)
+ clset->esls_table[i].normal_rt = NULL;
+ if (clset->esls_table[i].alt_rt == rt)
+ clset->esls_table[i].alt_rt = NULL;
+ }
+
llist_del(&rt->list);
rt->clset = NULL;
clset->num_routes--;
if (clset->num_routes == 0)
ss7_combined_linkset_free(clset);
}
+
+static ext_sls_t osmo_ss7_instance_calc_itu_ext_sls(const struct osmo_ss7_instance *inst, const struct osmo_ss7_route_label *rtlabel)
+{
+ /* Take 6 bits from OPC and DPC according to config: */
+ uint8_t opc6 = (uint8_t)((rtlabel->opc >> inst->cfg.opc_shift) & 0x3f);
+ uint8_t dpc6 = (uint8_t)((rtlabel->dpc >> inst->cfg.dpc_shift) & 0x3f);
+
+ /* Derivate 3-bit value from OPC and DPC: */
+ uint8_t opc3 = ((opc6 >> 3) ^ (opc6 & 0x07)) & 0x07;
+ uint8_t dpc3 = ((dpc6 >> 3) ^ (dpc6 & 0x07)) & 0x07;
+ uint8_t opc_dpc3 = (opc3 ^ dpc3) & 0x07;
+
+ /* Generate 7 bit extended-SLS: 3-bit OPC-DPC + 4 bit SLS: */
+ uint8_t ext_sls = (opc_dpc3 << 4) | ((rtlabel->sls) & 0x0f);
+ OSMO_ASSERT(ext_sls < NUM_EXT_SLS);
+
+ /* Pick extended-SLS bits according to config: */
+ ext_sls = ext_sls >> inst->cfg.sls_shift;
+ return ext_sls;
+}
+
+/* ITU Q.704 4.2.1: "current link set (combined link set)". Pick available already selected route */
+struct osmo_ss7_route *current_rt(const struct osmo_ss7_esls_entry *eslse)
+{
+ if (eslse->normal_rt && ss7_route_is_available(eslse->normal_rt))
+ return eslse->normal_rt;
+ if (eslse->alt_rt && ss7_route_is_available(eslse->alt_rt))
+ return eslse->alt_rt;
+ return NULL;
+}
+
+struct osmo_ss7_route *
+ss7_combined_linkset_lookup_route(struct osmo_ss7_combined_linkset *clset, const struct osmo_ss7_route_label *rtlabel)
+{
+ struct osmo_ss7_route *rt;
+ ext_sls_t esls = osmo_ss7_instance_calc_itu_ext_sls(clset->rtable->inst, rtlabel);
+ struct osmo_ss7_esls_entry *eslse = &clset->esls_table[esls];
+
+ /* First check if we have a cached route for this ESLS */
+ rt = current_rt(eslse);
+ if (rt) {
+ if (rt == eslse->normal_rt) {
+ /* We can transmit over normal route.
+ * Clean up alternative route since it's not needed anymore */
+ eslse->alt_rt = NULL;
+ return rt;
+ }
+ /* We can transmit over alternative route: */
+ return rt;
+ }
+
+ /* TODO: Check if the AS/linkset in rt is actually UP and can be
+ * used, otherwise start ITU Q.704 section 7 "forced rerouting" prcoedure:
+ * we need to pick a temporary dst (update the esls_table entry) while the
+ * original one is DOWN. */
+
+ /* We need to pick a new AS/linkset from the combined linkset and cache
+ * it so it is always used for this eSLS: */
+ /* FIXME: for now we simply take the first AS in the combined linksed, to be improved later... */
+ rt = llist_first_entry_or_null(&clset->routes, struct osmo_ss7_route, list);
+
+ /* TODO: here we'd need to actually check if dst AS/linkset in the route
+ * is actually UP, otherwise pick next one in the roundrobin list... */
+ if (rt)
+ clset->esls_table[esls].normal_rt = rt;
+
+ return rt;
+}
diff --git a/src/osmo_ss7_hmrt.c b/src/osmo_ss7_hmrt.c
index 118acab..1e000b4 100644
--- a/src/osmo_ss7_hmrt.c
+++ b/src/osmo_ss7_hmrt.c
@@ -153,11 +153,16 @@
struct xua_msg *xua)
{
uint32_t dpc = xua->mtp.dpc;
+ struct osmo_ss7_route_label rtlabel = {
+ .opc = xua->mtp.opc,
+ .dpc = xua->mtp.dpc,
+ .sls = xua->mtp.sls,
+ };
struct osmo_ss7_route *rt;
- /* find route for DPC */
+ /* find route for OPC+DPC+SLS: */
/* FIXME: unify with gen_mtp_transfer_req_xua() */
- rt = osmo_ss7_route_lookup(inst, dpc);
+ rt = ss7_instance_lookup_route(inst, &rtlabel);
if (rt) {
/* FIXME: DPC SP restart? */
/* FIXME: DPC Congested? */
diff --git a/src/osmo_ss7_instance.c b/src/osmo_ss7_instance.c
index f7d9a41..527cf2a 100644
--- a/src/osmo_ss7_instance.c
+++ b/src/osmo_ss7_instance.c
@@ -202,6 +202,15 @@
return -1;
}
+/*! \brief Find a SS7 route for given destination point code in given SS7 */
+struct osmo_ss7_route *
+ss7_instance_lookup_route(struct osmo_ss7_instance *inst, const struct osmo_ss7_route_label *rtlabel)
+{
+ OSMO_ASSERT(ss7_initialized);
+ return ss7_route_table_lookup_route(inst->rtable_system, rtlabel);
+}
+
+
/***********************************************************************
* SS7 Application Server
***********************************************************************/
diff --git a/src/osmo_ss7_route.c b/src/osmo_ss7_route.c
index f1fe150..f75e32a 100644
--- a/src/osmo_ss7_route.c
+++ b/src/osmo_ss7_route.c
@@ -335,12 +335,21 @@
return buf;
}
-/*! \brief Find a SS7 route for given destination point code in given SS7 */
+/*! \brief Find a SS7 route for given destination point code in given SS7
+ *
+ * NOTE: DEPRECATED, use ss7_instance_lookup_route() instead
+ */
struct osmo_ss7_route *
osmo_ss7_route_lookup(struct osmo_ss7_instance *inst, uint32_t dpc)
{
OSMO_ASSERT(ss7_initialized);
- return ss7_route_table_find_route_by_dpc(inst->rtable_system, dpc);
+ struct osmo_ss7_route_label rtlb = {
+ .opc = 0,
+ .dpc = dpc,
+ .sls = 0,
+ };
+
+ return ss7_instance_lookup_route(inst, &rtlb);
}
/*! \brief Get destination AS of route
@@ -353,7 +362,6 @@
return rt->dest.as;
}
-
/* Whether route is available, ITU Q.704 */
bool ss7_route_is_available(const struct osmo_ss7_route *rt)
{
diff --git a/src/osmo_ss7_route_table.c b/src/osmo_ss7_route_table.c
index b230521..734db88 100644
--- a/src/osmo_ss7_route_table.c
+++ b/src/osmo_ss7_route_table.c
@@ -19,6 +19,8 @@
*
*/
+ #include <stdio.h>
+
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/logging.h>
#include <osmocom/sigtran/mtp_sap.h>
@@ -29,6 +31,22 @@
#include "ss7_route_table.h"
#include "ss7_internal.h"
+
+/***********************************************************************
+ * SS7 Route Label
+ ***********************************************************************/
+
+char *ss7_route_label_to_str(char *buf, size_t buf_len, const struct osmo_ss7_instance *inst, const struct osmo_ss7_route_label *rtlb)
+{
+ if (buf_len == 0)
+ return NULL;
+ snprintf(buf, buf_len, "OPC=%u=%s,DPC=%u=%s,SLS=%u",
+ rtlb->opc, osmo_ss7_pointcode_print(inst, rtlb->opc),
+ rtlb->dpc, osmo_ss7_pointcode_print2(inst, rtlb->dpc),
+ rtlb->sls);
+ return buf;
+}
+
/***********************************************************************
* SS7 Route Tables
***********************************************************************/
@@ -83,25 +101,10 @@
talloc_free(rtbl);
}
-/*! \brief Find a SS7 route for given destination point code in given table */
-struct osmo_ss7_route *
-ss7_route_table_find_route_by_dpc(struct osmo_ss7_route_table *rtbl, uint32_t dpc)
-{
- struct osmo_ss7_combined_linkset *clset;
- struct osmo_ss7_route *rt;
-
- OSMO_ASSERT(ss7_initialized);
-
- dpc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, dpc);
-
- clset = ss7_route_table_find_combined_linkset_by_dpc(rtbl, dpc);
- if (!clset)
- return NULL;
- rt = llist_first_entry_or_null(&clset->routes, struct osmo_ss7_route, list);
- return rt;
-}
-
-/*! \brief Find a SS7 route for given destination point code + mask in given table */
+/*! \brief Find a SS7 route for given destination point code + mask in given table.
+ *
+ * This function is used for route management procedures, not for packet routing lookup procedures!
+ */
struct osmo_ss7_route *
ss7_route_table_find_route_by_dpc_mask(struct osmo_ss7_route_table *rtbl, uint32_t dpc,
uint32_t mask)
@@ -227,3 +230,27 @@
}
}
}
+
+struct osmo_ss7_route *
+ss7_route_table_lookup_route(struct osmo_ss7_route_table *rtbl, const struct osmo_ss7_route_label *rtlabel)
+{
+ struct osmo_ss7_combined_linkset *clset;
+ struct osmo_ss7_route *rt;
+ struct osmo_ss7_route_label rtlb = {
+ .opc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, rtlabel->opc),
+ .dpc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, rtlabel->dpc),
+ .sls = rtlabel->sls,
+ };
+ /* we assume the combined_links are sorted by mask length, i.e. more
+ * specific combined links first, and less specific combined links with shorter
+ * mask later */
+ llist_for_each_entry(clset, &rtbl->combined_linksets, list) {
+ if ((rtlb.dpc & clset->cfg.mask) != clset->cfg.pc)
+ continue;
+ rt = ss7_combined_linkset_lookup_route(clset, &rtlb);
+ if (!rt)
+ continue;
+ return rt;
+ }
+ return NULL;
+}
diff --git a/src/osmo_ss7_vty.c b/src/osmo_ss7_vty.c
index 2704742..81ce0ce 100644
--- a/src/osmo_ss7_vty.c
+++ b/src/osmo_ss7_vty.c
@@ -290,6 +290,41 @@
return CMD_SUCCESS;
}
+
+DEFUN_ATTR(cs7_opc_dpc_shift, cs7_opc_dpc_shift_cmd,
+ "sls-opc-dpc [opc-shift] [<0-8>] [dpc-shift] [<0-8>]",
+ "Shift OPC and DPC bits used during routing decision\n"
+ "Shift OPC bits used during routing decision\n"
+ "How many bits from ITU OPC field (starting from least-significant-bit) to skip (default=0). 6 bits are always used\n"
+ "Shift DPC bits used during routing decision\n"
+ "How many bits from ITU DPC field (starting from least-significant-bit) to skip (default=0). 6 bits are always used\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_instance *inst = vty->index;
+ if (argc == 4)
+ inst->cfg.dpc_shift = atoi(argv[3]);
+ else if (argc == 3)
+ inst->cfg.dpc_shift = 0;
+ if (argc >= 2)
+ inst->cfg.opc_shift = atoi(argv[1]);
+ else if (argc == 1)
+ inst->cfg.opc_shift = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(cs7_sls_shift, cs7_sls_shift_cmd,
+ "sls-shift <0-6>",
+ "Shift SLS bits used during routing decision\n"
+ "How many bits from derivated 7-bit extended-SLS (OPC, DPC, SLS) field (starting from least-significant-bit) to skip\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_instance *inst = vty->index;
+ inst->cfg.sls_shift = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
static void write_one_cs7(struct vty *vty, struct osmo_ss7_instance *inst, bool show_dyn_config);
static int write_all_cs7(struct vty *vty, bool show_dyn_config)
@@ -584,7 +619,7 @@
bool list_asps = argc > 4;
struct osmo_ss7_instance *inst;
struct osmo_ss7_route *rt;
- uint32_t dpc;
+ struct osmo_ss7_route_label rtlabel = {};
int pc;
inst = osmo_ss7_instance_find(id);
@@ -598,18 +633,22 @@
vty_out(vty, "Invalid point code (%s)%s", argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
- dpc = pc;
+ rtlabel.dpc = pc;
pc = osmo_ss7_pointcode_parse(inst, argv[2]);
if (pc < 0 || !osmo_ss7_pc_is_valid((uint32_t)pc)) {
vty_out(vty, "Invalid point code (%s)%s", argv[2], VTY_NEWLINE);
return CMD_WARNING;
}
+ rtlabel.opc = pc;
- rt = osmo_ss7_route_lookup(inst, dpc);
+ rtlabel.sls = atoi(argv[3]);
+
+ rt = ss7_instance_lookup_route(inst, &rtlabel);
if (!rt) {
- vty_out(vty, "No route found for DPC %s%s",
- osmo_ss7_pointcode_print(inst, dpc), VTY_NEWLINE);
+ char buf[256];
+ vty_out(vty, "No route found for label '%s'%s",
+ ss7_route_label_to_str(buf, sizeof(buf), inst, &rtlabel), VTY_NEWLINE);
return CMD_WARNING;
}
@@ -2971,6 +3010,13 @@
if (inst->cfg.permit_dyn_rkm_alloc)
vty_out(vty, " xua rkm routing-key-allocation dynamic-permitted%s", VTY_NEWLINE);
+ if (inst->cfg.opc_shift != 0 || inst->cfg.dpc_shift != 0)
+ vty_out(vty, " sls-opc-dpc opc-shift %u dpc-shift %u%s",
+ inst->cfg.opc_shift, inst->cfg.dpc_shift, VTY_NEWLINE);
+
+ if (inst->cfg.sls_shift != 0)
+ vty_out(vty, " sls-shift %u%s", inst->cfg.sls_shift, VTY_NEWLINE);
+
/* first dump ASPs, as ASs reference them */
llist_for_each_entry(asp, &inst->asp_list, list)
write_one_asp(vty, asp, show_dyn_config);
@@ -3133,6 +3179,8 @@
install_lib_element(L_CS7_NODE, &cs7_pc_format_def_cmd);
install_lib_element(L_CS7_NODE, &cs7_pc_delimiter_cmd);
install_lib_element(L_CS7_NODE, &cs7_permit_dyn_rkm_cmd);
+ install_lib_element(L_CS7_NODE, &cs7_opc_dpc_shift_cmd);
+ install_lib_element(L_CS7_NODE, &cs7_sls_shift_cmd);
install_node(&asp_node, NULL);
install_lib_element_ve(&show_cs7_asp_cmd);
diff --git a/src/sccp_scrc.c b/src/sccp_scrc.c
index 23c3f2d..869235c 100644
--- a/src/sccp_scrc.c
+++ b/src/sccp_scrc.c
@@ -37,6 +37,7 @@
#include "ss7_instance.h"
#include "ss7_linkset.h"
#include "ss7_route.h"
+#include "ss7_route_table.h"
#include "xua_internal.h"
@@ -120,6 +121,7 @@
const struct osmo_sccp_addr *called)
{
struct osmo_ss7_route *rt;
+ struct osmo_ss7_route_label rtlabel;
/* this is a bit fishy due to the different requirements of
* classic SSCP/MTP compared to various SIGTRAN stackings.
@@ -144,7 +146,13 @@
return -1;
}
- rt = osmo_ss7_route_lookup(inst->ss7, xua->mtp.dpc);
+ rtlabel = (struct osmo_ss7_route_label){
+ .opc = xua->mtp.opc,
+ .dpc = xua->mtp.dpc,
+ .sls = xua->mtp.sls,
+ };
+
+ rt = ss7_instance_lookup_route(inst->ss7, &rtlabel);
if (!rt) {
LOGP(DLSCCP, LOGL_ERROR, "MTP-TRANSFER.req from SCCP for "
"DPC %u: no route!\n", xua->mtp.dpc);
diff --git a/src/ss7_combined_linkset.h b/src/ss7_combined_linkset.h
index 1c3b684..e2f9c9d 100644
--- a/src/ss7_combined_linkset.h
+++ b/src/ss7_combined_linkset.h
@@ -10,6 +10,17 @@
struct osmo_ss7_instance;
struct osmo_ss7_link;
+struct osmo_ss7_route_label;
+
+#define NUM_EXT_SLS 128
+typedef uint8_t ext_sls_t; /* range: 0-127, 7 bit */
+
+struct osmo_ss7_esls_entry {
+ /* ITU Q.704 4.2.1: "normal link set (combined link set)" */
+ struct osmo_ss7_route *normal_rt;
+ /* ITU Q.704 4.2.1: "alternative link set (combined link set)" */
+ struct osmo_ss7_route *alt_rt;
+};
struct osmo_ss7_combined_linkset {
/*! member in \ref osmo_ss7_route_table.combined_linksets */
@@ -17,6 +28,7 @@
/*! \ref osmo_ss7_route_table to which we belong */
struct osmo_ss7_route_table *rtable;
+ struct osmo_ss7_esls_entry esls_table[NUM_EXT_SLS];
/*! list of \ref osmo_ss7_route */
struct llist_head routes;
@@ -41,3 +53,5 @@
ss7_combined_linkset_add_route(struct osmo_ss7_combined_linkset *clset, struct osmo_ss7_route *rt);
void
ss7_combined_linkset_del_route(struct osmo_ss7_route *rt);
+struct osmo_ss7_route *
+ss7_combined_linkset_lookup_route(struct osmo_ss7_combined_linkset *clset, const struct osmo_ss7_route_label *rtlabel);
diff --git a/src/ss7_instance.h b/src/ss7_instance.h
index d76891f..bb8815b 100644
--- a/src/ss7_instance.h
+++ b/src/ss7_instance.h
@@ -10,6 +10,7 @@
struct osmo_ss7_user;
struct osmo_ss7_route_table;
+struct osmo_ss7_route_label;
struct osmo_sccp_instance;
struct osmo_ss7_pc_fmt {
@@ -49,6 +50,15 @@
bool permit_dyn_rkm_alloc;
struct llist_head sccp_address_book;
uint32_t secondary_pc;
+ /* How many bits from ITU OPC/DPC field (starting from least-significant-bit)
+ * to skip for routing decisions (always takes 6 bits).
+ * range 0-8, defaults to 0, which means take least significant 6 bits. */
+ uint8_t opc_shift;
+ uint8_t dpc_shift;
+ /* How many bits from ITU SLS field (starting from least-significant-bit)
+ * to skip for routing decisions.
+ * range 0-3, defaults to 0, which means take all 4 bits. */
+ uint8_t sls_shift;
} cfg;
};
@@ -56,6 +66,8 @@
ss7_instance_alloc(void *ctx, uint32_t id);
uint32_t ss7_find_free_l_rk_id(struct osmo_ss7_instance *inst);
+struct osmo_ss7_route *
+ss7_instance_lookup_route(struct osmo_ss7_instance *inst, const struct osmo_ss7_route_label *rtlabel);
#define _LOGSS7(inst, subsys, level, fmt, args ...) \
LOGP(subsys, level, "%u: " fmt, inst ? (inst)->cfg.id : 0, ## args)
diff --git a/src/ss7_route_table.h b/src/ss7_route_table.h
index c88c742..1de3be5 100644
--- a/src/ss7_route_table.h
+++ b/src/ss7_route_table.h
@@ -1,6 +1,7 @@
#pragma once
#include <stdint.h>
+#include <unistd.h>
#include <osmocom/core/linuxlist.h>
/***********************************************************************
@@ -9,6 +10,13 @@
struct osmo_ss7_instance;
+struct osmo_ss7_route_label {
+ uint32_t opc;
+ uint32_t dpc;
+ uint8_t sls;
+};
+char *ss7_route_label_to_str(char *buf, size_t buf_len, const struct osmo_ss7_instance *inst, const struct osmo_ss7_route_label *rtlb);
+
struct osmo_ss7_route_table {
/*! member in list of routing tables */
struct llist_head list;
@@ -30,10 +38,10 @@
void ss7_route_table_destroy(struct osmo_ss7_route_table *rtbl);
struct osmo_ss7_route *
-ss7_route_table_find_route_by_dpc(struct osmo_ss7_route_table *rtbl, uint32_t dpc);
-struct osmo_ss7_route *
ss7_route_table_find_route_by_dpc_mask(struct osmo_ss7_route_table *rtbl, uint32_t dpc,
uint32_t mask);
+struct osmo_ss7_route *
+ss7_route_table_lookup_route(struct osmo_ss7_route_table *rtbl, const struct osmo_ss7_route_label *rtlabel);
struct osmo_ss7_combined_linkset *
ss7_route_table_find_combined_linkset(struct osmo_ss7_route_table *rtbl, uint32_t dpc, uint32_t mask, uint32_t prio);
diff --git a/src/xua_rkm.c b/src/xua_rkm.c
index 98f41c5..8fa8c3b 100644
--- a/src/xua_rkm.c
+++ b/src/xua_rkm.c
@@ -393,7 +393,7 @@
return -1;
}
- rt = ss7_route_table_find_route_by_dpc(inst->rtable_system, as->cfg.routing_key.pc);
+ rt = ss7_route_table_find_route_by_dpc_mask(inst->rtable_system, as->cfg.routing_key.pc, 0xffffff);
if (!rt) {
msgb_append_dereg_res(resp, M3UA_RKM_DEREG_ERR_UNKNOWN, 0);
return -1;
diff --git a/src/xua_snm.c b/src/xua_snm.c
index 971380b..acdfe0c 100644
--- a/src/xua_snm.c
+++ b/src/xua_snm.c
@@ -34,6 +34,7 @@
#include "ss7_as.h"
#include "ss7_asp.h"
#include "ss7_internal.h"
+#include "ss7_route_table.h"
#include "xua_internal.h"
#include "sccp_internal.h"
@@ -340,8 +341,14 @@
if (mask == 0) {
/* one single point code */
+ struct osmo_ss7_route_label rtlabel = {
+ .opc = xua->mtp.opc, /* Use OPC of received DAUD. FIXME: is this correct? */
+ .dpc = pc,
+ .sls = 0,
+ };
+
/* FIXME: don't just check for a route; but also check if the route is "active" */
- if (osmo_ss7_route_lookup(s7i, pc))
+ if (ss7_instance_lookup_route(s7i, &rtlabel))
is_available = true;
xua_tx_snm_available(asp, rctx, num_rctx, &aff_pc[i], 1, "Response to DAUD",
diff --git a/tests/ss7/ss7_test.c b/tests/ss7/ss7_test.c
index 6fe1110..95fa1b1 100644
--- a/tests/ss7/ss7_test.c
+++ b/tests/ss7/ss7_test.c
@@ -147,11 +147,15 @@
osmo_ss7_user_destroy(user2);
}
+#define RT_LABEL(opc_val, dpc_val, sls_val) \
+ (struct osmo_ss7_route_label){ .opc = (opc_val), .dpc = (dpc_val), .sls = (sls_val) }
+
static void test_route(void)
{
struct osmo_ss7_route_table *rtbl;
struct osmo_ss7_linkset *lset_a, *lset_b;
struct osmo_ss7_route *rt, *rt12, *rtdef;
+ struct osmo_ss7_route_label route_label;
printf("Testing SS7 routing\n");
@@ -173,32 +177,45 @@
OSMO_ASSERT(lset_b);
/* route with full mask */
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 12) == NULL);
+ route_label = RT_LABEL(0, 12, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == NULL);
rt = ss7_route_create(rtbl, 12, 0xffff, "a");
printf("route with full mask: %s\n", osmo_ss7_route_print(rt));
OSMO_ASSERT(rt);
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 12) == rt);
+ route_label = RT_LABEL(0, 12, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == rt);
ss7_route_destroy(rt);
/* route with partial mask */
rt = ss7_route_create(rtbl, 8, 0xfff8, "a");
printf("route with partial mask: %s\n", osmo_ss7_route_print(rt));
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 8) == rt);
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 9) == rt);
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 12) == rt);
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 15) == rt);
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 16) == NULL);
+ route_label = RT_LABEL(0, 8, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == rt);
+ route_label = RT_LABEL(0, 9, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == rt);
+ route_label = RT_LABEL(0, 12, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == rt);
+ route_label = RT_LABEL(0, 15, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == rt);
+ route_label = RT_LABEL(0, 16, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == NULL);
/* insert more specific route for 12, must have higher priority
* than existing one */
rt12 = ss7_route_create(rtbl, 12, 0xffff, "b");
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 12) == rt12);
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 15) == rt);
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 16) == NULL);
+ route_label = RT_LABEL(0, 12, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == rt12);
+ route_label = RT_LABEL(0, 15, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == rt);
+ route_label = RT_LABEL(0, 16, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == NULL);
/* add a default route, which should have lowest precedence */
rtdef = ss7_route_create(rtbl, 0, 0, "a");
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 12) == rt12);
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 15) == rt);
- OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 16) == rtdef);
+ route_label = RT_LABEL(0, 12, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == rt12);
+ route_label = RT_LABEL(0, 15, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == rt);
+ route_label = RT_LABEL(0, 16, 0);
+ OSMO_ASSERT(ss7_route_table_lookup_route(rtbl, &route_label) == rtdef);
ss7_route_destroy(rtdef);
ss7_route_destroy(rt12);
diff --git a/tests/vty/osmo_stp_test.vty b/tests/vty/osmo_stp_test.vty
index 747c7b7..200fff8 100644
--- a/tests/vty/osmo_stp_test.vty
+++ b/tests/vty/osmo_stp_test.vty
@@ -112,6 +112,8 @@
point-code format default
point-code delimiter (default|dash)
xua rkm routing-key-allocation (static-only|dynamic-permitted)
+ sls-opc-dpc [opc-shift] [<0-8>] [dpc-shift] [<0-8>]
+ sls-shift <0-6>
asp NAME <0-65535> <0-65535> (sua|m3ua|ipa)
asp NAME <0-65535> <0-65535> (sua|m3ua|ipa) (sctp|tcp)
no asp NAME
@@ -132,6 +134,8 @@
point-code Configure the local Point Code
secondary-pc Configure the local Secondary Point Code
xua SIGTRAN xxxUA related
+ sls-opc-dpc Shift OPC and DPC bits used during routing decision
+ sls-shift Shift SLS bits used during routing decision
asp Configure Application Server Process
no Negate a command or set its defaults
as Configure an Application Server
--
To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/39377?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I0fb4ca4959096f748a23082efa0481300de56436
Gerrit-Change-Number: 39377
Gerrit-PatchSet: 12
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
[L] Change in libosmo-sigtran[master]: AS loadsharing: Introduce combined_linkset
by pespin 06 Mar '25
by pespin 06 Mar '25
06 Mar '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/38731?usp=email )
(
13 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: AS loadsharing: Introduce combined_linkset
......................................................................
AS loadsharing: Introduce combined_linkset
A "Combined linkset" is a set of routes for different AS or linksets
whose destination (DPC & mask) and priority are the same.
An SP is expected to load share traffic among linksets/AS of a given
combined linkset, based on DPC/OPC,SLS. This means certain state or
heuristics need to be stored in the combined linkset in order to keep
forwarding messages of the same transaction (SLS) over the same specific
AS/linkset.
This commit introduces the osmo_ss7_combined_linkset object, which
is roughly a set of osmo_ss7_route sharing DPC+MASK+PRIO key, and
it is placed in between the osmo_ss7_route_table and osmo_ss7_route
entries.
User still operates/manages indiviual routes, but those are grouped
internally inside its corresponding combined linkset.
No routing change is implemented in this commit. Code is only tweaked
minimally so far to retrieve the first route in the combined link.
This will allow future work, i.e to:
- Check if data can be sent over the combined link (at least one
AS/linkset is ACTIVE), and otherwise try using a combined link with a
less specific match (shorter prefix mask or/and lower priority).
- Select one of the AS/linksets inserted the combined link, based on
OPC/DPC/SLS of the message.
Related: SYS#7112
Change-Id: I500ec74ba975e3c93071771027e4e5fe6000e6f3
---
M src/Makefile.am
A src/osmo_ss7_combined_linkset.c
M src/osmo_ss7_route.c
M src/osmo_ss7_route_table.c
M src/osmo_ss7_vty.c
A src/ss7_combined_linkset.h
M src/ss7_route.h
M src/ss7_route_table.h
8 files changed, 357 insertions(+), 95 deletions(-)
Approvals:
Jenkins Builder: Verified
osmith: Looks good to me, but someone else must approve
daniel: Looks good to me, but someone else must approve
pespin: Looks good to me, approved
diff --git a/src/Makefile.am b/src/Makefile.am
index ced19f1..f108f06 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,6 +7,7 @@
ss7_as.h \
ss7_asp.h \
ss7_asp_peer.h \
+ ss7_combined_linkset.h \
ss7_instance.h \
ss7_internal.h \
ss7_link.h \
@@ -44,6 +45,7 @@
osmo_ss7_as.c \
osmo_ss7_asp.c \
osmo_ss7_asp_peer.c \
+ osmo_ss7_combined_linkset.c \
osmo_ss7_hmrt.c \
osmo_ss7_instance.c \
osmo_ss7_link.c \
diff --git a/src/osmo_ss7_combined_linkset.c b/src/osmo_ss7_combined_linkset.c
new file mode 100644
index 0000000..2e068b4
--- /dev/null
+++ b/src/osmo_ss7_combined_linkset.c
@@ -0,0 +1,134 @@
+/* (C) 2025 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ * Author: Pau Espin Pedrol <pespin(a)sysmocom.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <errno.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/sigtran/osmo_ss7.h>
+
+#include "ss7_combined_linkset.h"
+#include "ss7_route.h"
+#include "ss7_route_table.h"
+#include "ss7_internal.h"
+
+/******************************************************************************
+ * SS7 Combined Linkset
+ *
+ * ITU Q.704 4.2.1: "Signalling traffic to be sent to a particular signalling
+ * point in the network is normally routed to one or, in the case of load
+ * sharing between link sets in the international network, two link sets. A load
+ * sharing collection of two or more link sets is called a combined link set"
+ * [...]
+ * "The possible link set (combined link sets) appear in a certain priority
+ * order. The link set (combined link set) having the highest priority is used
+ * whenever it is available."
+ * [...]
+ * "It is defined that the normal link set (combined link set) for traffic to the
+ * concerned destination. The link set (combined link set) which is in use at a
+ * given time is called the current link set (combined link set). The current
+ * link set (combined link set) consists either of the normal link set (combined
+ * link set) or of an alternative link set (combined link set)."
+ *****************************************************************************/
+
+/*! \brief Insert combined_link into its routing table
+ * \param[in] clset Combined link to be inserted into its routing table
+ * \returns 0 on success, negative on error
+ *
+ * A combined link is only really used once it has been inserted into its routing table.
+ *
+ * insert the route in the ordered list of routes. The list is sorted by
+ * mask length, so that the more specific (longer mask) routes are
+ * first, while the less specific routes with shorter masks are last.
+ * Within the same mask length, the routes are ordered by priority.
+ * Hence, the first matching route in a linear iteration is the most
+ * specific match.
+ */
+static void ss7_combined_linkset_insert(struct osmo_ss7_combined_linkset *clset)
+{
+ struct osmo_ss7_route_table *rtbl = clset->rtable;
+ struct osmo_ss7_combined_linkset *it;
+
+ llist_for_each_entry(it, &rtbl->combined_linksets, list) {
+ if (it->cfg.mask == clset->cfg.mask &&
+ it->cfg.priority > clset->cfg.priority) {
+ /* insert before the current entry */
+ llist_add(&clset->list, it->list.prev);
+ return;
+ }
+ if (it->cfg.mask < clset->cfg.mask) {
+ /* insert before the current entry */
+ llist_add(&clset->list, it->list.prev);
+ return;
+ }
+ }
+ /* not added, i.e. no smaller mask length and priority found: we are the
+ * smallest mask and priority and thus should go last */
+ llist_add_tail(&clset->list, &rtbl->combined_linksets);
+}
+
+struct osmo_ss7_combined_linkset *
+ss7_combined_linkset_alloc(struct osmo_ss7_route_table *rtbl, uint32_t pc, uint32_t mask, uint32_t prio)
+{
+ struct osmo_ss7_combined_linkset *clset;
+
+ clset = talloc_zero(rtbl, struct osmo_ss7_combined_linkset);
+ if (!clset)
+ return NULL;
+
+ clset->rtable = rtbl;
+ /* truncate mask to maximum. Let's avoid callers specifying arbitrary large
+ * masks to ensure we don't fail duplicate detection with longer mask lengths */
+ clset->cfg.mask = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, mask);
+ clset->cfg.pc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, pc);
+ clset->cfg.priority = prio;
+ INIT_LLIST_HEAD(&clset->routes);
+
+ ss7_combined_linkset_insert(clset);
+ return clset;
+}
+
+void
+ss7_combined_linkset_free(struct osmo_ss7_combined_linkset *clset)
+{
+ if (!clset)
+ return;
+ llist_del(&clset->list);
+ talloc_free(clset);
+}
+
+void ss7_combined_linkset_add_route(struct osmo_ss7_combined_linkset *clset, struct osmo_ss7_route *rt)
+{
+ llist_add_tail(&rt->list, &clset->routes);
+ clset->num_routes++;
+ rt->clset = clset;
+}
+
+/* clset may end up freed as a result: */
+void ss7_combined_linkset_del_route(struct osmo_ss7_route *rt)
+{
+ struct osmo_ss7_combined_linkset *clset = rt->clset;
+ llist_del(&rt->list);
+ rt->clset = NULL;
+ clset->num_routes--;
+ if (clset->num_routes == 0)
+ ss7_combined_linkset_free(clset);
+}
diff --git a/src/osmo_ss7_route.c b/src/osmo_ss7_route.c
index 2787895..f1fe150 100644
--- a/src/osmo_ss7_route.c
+++ b/src/osmo_ss7_route.c
@@ -26,6 +26,7 @@
#include <osmocom/sigtran/mtp_sap.h>
#include <osmocom/sigtran/osmo_ss7.h>
+#include "ss7_combined_linkset.h"
#include "ss7_linkset.h"
#include "ss7_as.h"
#include "ss7_asp.h"
@@ -132,34 +133,6 @@
return 0;
}
-/* insert the route in the ordered list of routes. The list is sorted by
- * mask length, so that the more specific (longer mask) routes are
- * first, while the less specific routes with shorter masks are last.
- * Within the same mask length, the routes are ordered by priority.
- * Hence, the first matching route in a linear iteration is the most
- * specific match. */
-static void route_insert_sorted(struct osmo_ss7_route_table *rtbl,
- struct osmo_ss7_route *cmp)
-{
- struct osmo_ss7_route *rt;
-
- llist_for_each_entry(rt, &rtbl->routes, list) {
- if (rt->cfg.mask == cmp->cfg.mask &&
- rt->cfg.priority > cmp->cfg.priority) {
- /* insert before the current entry */
- llist_add(&cmp->list, rt->list.prev);
- return;
- }
- if (rt->cfg.mask < cmp->cfg.mask) {
- /* insert before the current entry */
- llist_add(&cmp->list, rt->list.prev);
- return;
- }
- }
- /* not added, i.e. no smaller mask length and priority found: we are the
- * smallest mask and priority and thus should go last */
- llist_add_tail(&cmp->list, &rtbl->routes);
-}
/*! \brief Insert route into its routing table
* \param[in] rt Route to be inserted into its routing table
@@ -170,7 +143,7 @@
int
ss7_route_insert(struct osmo_ss7_route *rt)
{
- struct osmo_ss7_route *prev_rt;
+ struct osmo_ss7_combined_linkset *clset;
struct osmo_ss7_route_table *rtbl = rt->rtable;
if (ss7_route_inserted(rt)) {
@@ -183,17 +156,24 @@
return -EINVAL;
}
- /* check for duplicates */
- prev_rt = ss7_route_table_find_route_by_dpc_mask(rtbl, rt->cfg.pc, rt->cfg.mask);
- if (prev_rt && !strcmp(prev_rt->cfg.linkset_name, rt->cfg.linkset_name)) {
- LOGSS7(rtbl->inst, LOGL_ERROR,
- "Refusing to create route with existing linkset name: pc=%u=%s mask=0x%x via linkset/AS '%s'\n",
- rt->cfg.pc, osmo_ss7_pointcode_print(rtbl->inst, rt->cfg.pc),
- rt->cfg.mask, rt->cfg.linkset_name);
- return -EADDRINUSE;
+ clset = ss7_route_table_find_combined_linkset(rtbl, rt->cfg.pc, rt->cfg.mask, rt->cfg.priority);
+ if (clset) { /* check for duplicates */
+ struct osmo_ss7_route *prev_rt;
+ llist_for_each_entry(prev_rt, &clset->routes, list) {
+ if (!strcmp(prev_rt->cfg.linkset_name, rt->cfg.linkset_name)) {
+ LOGSS7(rtbl->inst, LOGL_ERROR,
+ "Refusing to create route with existing linkset name: pc=%u=%s mask=0x%x via linkset/AS '%s'\n",
+ rt->cfg.pc, osmo_ss7_pointcode_print(rtbl->inst, rt->cfg.pc),
+ rt->cfg.mask, rt->cfg.linkset_name);
+ return -EADDRINUSE;
+ }
+ }
+ } else {
+ clset = ss7_combined_linkset_alloc(rtbl, rt->cfg.pc, rt->cfg.mask, rt->cfg.priority);
+ OSMO_ASSERT(clset);
}
- route_insert_sorted(rtbl, rt);
+ ss7_combined_linkset_add_route(clset, rt);
return 0;
}
@@ -250,7 +230,7 @@
"Destroying route: pc=%u=%s mask=0x%x via linkset/ASP '%s'\n",
rt->cfg.pc, osmo_ss7_pointcode_print(inst, rt->cfg.pc),
rt->cfg.mask, rt->cfg.linkset_name);
- llist_del(&rt->list);
+ ss7_combined_linkset_del_route(rt);
}
talloc_free(rt);
}
diff --git a/src/osmo_ss7_route_table.c b/src/osmo_ss7_route_table.c
index 03596d0..b230521 100644
--- a/src/osmo_ss7_route_table.c
+++ b/src/osmo_ss7_route_table.c
@@ -24,6 +24,7 @@
#include <osmocom/sigtran/mtp_sap.h>
#include <osmocom/sigtran/osmo_ss7.h>
+#include "ss7_combined_linkset.h"
#include "ss7_route.h"
#include "ss7_route_table.h"
#include "ss7_internal.h"
@@ -44,7 +45,7 @@
rtbl->inst = inst;
rtbl->cfg.name = talloc_strdup(rtbl, name);
- INIT_LLIST_HEAD(&rtbl->routes);
+ INIT_LLIST_HEAD(&rtbl->combined_linksets);
llist_add_tail(&rtbl->list, &inst->rtable_list);
return rtbl;
}
@@ -77,8 +78,8 @@
ss7_route_table_destroy(struct osmo_ss7_route_table *rtbl)
{
llist_del(&rtbl->list);
- /* routes are allocated as children of route table, will be
- * automatically freed() */
+ /* combined links & routes are allocated as children of route table,
+ * will be automatically freed() */
talloc_free(rtbl);
}
@@ -86,20 +87,18 @@
struct osmo_ss7_route *
ss7_route_table_find_route_by_dpc(struct osmo_ss7_route_table *rtbl, uint32_t dpc)
{
+ struct osmo_ss7_combined_linkset *clset;
struct osmo_ss7_route *rt;
OSMO_ASSERT(ss7_initialized);
dpc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, dpc);
- /* we assume the routes are sorted by mask length, i.e. more
- * specific routes first, and less specific routes with shorter
- * mask later */
- llist_for_each_entry(rt, &rtbl->routes, list) {
- if ((dpc & rt->cfg.mask) == rt->cfg.pc)
- return rt;
- }
- return NULL;
+ clset = ss7_route_table_find_combined_linkset_by_dpc(rtbl, dpc);
+ if (!clset)
+ return NULL;
+ rt = llist_first_entry_or_null(&clset->routes, struct osmo_ss7_route, list);
+ return rt;
}
/*! \brief Find a SS7 route for given destination point code + mask in given table */
@@ -107,40 +106,124 @@
ss7_route_table_find_route_by_dpc_mask(struct osmo_ss7_route_table *rtbl, uint32_t dpc,
uint32_t mask)
{
+ struct osmo_ss7_combined_linkset *clset;
struct osmo_ss7_route *rt;
OSMO_ASSERT(ss7_initialized);
- mask = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, mask);
- dpc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, dpc);
- /* we assume the routes are sorted by mask length, i.e. more
- * specific routes first, and less specific routes with shorter
+ dpc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, dpc);
+ mask = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, mask);
+
+ clset = ss7_route_table_find_combined_linkset_by_dpc_mask(rtbl, dpc, mask);
+ if (!clset)
+ return NULL;
+ rt = llist_first_entry_or_null(&clset->routes, struct osmo_ss7_route, list);
+ return rt;
+}
+
+struct osmo_ss7_combined_linkset *
+ss7_route_table_find_combined_linkset_by_dpc(struct osmo_ss7_route_table *rtbl, uint32_t dpc)
+{
+ struct osmo_ss7_combined_linkset *clset;
+
+ OSMO_ASSERT(ss7_initialized);
+
+ dpc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, dpc);
+ /* we assume the combined_links are sorted by mask length, i.e. more
+ * specific combined links first, and less specific combined links with shorter
* mask later */
- llist_for_each_entry(rt, &rtbl->routes, list) {
- if (dpc == rt->cfg.pc && mask == rt->cfg.mask)
- return rt;
+ llist_for_each_entry(clset, &rtbl->combined_linksets, list) {
+ if ((dpc & clset->cfg.mask) != clset->cfg.pc)
+ continue;
+ return clset;
}
return NULL;
}
-/* find any routes pointing to this linkset and remove them */
-void ss7_route_table_del_routes_by_linkset(struct osmo_ss7_route_table *rtbl, struct osmo_ss7_linkset *lset)
+struct osmo_ss7_combined_linkset *
+ss7_route_table_find_combined_linkset_by_dpc_mask(struct osmo_ss7_route_table *rtbl, uint32_t dpc, uint32_t mask)
{
- struct osmo_ss7_route *rt, *rt2;
+ struct osmo_ss7_combined_linkset *clset;
- llist_for_each_entry_safe(rt, rt2, &rtbl->routes, list) {
- if (rt->dest.linkset == lset)
- ss7_route_destroy(rt);
+ OSMO_ASSERT(ss7_initialized);
+
+ dpc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, dpc);
+ /* we assume the combined_links are sorted by mask length, i.e. more
+ * specific combined links first, and less specific combined links with shorter
+ * mask later */
+ llist_for_each_entry(clset, &rtbl->combined_linksets, list) {
+ if ((dpc & clset->cfg.mask) != clset->cfg.pc)
+ continue;
+ if (mask != clset->cfg.mask)
+ continue;
+ return clset;
}
+ return NULL;
+}
+
+struct osmo_ss7_combined_linkset *
+ss7_route_table_find_combined_linkset(struct osmo_ss7_route_table *rtbl, uint32_t dpc, uint32_t mask, uint32_t prio)
+{
+ struct osmo_ss7_combined_linkset *clset;
+
+ /* we assume the combined_links are sorted by mask length, i.e. more
+ * specific routes first, and less specific routes with shorter
+ * mask later */
+ llist_for_each_entry(clset, &rtbl->combined_linksets, list) {
+ if (mask < clset->cfg.mask)
+ break;
+ if (dpc == clset->cfg.pc && mask == clset->cfg.mask) {
+ if (prio > clset->cfg.priority)
+ break;
+ if (prio == clset->cfg.priority)
+ return clset;
+ }
+ }
+ return NULL;
+}
+
+struct osmo_ss7_combined_linkset *
+ss7_route_table_find_or_create_combined_linkset(struct osmo_ss7_route_table *rtable, uint32_t pc, uint32_t mask, uint32_t prio)
+{
+ struct osmo_ss7_combined_linkset *clset;
+ clset = ss7_route_table_find_combined_linkset(rtable, pc, mask, prio);
+ if (!clset)
+ clset = ss7_combined_linkset_alloc(rtable, pc, mask, prio);
+ return clset;
}
/* find any routes pointing to this AS and remove them */
void ss7_route_table_del_routes_by_as(struct osmo_ss7_route_table *rtbl, struct osmo_ss7_as *as)
{
- struct osmo_ss7_route *rt, *rt2;
+ struct osmo_ss7_combined_linkset *clset, *clset2;
- llist_for_each_entry_safe(rt, rt2, &rtbl->routes, list) {
- if (rt->dest.as == as)
- ss7_route_destroy(rt);
+ llist_for_each_entry_safe(clset, clset2, &rtbl->combined_linksets, list) {
+ struct osmo_ss7_route *rt;
+ llist_for_each_entry(rt, &clset->routes, list) {
+ if (rt->dest.as == as) {
+ ss7_route_destroy(rt);
+ /* clset may have been freed here. Same AS can't be twice in a combined
+ * linkset, so simply continue iterating in the upper loop. */
+ break;
+ }
+ }
+ }
+}
+
+/* find any routes pointing to this linkset and remove them */
+void ss7_route_table_del_routes_by_linkset(struct osmo_ss7_route_table *rtbl, struct osmo_ss7_linkset *lset)
+{
+ struct osmo_ss7_combined_linkset *clset, *clset2;
+
+ llist_for_each_entry_safe(clset, clset2, &rtbl->combined_linksets, list) {
+ struct osmo_ss7_route *rt;
+ llist_for_each_entry(rt, &clset->routes, list) {
+ if (rt->dest.linkset == lset) {
+ ss7_route_destroy(rt);
+ /* clset may have been freed here. Same linkset can't be twice in a combined
+ * linkset, so simply continue iterating in the upper loop. */
+ break;
+ }
+ }
}
}
diff --git a/src/osmo_ss7_vty.c b/src/osmo_ss7_vty.c
index f76a69e..2704742 100644
--- a/src/osmo_ss7_vty.c
+++ b/src/osmo_ss7_vty.c
@@ -48,6 +48,7 @@
#include "sccp_internal.h"
#include "ss7_as.h"
#include "ss7_asp.h"
+#include "ss7_combined_linkset.h"
#include "ss7_route.h"
#include "ss7_route_table.h"
#include "ss7_internal.h"
@@ -487,27 +488,31 @@
static void write_one_rtable(struct vty *vty, struct osmo_ss7_route_table *rtable)
{
+ struct osmo_ss7_combined_linkset *clset;
struct osmo_ss7_route *rt;
vty_out(vty, " route-table %s%s", rtable->cfg.name, VTY_NEWLINE);
if (rtable->cfg.description)
vty_out(vty, " description %s%s", rtable->cfg.description, VTY_NEWLINE);
- llist_for_each_entry(rt, &rtable->routes, list) {
- vty_out(vty, " update route %s %s linkset %s",
- osmo_ss7_pointcode_print(rtable->inst, rt->cfg.pc),
- osmo_ss7_pointcode_print2(rtable->inst, rt->cfg.mask),
- rt->cfg.linkset_name);
- if (rt->cfg.priority != OSMO_SS7_ROUTE_PRIO_DEFAULT)
- vty_out(vty, " priority %u", rt->cfg.priority);
- if (rt->cfg.qos_class)
- vty_out(vty, " qos-class %u", rt->cfg.qos_class);
- vty_out(vty, "%s", VTY_NEWLINE);
+ llist_for_each_entry(clset, &rtable->combined_linksets, list) {
+ llist_for_each_entry(rt, &clset->routes, list) {
+ vty_out(vty, " update route %s %s linkset %s",
+ osmo_ss7_pointcode_print(rtable->inst, rt->cfg.pc),
+ osmo_ss7_pointcode_print2(rtable->inst, rt->cfg.mask),
+ rt->cfg.linkset_name);
+ if (rt->cfg.priority != OSMO_SS7_ROUTE_PRIO_DEFAULT)
+ vty_out(vty, " priority %u", rt->cfg.priority);
+ if (rt->cfg.qos_class)
+ vty_out(vty, " qos-class %u", rt->cfg.qos_class);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
}
}
/* "filter_pc == OSMO_SS7_PC_INVALID" means "show all" */
static void vty_dump_rtable(struct vty *vty, struct osmo_ss7_route_table *rtbl, uint32_t filter_pc)
{
+ struct osmo_ss7_combined_linkset *clset;
struct osmo_ss7_route *rt;
vty_out(vty, "Routing table = %s%s", rtbl->cfg.name, VTY_NEWLINE);
@@ -516,23 +521,25 @@
vty_out(vty, "Destination C Q P Linkset Name Linkset Non-adj Route%s", VTY_NEWLINE);
vty_out(vty, "---------------------- - - - ------------------- ------- ------- -------%s", VTY_NEWLINE);
- llist_for_each_entry(rt, &rtbl->routes, list) {
- if ((filter_pc != OSMO_SS7_PC_INVALID) && ((filter_pc & rt->cfg.mask) != rt->cfg.pc))
- continue; /* Skip routes not matching destination */
+ llist_for_each_entry(clset, &rtbl->combined_linksets, list) {
+ if ((filter_pc != OSMO_SS7_PC_INVALID) && ((filter_pc & clset->cfg.mask) != clset->cfg.pc))
+ continue; /* Skip combined linksets not matching destination */
- bool rt_avail = ss7_route_is_available(rt);
+ llist_for_each_entry(rt, &clset->routes, list) {
+ bool rt_avail = ss7_route_is_available(rt);
- vty_out(vty, "%-16s %-5s %c %c %u %-19s %-7s %-7s %-7s%s",
- osmo_ss7_route_print(rt),
- rt_avail ? "acces" : "INACC",
- ' ',
- '0' + rt->cfg.qos_class,
- rt->cfg.priority,
- rt->cfg.linkset_name,
- rt_avail ? "avail" : "UNAVAIL",
- "?",
- rt_avail ? "avail" : "UNAVAIL",
- VTY_NEWLINE);
+ vty_out(vty, "%-16s %-5s %c %c %u %-19s %-7s %-7s %-7s%s",
+ osmo_ss7_route_print(rt),
+ rt_avail ? "acces" : "INACC",
+ ' ',
+ '0' + rt->cfg.qos_class,
+ rt->cfg.priority,
+ rt->cfg.linkset_name,
+ rt_avail ? "avail" : "UNAVAIL",
+ "?",
+ rt_avail ? "avail" : "UNAVAIL",
+ VTY_NEWLINE);
+ }
}
}
diff --git a/src/ss7_combined_linkset.h b/src/ss7_combined_linkset.h
new file mode 100644
index 0000000..1c3b684
--- /dev/null
+++ b/src/ss7_combined_linkset.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <stdint.h>
+#include <osmocom/core/linuxlist.h>
+
+/***********************************************************************
+ * SS7 Combined Linkset
+ * Set of routes with same destination and priority.
+ ***********************************************************************/
+
+struct osmo_ss7_instance;
+struct osmo_ss7_link;
+
+struct osmo_ss7_combined_linkset {
+ /*! member in \ref osmo_ss7_route_table.combined_linksets */
+ struct llist_head list;
+
+ /*! \ref osmo_ss7_route_table to which we belong */
+ struct osmo_ss7_route_table *rtable;
+
+ /*! list of \ref osmo_ss7_route */
+ struct llist_head routes;
+ unsigned int num_routes;
+
+ struct {
+ uint32_t pc;
+ uint32_t mask;
+ /*! lower priority is higher */
+ uint32_t priority;
+ } cfg;
+};
+
+struct osmo_ss7_combined_linkset *
+ss7_combined_linkset_alloc(struct osmo_ss7_route_table *rtbl, uint32_t pc, uint32_t mask, uint32_t prio);
+void
+ss7_combined_linkset_free(struct osmo_ss7_combined_linkset *clset);
+struct osmo_ss7_linkset *
+ss7_combined_linkset_find_or_create(struct osmo_ss7_route_table *rtbl, uint32_t pc, uint32_t mask, uint32_t prio);
+
+void
+ss7_combined_linkset_add_route(struct osmo_ss7_combined_linkset *clset, struct osmo_ss7_route *rt);
+void
+ss7_combined_linkset_del_route(struct osmo_ss7_route *rt);
diff --git a/src/ss7_route.h b/src/ss7_route.h
index 0382564..0dcc34e 100644
--- a/src/ss7_route.h
+++ b/src/ss7_route.h
@@ -15,10 +15,12 @@
#define OSMO_SS7_ROUTE_PRIO_DEFAULT 5
struct osmo_ss7_route {
- /*! member in \ref osmo_ss7_route_table.routes */
+ /*! member in \ref osmo_ss7_combined_linkset.routes */
struct llist_head list;
/*! \ref osmo_ss7_route_table to which we belong */
struct osmo_ss7_route_table *rtable;
+ /* Combined linkset this route is part of */
+ struct osmo_ss7_combined_linkset *clset;
struct {
/*! pointer to linkset (destination) of route */
diff --git a/src/ss7_route_table.h b/src/ss7_route_table.h
index 38cff31..c88c742 100644
--- a/src/ss7_route_table.h
+++ b/src/ss7_route_table.h
@@ -14,8 +14,8 @@
struct llist_head list;
/*! \ref osmo_ss7_instance to which we belong */
struct osmo_ss7_instance *inst;
- /*! list of \ref osmo_ss7_route */
- struct llist_head routes;
+ /*! list of \ref osmo_ss7_combined_linksets*/
+ struct llist_head combined_linksets;
struct {
char *name;
@@ -35,5 +35,16 @@
ss7_route_table_find_route_by_dpc_mask(struct osmo_ss7_route_table *rtbl, uint32_t dpc,
uint32_t mask);
+struct osmo_ss7_combined_linkset *
+ss7_route_table_find_combined_linkset(struct osmo_ss7_route_table *rtbl, uint32_t dpc, uint32_t mask, uint32_t prio);
+struct osmo_ss7_combined_linkset *
+ss7_route_table_find_or_create_combined_linkset(struct osmo_ss7_route_table *rtbl, uint32_t pc, uint32_t mask, uint32_t prio);
+struct osmo_ss7_combined_linkset *
+ss7_route_table_find_combined_linkset_by_dpc(struct osmo_ss7_route_table *rtbl, uint32_t dpc);
+struct osmo_ss7_combined_linkset *
+ss7_route_table_find_combined_linkset_by_dpc_mask(struct osmo_ss7_route_table *rtbl, uint32_t dpc, uint32_t mask);
+struct osmo_ss7_combined_linkset *
+ss7_route_table_find_combined_linkset(struct osmo_ss7_route_table *rtbl, uint32_t dpc, uint32_t mask, uint32_t prio);
+
void ss7_route_table_del_routes_by_as(struct osmo_ss7_route_table *rtbl, struct osmo_ss7_as *as);
void ss7_route_table_del_routes_by_linkset(struct osmo_ss7_route_table *rtbl, struct osmo_ss7_linkset *lset);
--
To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/38731?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I500ec74ba975e3c93071771027e4e5fe6000e6f3
Gerrit-Change-Number: 38731
Gerrit-PatchSet: 14
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
[M] Change in libosmo-sigtran[master]: AS loadsharing: Implement AS loadshare, skip unavailable AS/lset when...
by pespin 06 Mar '25
by pespin 06 Mar '25
06 Mar '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/39391?usp=email )
Change subject: AS loadsharing: Implement AS loadshare, skip unavailable AS/lset when choosing
......................................................................
AS loadsharing: Implement AS loadshare, skip unavailable AS/lset when choosing
Pick normal route containing destination AS/lset to serve a given
func(<OPC,DPC,SLS>)=eSLS on a round-robin base.
If normal route becomes unavailable, pick an alternative route in a
similar way. This alternative route will be used until itself becomes
unavailable or the normal route becomes available again.
Related: SYS#7112
Change-Id: I928fb1ef5db6922f1386a188e3fbf9e70780f25d
---
M src/osmo_ss7_combined_linkset.c
M src/osmo_ss7_hmrt.c
M src/ss7_combined_linkset.h
M src/xua_snm.c
M tests/ss7/ss7_test.c
M tests/vty/osmo_stp_route_prio.vty
6 files changed, 67 insertions(+), 21 deletions(-)
Approvals:
Jenkins Builder: Verified
pespin: Looks good to me, approved
osmith: Looks good to me, but someone else must approve
diff --git a/src/osmo_ss7_combined_linkset.c b/src/osmo_ss7_combined_linkset.c
index 90a54f6..99b0c79 100644
--- a/src/osmo_ss7_combined_linkset.c
+++ b/src/osmo_ss7_combined_linkset.c
@@ -49,6 +49,20 @@
* link set) or of an alternative link set (combined link set)."
*****************************************************************************/
+static inline struct llist_head *_ss7_llist_round_robin(struct llist_head *list, void **state)
+{
+ struct llist_head *e = *state;
+ if (!e || e->next == list)
+ e = list;
+ e = e->next;
+ if (e == list)
+ e = NULL;
+ *state = e;
+ return e;
+}
+#define ss7_llist_round_robin(list, state, struct_type, entry_name) \
+ llist_entry(_ss7_llist_round_robin(list, state), struct_type, entry_name)
+
/*! \brief Insert combined_link into its routing table
* \param[in] clset Combined link to be inserted into its routing table
* \returns 0 on success, negative on error
@@ -135,6 +149,14 @@
clset->esls_table[i].alt_rt = NULL;
}
+ /* Update round robin state */
+ if (rt == clset->last_route_roundrobin) {
+ ss7_llist_round_robin(&clset->routes, &clset->last_route_roundrobin, struct osmo_ss7_route, list);
+ /* If there's only one left, remove state: */
+ if (rt == clset->last_route_roundrobin)
+ clset->last_route_roundrobin = NULL;
+ }
+
llist_del(&rt->list);
rt->clset = NULL;
clset->num_routes--;
@@ -172,6 +194,27 @@
return NULL;
}
+static struct osmo_ss7_route *ss7_combined_linkset_select_route_roundrobin(struct osmo_ss7_combined_linkset *clset)
+{
+ struct osmo_ss7_route *rt;
+ struct osmo_ss7_route *rt_found = NULL;
+ unsigned int i = 0;
+
+ while (i < clset->num_routes) {
+ i++;
+ rt = ss7_llist_round_robin(&clset->routes, &clset->last_route_roundrobin, struct osmo_ss7_route, list);
+ if (ss7_route_is_available(rt)) {
+ rt_found = rt;
+ break;
+ }
+ }
+
+ if (!rt_found)
+ return NULL;
+
+ return rt_found;
+}
+
struct osmo_ss7_route *
ss7_combined_linkset_lookup_route(struct osmo_ss7_combined_linkset *clset, const struct osmo_ss7_route_label *rtlabel)
{
@@ -192,20 +235,20 @@
return rt;
}
- /* TODO: Check if the AS/linkset in rt is actually UP and can be
- * used, otherwise start ITU Q.704 section 7 "forced rerouting" prcoedure:
- * we need to pick a temporary dst (update the esls_table entry) while the
- * original one is DOWN. */
+ /* No current route available, try to find a new current route: */
- /* We need to pick a new AS/linkset from the combined linkset and cache
- * it so it is always used for this eSLS: */
- /* FIXME: for now we simply take the first AS in the combined linksed, to be improved later... */
- rt = llist_first_entry_or_null(&clset->routes, struct osmo_ss7_route, list);
+ /* No normal route selected yet: */
+ if (!eslse->normal_rt) {
+ rt = ss7_combined_linkset_select_route_roundrobin(clset);
+ /* Either a normal route was selected or none found: */
+ eslse->normal_rt = rt;
+ return rt;
+ }
- /* TODO: here we'd need to actually check if dst AS/linkset in the route
- * is actually UP, otherwise pick next one in the roundrobin list... */
+ /* Normal route unavailable and no alternative route (or unavailable too).
+ * start ITU Q.704 section 7 "forced rerouting" procedure: */
+ rt = ss7_combined_linkset_select_route_roundrobin(clset);
if (rt)
- clset->esls_table[esls].normal_rt = rt;
-
+ eslse->alt_rt = rt;
return rt;
}
diff --git a/src/osmo_ss7_hmrt.c b/src/osmo_ss7_hmrt.c
index 1e000b4..72d5adc 100644
--- a/src/osmo_ss7_hmrt.c
+++ b/src/osmo_ss7_hmrt.c
@@ -180,12 +180,6 @@
dpc, osmo_ss7_pointcode_print(inst, dpc), rt_name);
}
- if (osmo_ss7_as_down(as)) {
- LOGP(DLSS7, LOGL_ERROR, "Unable to route HMRT message: the AS %s is down\n",
- as->cfg.name);
- return -ENETDOWN;
- }
-
rate_ctr_inc2(as->ctrg, SS7_AS_CTR_TX_MSU_TOTAL);
switch (as->cfg.proto) {
diff --git a/src/ss7_combined_linkset.h b/src/ss7_combined_linkset.h
index e2f9c9d..b80a007 100644
--- a/src/ss7_combined_linkset.h
+++ b/src/ss7_combined_linkset.h
@@ -33,6 +33,7 @@
/*! list of \ref osmo_ss7_route */
struct llist_head routes;
unsigned int num_routes;
+ void *last_route_roundrobin;
struct {
uint32_t pc;
diff --git a/src/xua_snm.c b/src/xua_snm.c
index acdfe0c..1481178 100644
--- a/src/xua_snm.c
+++ b/src/xua_snm.c
@@ -347,7 +347,7 @@
.sls = 0,
};
- /* FIXME: don't just check for a route; but also check if the route is "active" */
+ /* Check if there's an "active" route available: */
if (ss7_instance_lookup_route(s7i, &rtlabel))
is_available = true;
diff --git a/tests/ss7/ss7_test.c b/tests/ss7/ss7_test.c
index 95fa1b1..f61ee0a 100644
--- a/tests/ss7/ss7_test.c
+++ b/tests/ss7/ss7_test.c
@@ -154,6 +154,7 @@
{
struct osmo_ss7_route_table *rtbl;
struct osmo_ss7_linkset *lset_a, *lset_b;
+ struct osmo_ss7_link *l_a, *l_b;
struct osmo_ss7_route *rt, *rt12, *rtdef;
struct osmo_ss7_route_label route_label;
@@ -173,8 +174,15 @@
lset_a = ss7_linkset_find_or_create(s7i, "a", 100);
OSMO_ASSERT(lset_a);
+ l_a = ss7_link_find_or_create(lset_a, 0);
+ OSMO_ASSERT(l_a);
+ l_a->cfg.adm_state = OSMO_SS7_LS_ENABLED;
+
lset_b = ss7_linkset_find_or_create(s7i, "b", 200);
OSMO_ASSERT(lset_b);
+ l_b = ss7_link_find_or_create(lset_b, 0);
+ OSMO_ASSERT(l_b);
+ l_b->cfg.adm_state = OSMO_SS7_LS_ENABLED;
/* route with full mask */
route_label = RT_LABEL(0, 12, 0);
diff --git a/tests/vty/osmo_stp_route_prio.vty b/tests/vty/osmo_stp_route_prio.vty
index 6f60d9a..2b7cec6 100644
--- a/tests/vty/osmo_stp_route_prio.vty
+++ b/tests/vty/osmo_stp_route_prio.vty
@@ -87,6 +87,6 @@
3.2.1/14 INACC 0 5 as2 UNAVAIL ? UNAVAIL
3.2.1/14 INACC 7 6 as1 UNAVAIL ? UNAVAIL
-OsmoSTP(config-cs7-rt)# ! NOW TEST LOOKUP WORKS AS DESIRED (as3 PICKED):
+OsmoSTP(config-cs7-rt)# ! NOW TEST LOOKUP FAILS AS EXPECTED (all route links are down):
OsmoSTP(config-cs7-rt)# do show cs7 instance 0 route-lookup 3.2.1 from 0.0.1 sls 0
-pc=6161=3.2.1 mask=0x3fff=7.255.7 via AS as3 proto=m3ua
+No route found for label 'OPC=1=0.0.1,DPC=6161=3.2.1,SLS=0'
--
To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/39391?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I928fb1ef5db6922f1386a188e3fbf9e70780f25d
Gerrit-Change-Number: 39391
Gerrit-PatchSet: 11
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-CC: laforge <laforge(a)osmocom.org>
1
0
[S] Change in libosmo-sigtran[master]: AS loadsharing: Introduce AS rate_ctr rx:msu:sls:*
by pespin 06 Mar '25
by pespin 06 Mar '25
06 Mar '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/39406?usp=email )
(
9 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: AS loadsharing: Introduce AS rate_ctr rx:msu:sls:*
......................................................................
AS loadsharing: Introduce AS rate_ctr rx:msu:sls:*
Related: SYS#7112
Change-Id: I695bd3933a116323db45ab7f45dcf539791139aa
---
M src/ipa.c
M src/m3ua.c
M src/osmo_ss7_as.c
M src/ss7_as.h
M src/sua.c
5 files changed, 43 insertions(+), 2 deletions(-)
Approvals:
daniel: Looks good to me, but someone else must approve
laforge: Looks good to me, but someone else must approve
Jenkins Builder: Verified
pespin: Looks good to me, approved
osmith: Looks good to me, but someone else must approve
diff --git a/src/ipa.c b/src/ipa.c
index 6ca5b50..4e0180c 100644
--- a/src/ipa.c
+++ b/src/ipa.c
@@ -238,6 +238,8 @@
}
rate_ctr_inc2(as->ctrg, SS7_AS_CTR_RX_MSU_TOTAL);
+ OSMO_ASSERT(sls <= 0xf);
+ rate_ctr_inc2(as->ctrg, SS7_AS_CTR_RX_MSU_SLS_0 + sls);
/* pull the IPA header */
msgb_pull_to_l2(msg);
diff --git a/src/m3ua.c b/src/m3ua.c
index 78f1aef..2f180c3 100644
--- a/src/m3ua.c
+++ b/src/m3ua.c
@@ -617,6 +617,8 @@
"%s(): M3UA data header: opc=%u=%s dpc=%u=%s\n",
__func__, xua->mtp.opc, osmo_ss7_pointcode_print(asp->inst, xua->mtp.opc),
xua->mtp.dpc, osmo_ss7_pointcode_print2(asp->inst, xua->mtp.dpc));
+ OSMO_ASSERT(xua->mtp.sls <= 0xf);
+ rate_ctr_inc2(as->ctrg, SS7_AS_CTR_RX_MSU_SLS_0 + xua->mtp.sls);
if (rctx_ie) {
/* remove ROUTE_CTX as in the routing case we want to add a new
diff --git a/src/osmo_ss7_as.c b/src/osmo_ss7_as.c
index 6aadb8f..d50d113 100644
--- a/src/osmo_ss7_as.c
+++ b/src/osmo_ss7_as.c
@@ -54,9 +54,26 @@
{ 0, NULL }
};
+#define SS7_AS_CTR_RX_MSU_SLS_STR "Number of MSU received on SLS "
static const struct rate_ctr_desc ss7_as_rcd[] = {
- [SS7_AS_CTR_RX_MSU_TOTAL] = { "rx:msu:total", "Total number of MSU received" },
- [SS7_AS_CTR_TX_MSU_TOTAL] = { "tx:msu:total", "Total number of MSU transmitted" },
+ [SS7_AS_CTR_RX_MSU_TOTAL] = { "rx:msu:total", "Total number of MSU received" },
+ [SS7_AS_CTR_RX_MSU_SLS_0] = { "rx:msu:sls:0", SS7_AS_CTR_RX_MSU_SLS_STR "0" },
+ [SS7_AS_CTR_RX_MSU_SLS_1] = { "rx:msu:sls:1", SS7_AS_CTR_RX_MSU_SLS_STR "1" },
+ [SS7_AS_CTR_RX_MSU_SLS_2] = { "rx:msu:sls:2", SS7_AS_CTR_RX_MSU_SLS_STR "2" },
+ [SS7_AS_CTR_RX_MSU_SLS_3] = { "rx:msu:sls:3", SS7_AS_CTR_RX_MSU_SLS_STR "3" },
+ [SS7_AS_CTR_RX_MSU_SLS_4] = { "rx:msu:sls:4", SS7_AS_CTR_RX_MSU_SLS_STR "4" },
+ [SS7_AS_CTR_RX_MSU_SLS_5] = { "rx:msu:sls:5", SS7_AS_CTR_RX_MSU_SLS_STR "5" },
+ [SS7_AS_CTR_RX_MSU_SLS_6] = { "rx:msu:sls:6", SS7_AS_CTR_RX_MSU_SLS_STR "6" },
+ [SS7_AS_CTR_RX_MSU_SLS_7] = { "rx:msu:sls:7", SS7_AS_CTR_RX_MSU_SLS_STR "7" },
+ [SS7_AS_CTR_RX_MSU_SLS_8] = { "rx:msu:sls:8", SS7_AS_CTR_RX_MSU_SLS_STR "8" },
+ [SS7_AS_CTR_RX_MSU_SLS_9] = { "rx:msu:sls:9", SS7_AS_CTR_RX_MSU_SLS_STR "9" },
+ [SS7_AS_CTR_RX_MSU_SLS_10] = { "rx:msu:sls:10", SS7_AS_CTR_RX_MSU_SLS_STR "10" },
+ [SS7_AS_CTR_RX_MSU_SLS_11] = { "rx:msu:sls:11", SS7_AS_CTR_RX_MSU_SLS_STR "11" },
+ [SS7_AS_CTR_RX_MSU_SLS_12] = { "rx:msu:sls:12", SS7_AS_CTR_RX_MSU_SLS_STR "12" },
+ [SS7_AS_CTR_RX_MSU_SLS_13] = { "rx:msu:sls:13", SS7_AS_CTR_RX_MSU_SLS_STR "13" },
+ [SS7_AS_CTR_RX_MSU_SLS_14] = { "rx:msu:sls:14", SS7_AS_CTR_RX_MSU_SLS_STR "14" },
+ [SS7_AS_CTR_RX_MSU_SLS_15] = { "rx:msu:sls:15", SS7_AS_CTR_RX_MSU_SLS_STR "15" },
+ [SS7_AS_CTR_TX_MSU_TOTAL] = { "tx:msu:total", "Total number of MSU transmitted" },
};
static const struct rate_ctr_group_desc ss7_as_rcgd = {
diff --git a/src/ss7_as.h b/src/ss7_as.h
index db7372c..67c0793 100644
--- a/src/ss7_as.h
+++ b/src/ss7_as.h
@@ -25,6 +25,22 @@
enum ss7_as_ctr {
SS7_AS_CTR_RX_MSU_TOTAL,
+ SS7_AS_CTR_RX_MSU_SLS_0,
+ SS7_AS_CTR_RX_MSU_SLS_1,
+ SS7_AS_CTR_RX_MSU_SLS_2,
+ SS7_AS_CTR_RX_MSU_SLS_3,
+ SS7_AS_CTR_RX_MSU_SLS_4,
+ SS7_AS_CTR_RX_MSU_SLS_5,
+ SS7_AS_CTR_RX_MSU_SLS_6,
+ SS7_AS_CTR_RX_MSU_SLS_7,
+ SS7_AS_CTR_RX_MSU_SLS_8,
+ SS7_AS_CTR_RX_MSU_SLS_9,
+ SS7_AS_CTR_RX_MSU_SLS_10,
+ SS7_AS_CTR_RX_MSU_SLS_11,
+ SS7_AS_CTR_RX_MSU_SLS_12,
+ SS7_AS_CTR_RX_MSU_SLS_13,
+ SS7_AS_CTR_RX_MSU_SLS_14,
+ SS7_AS_CTR_RX_MSU_SLS_15,
SS7_AS_CTR_TX_MSU_TOTAL,
};
diff --git a/src/sua.c b/src/sua.c
index e81c471..6d023cb 100644
--- a/src/sua.c
+++ b/src/sua.c
@@ -534,6 +534,8 @@
return rc;
rate_ctr_inc2(as->ctrg, SS7_AS_CTR_RX_MSU_TOTAL);
+ OSMO_ASSERT(xua->mtp.sls <= 0xf);
+ rate_ctr_inc2(as->ctrg, SS7_AS_CTR_RX_MSU_SLS_0 + xua->mtp.sls);
switch (xua->hdr.msg_type) {
case 0: /* Reserved, permitted by ETSI TS 101 592 5.2.3.2 */
@@ -564,6 +566,8 @@
return rc;
rate_ctr_inc2(as->ctrg, SS7_AS_CTR_RX_MSU_TOTAL);
+ OSMO_ASSERT(xua->mtp.sls <= 0xf);
+ rate_ctr_inc2(as->ctrg, SS7_AS_CTR_RX_MSU_SLS_0 + xua->mtp.sls);
switch (xua->hdr.msg_type) {
case 0: /* Reserved, permitted by ETSI TS 101 592 5.2.3.2 */
--
To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/39406?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I695bd3933a116323db45ab7f45dcf539791139aa
Gerrit-Change-Number: 39406
Gerrit-PatchSet: 10
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
[S] Change in libosmo-sigtran[master]: AS loadsharing: Introduce AS rate_ctr tx:msu:sls:*
by pespin 06 Mar '25
by pespin 06 Mar '25
06 Mar '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/39407?usp=email )
(
9 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: AS loadsharing: Introduce AS rate_ctr tx:msu:sls:*
......................................................................
AS loadsharing: Introduce AS rate_ctr tx:msu:sls:*
Related: SYS#7112
Change-Id: Ia446e11ea24ecb021a3dddf5547aa2b3cdbbe60b
---
M src/osmo_ss7_as.c
M src/osmo_ss7_hmrt.c
M src/ss7_as.h
3 files changed, 35 insertions(+), 0 deletions(-)
Approvals:
osmith: Looks good to me, but someone else must approve
laforge: Looks good to me, but someone else must approve
Jenkins Builder: Verified
daniel: Looks good to me, but someone else must approve
pespin: Looks good to me, approved
diff --git a/src/osmo_ss7_as.c b/src/osmo_ss7_as.c
index d50d113..ab40080 100644
--- a/src/osmo_ss7_as.c
+++ b/src/osmo_ss7_as.c
@@ -55,6 +55,7 @@
};
#define SS7_AS_CTR_RX_MSU_SLS_STR "Number of MSU received on SLS "
+#define SS7_AS_CTR_TX_MSU_SLS_STR "Number of MSU transmitted on SLS "
static const struct rate_ctr_desc ss7_as_rcd[] = {
[SS7_AS_CTR_RX_MSU_TOTAL] = { "rx:msu:total", "Total number of MSU received" },
[SS7_AS_CTR_RX_MSU_SLS_0] = { "rx:msu:sls:0", SS7_AS_CTR_RX_MSU_SLS_STR "0" },
@@ -74,6 +75,22 @@
[SS7_AS_CTR_RX_MSU_SLS_14] = { "rx:msu:sls:14", SS7_AS_CTR_RX_MSU_SLS_STR "14" },
[SS7_AS_CTR_RX_MSU_SLS_15] = { "rx:msu:sls:15", SS7_AS_CTR_RX_MSU_SLS_STR "15" },
[SS7_AS_CTR_TX_MSU_TOTAL] = { "tx:msu:total", "Total number of MSU transmitted" },
+ [SS7_AS_CTR_TX_MSU_SLS_0] = { "tx:msu:sls:0", SS7_AS_CTR_TX_MSU_SLS_STR "0" },
+ [SS7_AS_CTR_TX_MSU_SLS_1] = { "tx:msu:sls:1", SS7_AS_CTR_TX_MSU_SLS_STR "1" },
+ [SS7_AS_CTR_TX_MSU_SLS_2] = { "tx:msu:sls:2", SS7_AS_CTR_TX_MSU_SLS_STR "2" },
+ [SS7_AS_CTR_TX_MSU_SLS_3] = { "tx:msu:sls:3", SS7_AS_CTR_TX_MSU_SLS_STR "3" },
+ [SS7_AS_CTR_TX_MSU_SLS_4] = { "tx:msu:sls:4", SS7_AS_CTR_TX_MSU_SLS_STR "4" },
+ [SS7_AS_CTR_TX_MSU_SLS_5] = { "tx:msu:sls:5", SS7_AS_CTR_TX_MSU_SLS_STR "5" },
+ [SS7_AS_CTR_TX_MSU_SLS_6] = { "tx:msu:sls:6", SS7_AS_CTR_TX_MSU_SLS_STR "6" },
+ [SS7_AS_CTR_TX_MSU_SLS_7] = { "tx:msu:sls:7", SS7_AS_CTR_TX_MSU_SLS_STR "7" },
+ [SS7_AS_CTR_TX_MSU_SLS_8] = { "tx:msu:sls:8", SS7_AS_CTR_TX_MSU_SLS_STR "8" },
+ [SS7_AS_CTR_TX_MSU_SLS_9] = { "tx:msu:sls:9", SS7_AS_CTR_TX_MSU_SLS_STR "9" },
+ [SS7_AS_CTR_TX_MSU_SLS_10] = { "tx:msu:sls:10", SS7_AS_CTR_TX_MSU_SLS_STR "10" },
+ [SS7_AS_CTR_TX_MSU_SLS_11] = { "tx:msu:sls:11", SS7_AS_CTR_TX_MSU_SLS_STR "11" },
+ [SS7_AS_CTR_TX_MSU_SLS_12] = { "tx:msu:sls:12", SS7_AS_CTR_TX_MSU_SLS_STR "12" },
+ [SS7_AS_CTR_TX_MSU_SLS_13] = { "tx:msu:sls:13", SS7_AS_CTR_TX_MSU_SLS_STR "13" },
+ [SS7_AS_CTR_TX_MSU_SLS_14] = { "tx:msu:sls:14", SS7_AS_CTR_TX_MSU_SLS_STR "14" },
+ [SS7_AS_CTR_TX_MSU_SLS_15] = { "tx:msu:sls:15", SS7_AS_CTR_TX_MSU_SLS_STR "15" },
};
static const struct rate_ctr_group_desc ss7_as_rcgd = {
diff --git a/src/osmo_ss7_hmrt.c b/src/osmo_ss7_hmrt.c
index 72d5adc..675b231 100644
--- a/src/osmo_ss7_hmrt.c
+++ b/src/osmo_ss7_hmrt.c
@@ -181,6 +181,8 @@
}
rate_ctr_inc2(as->ctrg, SS7_AS_CTR_TX_MSU_TOTAL);
+ OSMO_ASSERT(xua->mtp.sls <= 0xf);
+ rate_ctr_inc2(as->ctrg, SS7_AS_CTR_TX_MSU_SLS_0 + xua->mtp.sls);
switch (as->cfg.proto) {
case OSMO_SS7_ASP_PROT_M3UA:
diff --git a/src/ss7_as.h b/src/ss7_as.h
index 67c0793..6a2b649 100644
--- a/src/ss7_as.h
+++ b/src/ss7_as.h
@@ -42,6 +42,22 @@
SS7_AS_CTR_RX_MSU_SLS_14,
SS7_AS_CTR_RX_MSU_SLS_15,
SS7_AS_CTR_TX_MSU_TOTAL,
+ SS7_AS_CTR_TX_MSU_SLS_0,
+ SS7_AS_CTR_TX_MSU_SLS_1,
+ SS7_AS_CTR_TX_MSU_SLS_2,
+ SS7_AS_CTR_TX_MSU_SLS_3,
+ SS7_AS_CTR_TX_MSU_SLS_4,
+ SS7_AS_CTR_TX_MSU_SLS_5,
+ SS7_AS_CTR_TX_MSU_SLS_6,
+ SS7_AS_CTR_TX_MSU_SLS_7,
+ SS7_AS_CTR_TX_MSU_SLS_8,
+ SS7_AS_CTR_TX_MSU_SLS_9,
+ SS7_AS_CTR_TX_MSU_SLS_10,
+ SS7_AS_CTR_TX_MSU_SLS_11,
+ SS7_AS_CTR_TX_MSU_SLS_12,
+ SS7_AS_CTR_TX_MSU_SLS_13,
+ SS7_AS_CTR_TX_MSU_SLS_14,
+ SS7_AS_CTR_TX_MSU_SLS_15,
};
struct osmo_ss7_as {
--
To view, visit https://gerrit.osmocom.org/c/libosmo-sigtran/+/39407?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: Ia446e11ea24ecb021a3dddf5547aa2b3cdbbe60b
Gerrit-Change-Number: 39407
Gerrit-PatchSet: 10
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0