<p>lynxis lazus <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/23187">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Jenkins Builder: Verified
laforge: Looks good to me, approved
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">gprs_ns2_sns: implement local change weight procedure<br><br>When changing the bind ip-sns weight, initiate a<br>SNS CHANGE WEIGHT procedure to inform the other side.<br><br>Related: OS#5036<br>Change-Id: Icec4dabb46bc198f68f91bfe09ba279fbe68d454<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, 460 insertions(+), 9 deletions(-)<br><br></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 a895e3d..adf3b32 100644</span><br><span>--- a/src/gb/gprs_ns2.c</span><br><span>+++ b/src/gb/gprs_ns2.c</span><br><span>@@ -1440,6 +1440,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 ca6bfb7..afe6b69 100644</span><br><span>--- a/src/gb/gprs_ns2_internal.h</span><br><span>+++ b/src/gb/gprs_ns2_internal.h</span><br><span>@@ -60,8 +60,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>@@ -73,6 +73,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>@@ -89,6 +90,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>@@ -336,6 +338,7 @@</span><br><span> NS2_SNS_EV_REQ_NSVC_ALIVE, /*!< a NS-VC became alive */</span><br><span> NS2_SNS_EV_REQ_ADD_BIND, /*!< add a new local bind to this NSE */</span><br><span> NS2_SNS_EV_REQ_DELETE_BIND, /*!< remove a local bind from this NSE */</span><br><span style="color: hsl(120, 100%, 40%);">+ NS2_SNS_EV_REQ_CHANGE_WEIGHT, /*!< a bind changed its weight */</span><br><span> };</span><br><span> </span><br><span> enum ns2_cs ns2_create_vc(struct gprs_ns2_vc_bind *bind,</span><br><span>diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c</span><br><span>index 43e4920..9e30f62 100644</span><br><span>--- a/src/gb/gprs_ns2_sns.c</span><br><span>+++ b/src/gb/gprs_ns2_sns.c</span><br><span>@@ -70,6 +70,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/CHANGE procedure towards SGSN (BSS->SGSN) */</span><br><span> };</span><br><span> </span><br><span> static const struct value_string gprs_sns_event_names[] = {</span><br><span>@@ -88,9 +89,17 @@</span><br><span> { NS2_SNS_EV_REQ_NSVC_ALIVE, "REQ_NSVC_ALIVE"},</span><br><span> { NS2_SNS_EV_REQ_ADD_BIND, "REQ_ADD_BIND"},</span><br><span> { NS2_SNS_EV_REQ_DELETE_BIND, "REQ_DELETE_BIND"},</span><br><span style="color: hsl(120, 100%, 40%);">+ { NS2_SNS_EV_REQ_CHANGE_WEIGHT, "REQ_CHANGE_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_PROC_NONE, /*!< used as invalid/idle value */</span><br><span style="color: hsl(120, 100%, 40%);">+ SNS_PROC_ADD,</span><br><span style="color: hsl(120, 100%, 40%);">+ SNS_PROC_DEL,</span><br><span style="color: hsl(120, 100%, 40%);">+ SNS_PROC_CHANGE_WEIGHT,</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>@@ -99,6 +108,21 @@</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 style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</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 *sbind;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* copy entry to protect against changes of gss->local */</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%);">+ /* is the procedure in process */</span><br><span style="color: hsl(120, 100%, 40%);">+ bool running;</span><br><span> };</span><br><span> </span><br><span> struct ns2_sns_elems {</span><br><span>@@ -139,6 +163,9 @@</span><br><span> /* local configuration to send to the remote end */</span><br><span> struct ns2_sns_elems local;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* local configuration after all local procedures applied */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_elems local_procedure;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* remote configuration as received */</span><br><span> struct ns2_sns_elems remote;</span><br><span> </span><br><span>@@ -147,6 +174,10 @@</span><br><span> size_t num_max_nsvcs;</span><br><span> size_t num_max_ip4_remote;</span><br><span> size_t num_max_ip6_remote;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head procedures;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_procedure *current_procedure;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t trans_id;</span><br><span> };</span><br><span> </span><br><span> static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)</span><br><span>@@ -302,6 +333,16 @@</span><br><span> elems->num_ip6 = 0;</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%);">+ struct ns2_sns_procedure *procedure, *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->current_procedure = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry_safe(procedure, tmp, &gss->procedures, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_del(&procedure->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(procedure);</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> static void ns2_vc_create_ip(struct osmo_fsm_inst *fi, struct gprs_ns2_nse *nse, const struct osmo_sockaddr *remote,</span><br><span> uint8_t sig_weight, uint8_t data_weight)</span><br><span> {</span><br><span>@@ -777,6 +818,36 @@</span><br><span> return count;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int ns2_sns_copy_local_endpoints(struct ns2_sns_state *gss)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (gss->family) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AF_INET:</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->local_procedure.ip4 = talloc_realloc(gss, gss->local_procedure.ip4, struct gprs_ns_ie_ip4_elem,</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->local.num_ip4);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!gss->local_procedure.ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->local_procedure.num_ip4 = gss->local.num_ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(gss->local_procedure.ip4, gss->local.ip4,</span><br><span style="color: hsl(120, 100%, 40%);">+ sizeof(struct gprs_ns_ie_ip4_elem) * gss->local.num_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%);">+ gss->local_procedure.ip6 = talloc_realloc(gss, gss->local_procedure.ip6, struct gprs_ns_ie_ip6_elem,</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->local.num_ip6);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!gss->local_procedure.ip6)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->local_procedure.num_ip6 = gss->local.num_ip6;</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(gss->local_procedure.ip6, gss->local.ip6,</span><br><span style="color: hsl(120, 100%, 40%);">+ sizeof(struct gprs_ns_ie_ip6_elem) * gss->local.num_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(0);</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 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void ns2_sns_compute_local_ep_from_binds(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>@@ -878,6 +949,8 @@</span><br><span> gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->local.num_ip6, 8);</span><br><span> break;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ns2_sns_copy_local_endpoints(gss);</span><br><span> }</span><br><span> </span><br><span> static void ns2_sns_choose_next_bind(struct ns2_sns_state *gss)</span><br><span>@@ -902,6 +975,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>@@ -1367,7 +1441,135 @@</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%);">+ if (!llist_empty(&gss->procedures)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_LOCAL_PROCEDURE,</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->nse->nsi->timeout[NS_TOUT_TSNS_PROV], 5);</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_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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* check if resend or not */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!gss->current_procedure) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* take next procedure */</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->current_procedure = llist_first_entry_or_null(&gss->procedures,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_procedure, list);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!gss->current_procedure) {</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->N = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->current_procedure->running = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->current_procedure->trans_id = ++gss->trans_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gss->trans_id == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->trans_id = 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%);">+</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_PROC_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gss->family == AF_INET)</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%);">+ 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_ns_ie_ip4_elem *ip4, *proc4;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns_ie_ip6_elem *ip6, *proc6;</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%);">+ uint8_t cause;</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 NS2_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 NS2_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 NS2_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 NS2_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_INFO, "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%);">+ /* what happend on error cause? return to size? */</span><br><span style="color: hsl(120, 100%, 40%);">+ cause = tlvp_val8(tp, NS_IE_CAUSE, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx SNS ACK trans %d with cause code %d.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ nse->nsei, trans_id, cause);</span><br><span style="color: hsl(120, 100%, 40%);">+ sns_failed(fi, NULL);</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%);">+ switch (gss->current_procedure->procedure) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case SNS_PROC_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (gss->family) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AF_INET:</span><br><span style="color: hsl(120, 100%, 40%);">+ proc4 = &gss->current_procedure->ip4;</span><br><span style="color: hsl(120, 100%, 40%);">+ for (unsigned int i=0; i<gss->local.num_ip4; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4 = &gss->local.ip4[i];</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ip4->ip_addr != proc4->ip_addr ||</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4->udp_port != proc4->udp_port)</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4->sig_weight = proc4->sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4->data_weight = proc4->data_weight;</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 style="color: hsl(120, 100%, 40%);">+ case AF_INET6:</span><br><span style="color: hsl(120, 100%, 40%);">+ proc6 = &gss->current_procedure->ip6;</span><br><span style="color: hsl(120, 100%, 40%);">+ for (unsigned int i=0; i<gss->local.num_ip6; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6 = &gss->local.ip6[i];</span><br><span style="color: hsl(120, 100%, 40%);">+ if (memcmp(&ip6->ip_addr, &proc6->ip_addr, sizeof(proc6->ip_addr)) ||</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6->udp_port != proc6->udp_port) {</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%);">+ ip6->sig_weight = proc6->sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6->data_weight = proc6->data_weight;</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 style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(0);</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%);">+ 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%);">+ llist_del(&gss->current_procedure->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(gss->current_procedure);</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->current_procedure = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (llist_empty(&gss->procedures))</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_CONFIGURED,</span><br><span style="color: hsl(120, 100%, 40%);">+ 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_LOCAL_PROCEDURE,</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->nse->nsi->timeout[NS_TOUT_TSNS_PROV], 5);</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>@@ -1414,11 +1616,27 @@</span><br><span> S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |</span><br><span> S(NS2_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(NS2_SNS_EV_RX_ADD) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(NS2_SNS_EV_RX_DELETE) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(NS2_SNS_EV_RX_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(NS2_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>@@ -1453,14 +1671,173 @@</span><br><span> case 4:</span><br><span> sns_failed(fi, "Config succeeded but no NS-VC came online. Selecting next IP-SNS endpoint.");</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case 5:</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%);">+ sns_failed(fi, "SNS Procedure retries failed.");</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], 5);</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> </span><br><span style="color: hsl(120, 100%, 40%);">+static struct gprs_ns_ie_ip4_elem *ns2_get_sbind_ip4_entry(struct ns2_sns_state *gss,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_bind *sbind,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_elems *endpoints)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr *addr;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gss->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%);">+ addr = gprs_ns2_ip_bind_sockaddr(sbind->bind);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (addr->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 (unsigned int i=0; i<endpoints->num_ip4; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4 = &endpoints->ip4[i];</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ip4->ip_addr == addr->u.sin.sin_addr.s_addr &&</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4->udp_port == addr->u.sin.sin_port)</span><br><span style="color: hsl(120, 100%, 40%);">+ return ip4;</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 *ns2_get_sbind_ip6_entry(struct ns2_sns_state *gss,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_bind *sbind,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_elems *endpoints)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr *addr;</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%);">+ if (gss->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%);">+ addr = gprs_ns2_ip_bind_sockaddr(sbind->bind);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (addr->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 (unsigned int i=0; i<endpoints->num_ip6; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6 = &endpoints->ip6[i];</span><br><span style="color: hsl(120, 100%, 40%);">+ if (memcmp(&ip6->ip_addr, &addr->u.sin6.sin6_addr, sizeof(ip6->ip_addr)) ||</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6->udp_port != addr->u.sin6.sin6_port)</span><br><span style="color: hsl(120, 100%, 40%);">+ return ip6;</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%);">+/* return != 0 if the resulting weight is invalid. return 1 if sbind doesn't have an entry */</span><br><span style="color: hsl(120, 100%, 40%);">+static int ns2_update_weight_entry(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_elems *endpoints)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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%);">+ switch (gss->family) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AF_INET:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4 = ns2_get_sbind_ip4_entry(gss, sbind, endpoints);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ip4)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4->sig_weight = sbind->bind->sns_sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip4->data_weight = sbind->bind->sns_data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ return (ip4_weight_sum_sig(endpoints) != 0 && ip4_weight_sum_data(endpoints) != 0);</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%);">+ ip6 = ns2_get_sbind_ip6_entry(gss, sbind, endpoints);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ip6)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6->sig_weight = sbind->bind->sns_sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ ip6->data_weight = sbind->bind->sns_data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ return (ip6_weight_sum_sig(endpoints) != 0 && ip6_weight_sum_data(endpoints) != 0);</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(0);</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_add_procedure(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind,</span><br><span style="color: hsl(120, 100%, 40%);">+ enum sns_procedure procedure_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_procedure *procedure = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr *saddr;</span><br><span style="color: hsl(120, 100%, 40%);">+ saddr = gprs_ns2_ip_bind_sockaddr(sbind->bind);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (saddr->u.sa.sa_family != gss->family)</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 (procedure_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case SNS_PROC_CHANGE_WEIGHT:</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(procedure, &gss->procedures, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (procedure->sbind == sbind && procedure->procedure == procedure_type &&</span><br><span style="color: hsl(120, 100%, 40%);">+ !procedure->running) {</span><br><span style="color: hsl(120, 100%, 40%);">+ switch(gss->family) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AF_INET:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* merge it with a previous procedure */</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->ip4.ip_addr = sbind->bind->sns_sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->ip4.data_weight = sbind->bind->sns_data_weight;</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%);">+ /* merge it with a previous procedure */</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->ip6.sig_weight = sbind->bind->sns_sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->ip6.data_weight = sbind->bind->sns_data_weight;</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(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</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%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure = talloc_zero(gss, struct ns2_sns_procedure);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!procedure)</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%);">+ procedure->sbind = sbind;</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->procedure = procedure_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->sig_weight = sbind->bind->sns_sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->data_weight = sbind->bind->sns_data_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch(gss->family) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AF_INET:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->ip4.ip_addr = saddr->u.sin.sin_addr.s_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->ip4.udp_port = saddr->u.sin.sin_port;</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->ip4.sig_weight = sbind->bind->sns_sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->ip4.data_weight = sbind->bind->sns_data_weight;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(&procedure->ip6.ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->ip6.udp_port = saddr->u.sin.sin_port;</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->ip6.sig_weight = sbind->bind->sns_sig_weight;</span><br><span style="color: hsl(120, 100%, 40%);">+ procedure->ip6.data_weight = sbind->bind->sns_data_weight;</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(0);</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%);">+ llist_add_tail(&procedure->list, &gss->procedures);</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%);">+ return;</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->nse->bss_sns_fi->state == GPRS_SNS_ST_CONFIGURED) {</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_LOCAL_PROCEDURE,</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->nse->nsi->timeout[NS_TOUT_TSNS_PROV], 5);</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%);">+</span><br><span> /* common allstate-action for both roles */</span><br><span> static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span> {</span><br><span> struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;</span><br><span> struct ns2_sns_bind *sbind;</span><br><span> struct gprs_ns2_vc *nsvc, *nsvc2;</span><br><span> </span><br><span>@@ -1509,6 +1886,27 @@</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 NS2_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%);">+ /* select_endpoint will check if this is a valid configuration */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gss->role == GPRS_SNS_ROLE_BSS)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GPRS_SNS_ST_BSS_SIZE:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* invalid weight? */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ns2_update_weight_entry(gss, sbind, &gss->local))</span><br><span style="color: hsl(120, 100%, 40%);">+ sns_failed(fi, "updating weights results in an invalid configuration.");</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%);">+ if (!ns2_update_weight_entry(gss, sbind, &gss->local_procedure)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ sns_failed(fi, "updating weights results in an invalid configuration.");</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%);">+ ns2_add_procedure(gss, sbind, SNS_PROC_CHANGE_WEIGHT);</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> </span><br><span>@@ -1618,6 +2016,7 @@</span><br><span> S(NS2_SNS_EV_REQ_FREE_NSVCS) |</span><br><span> S(NS2_SNS_EV_REQ_SELECT_ENDPOINT) |</span><br><span> S(NS2_SNS_EV_REQ_ADD_BIND) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |</span><br><span> S(NS2_SNS_EV_REQ_DELETE_BIND),</span><br><span> .allstate_action = ns2_sns_st_all_action_bss,</span><br><span> .cleanup = NULL,</span><br><span>@@ -1653,6 +2052,7 @@</span><br><span> gss->num_max_ip6_remote = 8192;</span><br><span> INIT_LLIST_HEAD(&gss->sns_endpoints);</span><br><span> INIT_LLIST_HEAD(&gss->binds);</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&gss->procedures);</span><br><span> </span><br><span> return fi;</span><br><span> err:</span><br><span>@@ -1952,7 +2352,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>@@ -2052,7 +2452,26 @@</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 *sbind;</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%);">+ const struct osmo_sockaddr *addr = gprs_ns2_ip_bind_sockaddr(bind);</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+ if (addr->u.sa.sa_family != gss->family)</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%);">+ llist_for_each_entry(sbind, &gss->binds, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sbind->bind == bind) {</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(gss->nse->bss_sns_fi, NS2_SNS_EV_REQ_CHANGE_WEIGHT, sbind);</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>@@ -2067,6 +2486,7 @@</span><br><span> {</span><br><span> struct gprs_ns2_vc *nsvc, *nsvc2;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ns2_clear_procedures(gss);</span><br><span> ns2_clear_elems(&gss->local);</span><br><span> ns2_clear_elems(&gss->remote);</span><br><span> llist_for_each_entry_safe(nsvc, nsvc2, &gss->nse->nsvc, list) {</span><br><span>@@ -2207,12 +2627,28 @@</span><br><span> S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |</span><br><span> S(NS2_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_SGSN_WAIT_CONFIG),</span><br><span style="color: hsl(120, 100%, 40%);">+ S(GPRS_SNS_ST_SGSN_WAIT_CONFIG) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(GPRS_SNS_ST_LOCAL_PROCEDURE),</span><br><span> .name = "CONFIGURED",</span><br><span> /* shared with BSS side; once configured there's no difference */</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(NS2_SNS_EV_RX_ADD) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(NS2_SNS_EV_RX_DELETE) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(NS2_SNS_EV_RX_CHANGE_WEIGHT) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(NS2_SNS_EV_RX_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(NS2_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_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>@@ -2234,11 +2670,19 @@</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 5:</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%);">+ sns_failed(fi, "SNS Procedure retries failed.");</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>@@ -2349,6 +2793,7 @@</span><br><span> S(NS2_SNS_EV_REQ_NO_NSVC) |</span><br><span> S(NS2_SNS_EV_REQ_FREE_NSVCS) |</span><br><span> S(NS2_SNS_EV_REQ_ADD_BIND) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(NS2_SNS_EV_REQ_CHANGE_WEIGHT) |</span><br><span> S(NS2_SNS_EV_REQ_DELETE_BIND),</span><br><span> .allstate_action = ns2_sns_st_all_action_sgsn,</span><br><span> .cleanup = NULL,</span><br><span>@@ -2380,6 +2825,7 @@</span><br><span> gss->role = GPRS_SNS_ROLE_SGSN;</span><br><span> INIT_LLIST_HEAD(&gss->sns_endpoints);</span><br><span> INIT_LLIST_HEAD(&gss->binds);</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&gss->procedures);</span><br><span> </span><br><span> return fi;</span><br><span> err:</span><br><span>diff --git a/src/gb/gprs_ns2_vty.c b/src/gb/gprs_ns2_vty.c</span><br><span>index 0aa7902..52ce207 100644</span><br><span>--- a/src/gb/gprs_ns2_vty.c</span><br><span>+++ b/src/gb/gprs_ns2_vty.c</span><br><span>@@ -101,6 +101,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 45c8a16..62fff66 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/+/23187">change 23187</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/+/23187"/><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: Icec4dabb46bc198f68f91bfe09ba279fbe68d454 </div>
<div style="display:none"> Gerrit-Change-Number: 23187 </div>
<div style="display:none"> Gerrit-PatchSet: 17 </div>
<div style="display:none"> Gerrit-Owner: lynxis lazus <lynxis@fe80.eu> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: lynxis lazus <lynxis@fe80.eu> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>