pespin has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/libosmo-sigtran/+/39408?usp=email )


Change subject: Implement ASP loadsharing
......................................................................

Implement ASP loadsharing

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, 223 insertions(+), 11 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmo-sigtran 
refs/changes/08/39408/1

diff --git a/src/osmo_ss7_as.c b/src/osmo_ss7_as.c
index eb655ca..ccf929f 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"
@@ -153,6 +154,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;
@@ -254,6 +263,83 @@
        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)) & 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 */
+                       aeslse->alt_asp = NULL;
+                       return asp;
+               }
+               /* We can transmit over alternative ASP: */
+               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;
+               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;
+       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)
 {
@@ -278,7 +364,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;

@@ -287,9 +373,45 @@
                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);
+       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 6b404b3..852aca3 100644
--- a/src/osmo_ss7_vty.c
+++ b/src/osmo_ss7_vty.c
@@ -1916,10 +1916,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")
 {
@@ -1930,6 +1929,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",
@@ -1939,6 +1968,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;
 }

@@ -2157,9 +2202,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", 
osmo_ss7_as_traffic_mode_name(as->cfg.mode));
+               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%s", 
as->cfg.loadshare.opc_shift, VTY_NEWLINE);
+                       }
+               }
+               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);
@@ -3092,7 +3149,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 504818c..dbeb61e 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 */
@@ -28,6 +29,15 @@
        SS7_AS_CTR_TX_MSU_TOTAL,
 };

+#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;
@@ -45,6 +55,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;
@@ -64,8 +77,23 @@
 
                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);
+
 #define LOGPAS(as, subsys, level, fmt, args ...) \
        _LOGSS7((as)->inst, subsys, level, "as-%s: " fmt, (as)->cfg.name, ## 
args)
diff --git a/src/xua_as_fsm.c b/src/xua_as_fsm.c
index 5c2c5e0..e435970 100644
--- a/src/xua_as_fsm.c
+++ b/src/xua_as_fsm.c
@@ -150,7 +150,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 cb24560..dcde514 100644
--- a/tests/vty/osmo_stp_test.vty
+++ b/tests/vty/osmo_stp_test.vty
@@ -344,8 +344,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
@@ -361,6 +363,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: newchange
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I5f47e40b70ed566034cd1533b71e21fc03e94f6c
Gerrit-Change-Number: 39408
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <[email protected]>

Reply via email to