<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>