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