<p>lynxis lazus has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/23758">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">gprs_ns2: implement local update weight procedure<br><br>When changing the bind ip-sns weight, initiate a<br>SNS UPDATE WEIGHT procedure to inform the other side.<br><br>Related: OS#5036<br>Change-Id: If034ac371a604bab5e58beadb784382c8b97cca3<br>---<br>M src/gb/gprs_ns2.c<br>M src/gb/gprs_ns2_internal.h<br>M src/gb/gprs_ns2_sns.c<br>M src/gb/gprs_ns2_vty.c<br>M tests/gb/gprs_ns2_vty.vty<br>5 files changed, 298 insertions(+), 10 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/58/23758/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c</span><br><span>index 1148d6f..2f8396e 100644</span><br><span>--- a/src/gb/gprs_ns2.c</span><br><span>+++ b/src/gb/gprs_ns2.c</span><br><span>@@ -1400,6 +1400,7 @@</span><br><span>    nsi->timeout[NS_TOUT_TSNS_PROV] = 3; /* 1..10 */</span><br><span>  nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES] = 3;</span><br><span>      nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES] = 3;</span><br><span style="color: hsl(120, 100%, 40%);">+     nsi->timeout[NS_TOUT_TSNS_PROCEDURES_RETRIES] = 3;</span><br><span> </span><br><span>    return nsi;</span><br><span> }</span><br><span>diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h</span><br><span>index 70e212a..8b02a88 100644</span><br><span>--- a/src/gb/gprs_ns2_internal.h</span><br><span>+++ b/src/gb/gprs_ns2_internal.h</span><br><span>@@ -46,8 +46,8 @@</span><br><span> struct gprs_ns2_vc_driver;</span><br><span> struct gprs_ns2_vc_bind;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#define NS_TIMERS_COUNT 10</span><br><span style="color: hsl(0, 100%, 40%);">-#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries|tsns-prov|tsns-size-retries|tsns-config-retries)"</span><br><span style="color: hsl(120, 100%, 40%);">+#define NS_TIMERS_COUNT 11</span><br><span style="color: hsl(120, 100%, 40%);">+#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries|tsns-prov|tsns-size-retries|tsns-config-retries|tsns-procedures-retries)"</span><br><span> #define NS_TIMERS_HELP       \</span><br><span>    "(un)blocking Timer (Tns-block) timeout\n"            \</span><br><span>    "(un)blocking Timer (Tns-block) number of retries\n"  \</span><br><span>@@ -59,6 +59,7 @@</span><br><span>        "SNS Provision Timer (Tsns-prov) timeout\n"           \</span><br><span>    "SNS Size number of retries\n"                                \</span><br><span>    "SNS Config number of retries\n"                      \</span><br><span style="color: hsl(120, 100%, 40%);">+     "SNS Procedures number of retries\n"                  \</span><br><span> </span><br><span> /* Educated guess - LLC user payload is 1500 bytes plus possible headers */</span><br><span> #define NS_ALLOC_SIZE   3072</span><br><span>@@ -75,6 +76,7 @@</span><br><span>     NS_TOUT_TSNS_PROV,</span><br><span>   NS_TOUT_TSNS_SIZE_RETRIES,</span><br><span>   NS_TOUT_TSNS_CONFIG_RETRIES,</span><br><span style="color: hsl(120, 100%, 40%);">+  NS_TOUT_TSNS_PROCEDURES_RETRIES,</span><br><span> };</span><br><span> </span><br><span> enum nsvc_timer_mode {</span><br><span>diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c</span><br><span>index c6e80af..a19171f 100644</span><br><span>--- a/src/gb/gprs_ns2_sns.c</span><br><span>+++ b/src/gb/gprs_ns2_sns.c</span><br><span>@@ -75,6 +75,7 @@</span><br><span>    GPRS_SNS_ST_CONFIGURED,</span><br><span>      GPRS_SNS_ST_SGSN_WAIT_CONFIG,           /* !< SGSN role: Wait for CONFIG from BSS */</span><br><span>      GPRS_SNS_ST_SGSN_WAIT_CONFIG_ACK,       /* !< SGSN role: Wait for CONFIG-ACK from BSS */</span><br><span style="color: hsl(120, 100%, 40%);">+   GPRS_SNS_ST_LOCAL_PROCEDURE,            /*!< in process of a ADD/DEL/UPDATE procedure towards SGSN (BSS->SGSN) */</span><br><span> };</span><br><span> </span><br><span> enum gprs_sns_event {</span><br><span>@@ -92,6 +93,7 @@</span><br><span>       GPRS_SNS_EV_REQ_NSVC_ALIVE,             /*!< a NS-VC became alive */</span><br><span>      GPRS_SNS_EV_REQ_ADD_BIND,               /*!< add a new local bind to this NSE */</span><br><span>  GPRS_SNS_EV_REQ_DELETE_BIND,            /*!< remove a local bind from this NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+  GPRS_SNS_EV_REQ_CHANGE_WEIGHT,          /*!< a bind changed its weight */</span><br><span> };</span><br><span> </span><br><span> static const struct value_string gprs_sns_event_names[] = {</span><br><span>@@ -109,17 +111,40 @@</span><br><span>        { GPRS_SNS_EV_REQ_NSVC_ALIVE,           "REQ_NSVC_ALIVE"},</span><br><span>         { GPRS_SNS_EV_REQ_ADD_BIND,             "REQ_ADD_BIND"},</span><br><span>   { GPRS_SNS_EV_REQ_DELETE_BIND,          "REQ_DELETE_BIND"},</span><br><span style="color: hsl(120, 100%, 40%);">+ { GPRS_SNS_EV_REQ_CHANGE_WEIGHT,        "REQ_UPDATE_WEIGHT"},</span><br><span>      { 0, NULL }</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+enum sns_procedure {</span><br><span style="color: hsl(120, 100%, 40%);">+   SNS_NONE,               /*!< used as invalid/idle value */</span><br><span style="color: hsl(120, 100%, 40%);">+ SNS_ADD,</span><br><span style="color: hsl(120, 100%, 40%);">+      SNS_DEL,</span><br><span style="color: hsl(120, 100%, 40%);">+      SNS_CHANGE_WEIGHT,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum sns_bind_flag {</span><br><span style="color: hsl(120, 100%, 40%);">+        SNS_BIND_CHANGE_REQ,            /*!< need to change */</span><br><span style="color: hsl(120, 100%, 40%);">+     SNS_BIND_CHANGE_IN_PROGRESS,    /*!< change is going on */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct sns_endpoint {</span><br><span>         struct llist_head list;</span><br><span>      struct osmo_sockaddr saddr;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ns2_sns_procedure {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ns2_sns_bind *bind;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns_ie_ip4_elem *ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns_ie_ip6_elem *ip6;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum sns_procedure procedure;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t trans_id;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ns2_sns_bind {</span><br><span>        struct llist_head list;</span><br><span>      struct gprs_ns2_vc_bind *bind;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t change_weight_state;</span><br><span> };</span><br><span> </span><br><span> struct ns2_sns_state {</span><br><span>@@ -170,14 +195,46 @@</span><br><span>     /* remote configuration as received */</span><br><span>       struct gprs_ns_ie_ip6_elem *ip6_remote;</span><br><span>      unsigned int num_ip6_remote;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ns2_sns_procedure current_procedure;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void ns2_procedure_set_endpoint(struct ns2_sns_state *gss);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)</span><br><span> {</span><br><span>    struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span>    return gss->nse;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static struct gprs_ns_ie_ip4_elem *ip4_elem_by_saddr(struct gprs_ns_ie_ip4_elem *ip4, size_t num, const struct osmo_sockaddr *saddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (saddr->u.sa.sa_family != AF_INET)</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for (size_t i = 0; i < num; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (ip4[i].ip_addr == saddr->u.sin.sin_addr.s_addr &&</span><br><span style="color: hsl(120, 100%, 40%);">+                              ip4->udp_port == saddr->u.sin.sin_port)</span><br><span style="color: hsl(120, 100%, 40%);">+                 return &ip4[i];</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gprs_ns_ie_ip6_elem *ip6_elem_by_saddr(struct gprs_ns_ie_ip6_elem *ip6, size_t num, const struct osmo_sockaddr *saddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    if (saddr->u.sa.sa_family != AF_INET6)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for (size_t i = 0; i < num; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (memcmp(&ip6[i].ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr)) == 0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+                             ip6->udp_port == saddr->u.sin6.sin6_port)</span><br><span style="color: hsl(120, 100%, 40%);">+                       return &ip6[i];</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* helper function to compute the sum of all (data or signaling) weights */</span><br><span> static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,</span><br><span>                         bool data_weight)</span><br><span>@@ -298,6 +355,11 @@</span><br><span>   osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_NO_NSVC, NULL);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void ns2_clear_procedures(struct ns2_sns_state *gss)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   memset(&gss->current_procedure, 0, sizeof(struct ns2_sns_state));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void ns2_clear_ipv46_entries_local(struct ns2_sns_state *gss)</span><br><span> {</span><br><span>   TALLOC_FREE(gss->ip4_local);</span><br><span>@@ -896,6 +958,7 @@</span><br><span>        if (old_state != GPRS_SNS_ST_BSS_SIZE)</span><br><span>               gss->N = 0;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    ns2_clear_procedures(gss);</span><br><span>   gss->alive = false;</span><br><span> </span><br><span>   ns2_sns_compute_local_ep_from_binds(fi);</span><br><span>@@ -1372,7 +1435,102 @@</span><br><span>   if (gss->sns_nsvc->sns_only)</span><br><span>           gprs_ns2_free_nsvc(gss->sns_nsvc);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (old_state != GPRS_SNS_ST_LOCAL_PROCEDURE)</span><br><span style="color: hsl(120, 100%, 40%);">+         ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ns2_sns_st_local_procedure_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ns2_sns_bind *sns_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (gss->current_procedure.procedure == SNS_NONE) {</span><br><span style="color: hsl(120, 100%, 40%);">+                gss->N = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                /* select the next procedure */</span><br><span style="color: hsl(120, 100%, 40%);">+               llist_for_each_entry(sns_bind, &gss->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (sns_bind->change_weight_state & S(SNS_BIND_CHANGE_REQ)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          sns_bind->change_weight_state = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                         gss->current_procedure.bind = sns_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+                            gss->current_procedure.procedure = SNS_CHANGE_WEIGHT;</span><br><span style="color: hsl(120, 100%, 40%);">+                              ns2_procedure_set_endpoint(gss);</span><br><span style="color: hsl(120, 100%, 40%);">+                              break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (gss->current_procedure.procedure == SNS_NONE) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* nothing to do */</span><br><span style="color: hsl(120, 100%, 40%);">+                   osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             gss->current_procedure.trans_id++;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (gss->current_procedure.trans_id == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                  gss->current_procedure.trans_id = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* also takes care of retransmitting */</span><br><span style="color: hsl(120, 100%, 40%);">+       switch (gss->current_procedure.procedure) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_ADD:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (gss->ip == IPv4)</span><br><span style="color: hsl(120, 100%, 40%);">+                       ns2_tx_sns_add(gss->sns_nsvc, gss->current_procedure.trans_id, gss->current_procedure.ip4, 1, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              else</span><br><span style="color: hsl(120, 100%, 40%);">+                  ns2_tx_sns_add(gss->sns_nsvc, gss->current_procedure.trans_id, NULL, 0, gss->current_procedure.ip6, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+               if (gss->ip == IPv4)</span><br><span style="color: hsl(120, 100%, 40%);">+                       ns2_tx_sns_change_weight(gss->sns_nsvc, gss->current_procedure.trans_id, gss->current_procedure.ip4, 1, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+            else</span><br><span style="color: hsl(120, 100%, 40%);">+                  ns2_tx_sns_change_weight(gss->sns_nsvc, gss->current_procedure.trans_id, NULL, 0, gss->current_procedure.ip6, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SNS_DEL:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (gss->ip == IPv4)</span><br><span style="color: hsl(120, 100%, 40%);">+                       ns2_tx_sns_del(gss->sns_nsvc, gss->current_procedure.trans_id, gss->current_procedure.ip4, 1, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              else</span><br><span style="color: hsl(120, 100%, 40%);">+                  ns2_tx_sns_del(gss->sns_nsvc, gss->current_procedure.trans_id, NULL, 0, gss->current_procedure.ip6, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ns2_sns_st_local_procedure(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns2_inst *nsi = nse->nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct tlv_parsed *tp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t trans_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case GPRS_SNS_EV_RX_ADD:</span><br><span style="color: hsl(120, 100%, 40%);">+              ns2_sns_st_configured_add(fi, gss, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_RX_DELETE:</span><br><span style="color: hsl(120, 100%, 40%);">+           ns2_sns_st_configured_delete(fi, gss, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_RX_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+            ns2_sns_st_configured_change(fi, gss, tp);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_RX_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+              /* presence of trans_id is already checked here */</span><br><span style="color: hsl(120, 100%, 40%);">+            trans_id = tlvp_val8(tp, NS_IE_TRANS_ID, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (trans_id != gss->current_procedure.trans_id) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOGPFSML(fi, LOGL_DEBUG, "NSEI=%u Rx SNS ACK with invalid transaction id %d. Valid %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            nse->nsei, trans_id, gss->current_procedure.trans_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                 break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!TLVP_PRESENT(tp, NS_IE_CAUSE)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 gss->current_procedure.procedure = SNS_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* everything ok, local_procedure_onenter() will check if there are more procedures required */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);</span><br><span style="color: hsl(120, 100%, 40%);">+                     return;</span><br><span style="color: hsl(120, 100%, 40%);">+               } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* what happend on error cause? return to size? */</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span> }</span><br><span> </span><br><span> static const struct osmo_fsm_state ns2_sns_bss_states[] = {</span><br><span>@@ -1419,11 +1577,27 @@</span><br><span>                           S(GPRS_SNS_EV_RX_CHANGE_WEIGHT) |</span><br><span>                            S(GPRS_SNS_EV_REQ_NSVC_ALIVE),</span><br><span>              .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |</span><br><span style="color: hsl(0, 100%, 40%);">-                           S(GPRS_SNS_ST_BSS_SIZE),</span><br><span style="color: hsl(120, 100%, 40%);">+                              S(GPRS_SNS_ST_BSS_SIZE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(GPRS_SNS_ST_LOCAL_PROCEDURE),</span><br><span>            .name = "CONFIGURED",</span><br><span>              .action = ns2_sns_st_configured,</span><br><span>             .onenter = ns2_sns_st_configured_onenter,</span><br><span>    },</span><br><span style="color: hsl(120, 100%, 40%);">+    [GPRS_SNS_ST_LOCAL_PROCEDURE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .in_event_mask = S(GPRS_SNS_EV_RX_ADD) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(GPRS_SNS_EV_RX_DELETE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                            S(GPRS_SNS_EV_RX_CHANGE_WEIGHT) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(GPRS_SNS_EV_RX_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(GPRS_SNS_EV_REQ_NSVC_ALIVE),</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(GPRS_SNS_ST_BSS_SIZE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(GPRS_SNS_ST_CONFIGURED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                           S(GPRS_SNS_ST_LOCAL_PROCEDURE),</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "LOCAL_PROCEDURE",</span><br><span style="color: hsl(120, 100%, 40%);">+          .action = ns2_sns_st_local_procedure,</span><br><span style="color: hsl(120, 100%, 40%);">+         .onenter = ns2_sns_st_local_procedure_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> };</span><br><span> </span><br><span> static int ns2_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)</span><br><span>@@ -1462,6 +1636,14 @@</span><br><span>             LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config succeeded but no NS-VC came online. Selecting next IP-SNS endpoint.\n", nse->nsei);</span><br><span>            osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);</span><br><span>           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_ST_LOCAL_PROCEDURE:</span><br><span style="color: hsl(120, 100%, 40%);">+             if (gss->N >= nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOGPFSML(fi, LOGL_ERROR, "NSE %d: Procedure retries failed. Restarting NSE.\n", nse->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span>       }</span><br><span>    return 0;</span><br><span> }</span><br><span>@@ -1518,6 +1700,21 @@</span><br><span>              /* if this is the last bind, the free_nsvc() will trigger a reselection */</span><br><span>           talloc_free(sbind);</span><br><span>          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_EV_REQ_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+           sbind = data;</span><br><span style="color: hsl(120, 100%, 40%);">+         switch (fi->state) {</span><br><span style="color: hsl(120, 100%, 40%);">+               case GPRS_SNS_ST_UNCONFIGURED:</span><br><span style="color: hsl(120, 100%, 40%);">+                case GPRS_SNS_ST_BSS_SIZE:</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* unconfigured or size don't need a procedure */</span><br><span style="color: hsl(120, 100%, 40%);">+                 break;</span><br><span style="color: hsl(120, 100%, 40%);">+                /* all other states */</span><br><span style="color: hsl(120, 100%, 40%);">+                default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* change the flag */</span><br><span style="color: hsl(120, 100%, 40%);">+                 sbind->change_weight_state |= S(SNS_BIND_CHANGE_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nse->nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span>       }</span><br><span> }</span><br><span> </span><br><span>@@ -1577,6 +1774,7 @@</span><br><span>   .allstate_event_mask = S(GPRS_SNS_EV_REQ_NO_NSVC) |</span><br><span>                         S(GPRS_SNS_EV_REQ_SELECT_ENDPOINT) |</span><br><span>                         S(GPRS_SNS_EV_REQ_ADD_BIND) |</span><br><span style="color: hsl(120, 100%, 40%);">+                         S(GPRS_SNS_EV_REQ_CHANGE_WEIGHT) |</span><br><span>                           S(GPRS_SNS_EV_REQ_DELETE_BIND),</span><br><span>       .allstate_action = ns2_sns_st_all_action_bss,</span><br><span>        .cleanup = NULL,</span><br><span>@@ -1911,7 +2109,7 @@</span><br><span>             return;</span><br><span> </span><br><span>  gss = nse->bss_sns_fi->priv;</span><br><span style="color: hsl(0, 100%, 40%);">-      if(nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED)</span><br><span style="color: hsl(120, 100%, 40%);">+    if(nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED && nse->bss_sns_fi->state != GPRS_SNS_ST_LOCAL_PROCEDURE)</span><br><span>            return;</span><br><span> </span><br><span>  if (alive == gss->alive)</span><br><span>@@ -2005,12 +2203,71 @@</span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Update SNS weights</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] nsvc the NSVC which should be updated</span><br><span style="color: hsl(120, 100%, 40%);">+/* Update SNS weights for a bind (local endpoint). */</span><br><span style="color: hsl(120, 100%, 40%);">+static void ns2_procedure_set_endpoint(struct ns2_sns_state *gss) {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_sockaddr *local = NULL, *remote = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct osmo_sockaddr *sa;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gprs_ns_ie_ip4_elem *ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gprs_ns_ie_ip6_elem *ip6;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* TODO: ensure this bind is already added! */</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(gss->current_procedure.procedure != SNS_NONE);</span><br><span style="color: hsl(120, 100%, 40%);">+ sa = gprs_ns2_ip_bind_sockaddr(gss->current_procedure.bind->bind);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!sa)</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (sa->u.sa.sa_family) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case AF_INET:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (sa->u.sin.sin_addr.s_addr == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (osmo_sockaddr_local_ip(local, &gss->initial->saddr))</span><br><span style="color: hsl(120, 100%, 40%);">+                            return;</span><br><span style="color: hsl(120, 100%, 40%);">+                       ip4 = ip4_elem_by_saddr(gss->ip4_local, gss->num_ip4_local, local);</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ip4 = ip4_elem_by_saddr(gss->ip4_local, gss->num_ip4_local, sa);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* TODO: check if this bind is about to be added */</span><br><span style="color: hsl(120, 100%, 40%);">+           OSMO_ASSERT(ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+             gss->current_procedure.ip4 = ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case AF_INET6:</span><br><span style="color: hsl(120, 100%, 40%);">+                // in6addr_any</span><br><span style="color: hsl(120, 100%, 40%);">+                if (memcmp(&sa->u.sin6.sin6_addr, &in6addr_any, sizeof(struct in6_addr))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (osmo_sockaddr_local_ip(local, remote))</span><br><span style="color: hsl(120, 100%, 40%);">+                            return;</span><br><span style="color: hsl(120, 100%, 40%);">+                       ip6 = ip6_elem_by_saddr(gss->ip6_local, gss->num_ip6_local, local);</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ip6 = ip6_elem_by_saddr(gss->ip6_local, gss->num_ip6_local, sa);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             OSMO_ASSERT(ip6);</span><br><span style="color: hsl(120, 100%, 40%);">+             gss->current_procedure.ip6 = ip6;</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(false);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Update SNS weights for a bind (local endpoint).</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] bind the bind which has been updated</span><br><span>  */</span><br><span> void ns2_sns_update_weights(struct gprs_ns2_vc_bind *bind)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        /* TODO: implement weights after binds per sns implemented */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_bind *sns_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ns2_sns_state *gss;</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_for_each_entry(nse, &bind->nsi->nse, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!nse->bss_sns_fi)</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           gss = nse->bss_sns_fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+            llist_for_each_entry(sns_bind, &gss->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (sns_bind->bind == bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              osmo_fsm_inst_dispatch(gss->nse->bss_sns_fi, GPRS_SNS_EV_REQ_CHANGE_WEIGHT, sns_bind);</span><br><span style="color: hsl(120, 100%, 40%);">+                          break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> }</span><br><span> </span><br><span> </span><br><span>@@ -2145,6 +2402,22 @@</span><br><span>              .action = ns2_sns_st_configured,</span><br><span>             .onenter = ns2_sns_st_configured_onenter,</span><br><span>    },</span><br><span style="color: hsl(120, 100%, 40%);">+    [GPRS_SNS_ST_LOCAL_PROCEDURE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .in_event_mask = S(GPRS_SNS_EV_RX_ADD) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(GPRS_SNS_EV_RX_DELETE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                            S(GPRS_SNS_EV_RX_CHANGE_WEIGHT) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(GPRS_SNS_EV_RX_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(GPRS_SNS_EV_REQ_CHANGE_WEIGHT) |</span><br><span style="color: hsl(120, 100%, 40%);">+                            S(GPRS_SNS_EV_REQ_NSVC_ALIVE),</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(GPRS_SNS_ST_BSS_SIZE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(GPRS_SNS_ST_CONFIGURED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                           S(GPRS_SNS_ST_LOCAL_PROCEDURE),</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "LOCAL_PROCEDURE",</span><br><span style="color: hsl(120, 100%, 40%);">+          /* shared with BSS side; once configured there's no difference */</span><br><span style="color: hsl(120, 100%, 40%);">+         .action = ns2_sns_st_local_procedure,</span><br><span style="color: hsl(120, 100%, 40%);">+         .onenter = ns2_sns_st_local_procedure_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span> };</span><br><span> </span><br><span> static int ns2_sns_fsm_sgsn_timer_cb(struct osmo_fsm_inst *fi)</span><br><span>@@ -2166,11 +2439,20 @@</span><br><span>     case 4:</span><br><span>              LOGPFSML(fi, LOGL_ERROR, "NSE %d: Config succeeded but no NS-VC came online.\n", nse->nsei);</span><br><span>            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GPRS_SNS_ST_LOCAL_PROCEDURE:</span><br><span style="color: hsl(120, 100%, 40%);">+             if (gss->N >= nsi->timeout[NS_TOUT_TSNS_PROCEDURES_RETRIES]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOGPFSML(fi, LOGL_ERROR, "NSE %d: SNS Procedure retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nsi->timeout[NS_TOUT_TSNS_PROV],</span><br><span style="color: hsl(120, 100%, 40%);">+                                          fi->T);</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span>       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* allstate-action for SGSN role */</span><br><span> static void ns2_sns_st_all_action_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span> {</span><br><span>@@ -2238,6 +2520,7 @@</span><br><span>                       /* clear all state */</span><br><span>                        osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);</span><br><span>                         gss->N = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                        ns2_clear_procedures(gss);</span><br><span>                   ns2_clear_ipv46_entries_local(gss);</span><br><span>                  ns2_clear_ipv46_entries_remote(gss);</span><br><span>                         llist_for_each_entry_safe(nsvc, nsvc2, &gss->nse->nsvc, list) {</span><br><span>@@ -2272,6 +2555,7 @@</span><br><span>    .allstate_event_mask = S(GPRS_SNS_EV_RX_SIZE) |</span><br><span>                             S(GPRS_SNS_EV_REQ_NO_NSVC) |</span><br><span>                         S(GPRS_SNS_EV_REQ_ADD_BIND) |</span><br><span style="color: hsl(120, 100%, 40%);">+                         S(GPRS_SNS_EV_REQ_CHANGE_WEIGHT) |</span><br><span>                           S(GPRS_SNS_EV_REQ_DELETE_BIND),</span><br><span>       .allstate_action = ns2_sns_st_all_action_sgsn,</span><br><span>       .cleanup = NULL,</span><br><span>diff --git a/src/gb/gprs_ns2_vty.c b/src/gb/gprs_ns2_vty.c</span><br><span>index b678db4..169b891 100644</span><br><span>--- a/src/gb/gprs_ns2_vty.c</span><br><span>+++ b/src/gb/gprs_ns2_vty.c</span><br><span>@@ -100,6 +100,7 @@</span><br><span>      { 7, "tsns-prov" },</span><br><span>        { 8, "tsns-size-retries" },</span><br><span>        { 9, "tsns-config-retries" },</span><br><span style="color: hsl(120, 100%, 40%);">+       {10, "tsns-procedures-retries" },</span><br><span>  { 0, NULL }</span><br><span> };</span><br><span> </span><br><span>diff --git a/tests/gb/gprs_ns2_vty.vty b/tests/gb/gprs_ns2_vty.vty</span><br><span>index 78c7e78..1c78069 100644</span><br><span>--- a/tests/gb/gprs_ns2_vty.vty</span><br><span>+++ b/tests/gb/gprs_ns2_vty.vty</span><br><span>@@ -17,7 +17,7 @@</span><br><span> OsmoNSdummy(config)# ns</span><br><span> OsmoNSdummy(config-ns)# list</span><br><span> ...</span><br><span style="color: hsl(0, 100%, 40%);">-  timer (tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries|tsns-prov|tsns-size-retries|tsns-config-retries) <0-65535></span><br><span style="color: hsl(120, 100%, 40%);">+  timer (tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries|tsns-prov|tsns-size-retries|tsns-config-retries|tsns-procedures-retries) <0-65535></span><br><span>   nse <0-65535> [ip-sns-role-sgsn]</span><br><span>   no nse <0-65535></span><br><span>   bind (fr|udp) ID</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/23758">change 23758</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/libosmocore/+/23758"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: If034ac371a604bab5e58beadb784382c8b97cca3 </div>
<div style="display:none"> Gerrit-Change-Number: 23758 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: lynxis lazus <lynxis@fe80.eu> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>