<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/22742">View Change</a></p><div style="white-space:pre-wrap">Approvals:
laforge: Looks good to me, approved
daniel: Looks good to me, but someone else must approve
Jenkins Builder: Verified
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">gprs_ns2_sns: rework tracking of NS-VC unblocked/alive state<br><br>The SNS must know when all NS-VC have failed. Further more<br>there might be a corner case when the SNS configuration succeeds but<br>no NS-VC comes up afterwards.<br><br>Related: OS#5355<br>Change-Id: Ie72da9adeefe0c2850d49a9208b2d0a4556f9101<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>3 files changed, 90 insertions(+), 14 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 de27fb4..ca47934 100644</span><br><span>--- a/src/gb/gprs_ns2.c</span><br><span>+++ b/src/gb/gprs_ns2.c</span><br><span>@@ -577,7 +577,7 @@</span><br><span> ns2_nse_notify_unblocked(nsvc, false);</span><br><span> </span><br><span> /* check if sns is using this VC */</span><br><span style="color: hsl(0, 100%, 40%);">- ns2_sns_free_nsvc(nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+ ns2_sns_replace_nsvc(nsvc);</span><br><span> osmo_fsm_inst_term(nsvc->fi, OSMO_FSM_TERM_REQUEST, NULL);</span><br><span> </span><br><span> /* let the driver/bind clean up it's internal state */</span><br><span>@@ -1175,6 +1175,7 @@</span><br><span> {</span><br><span> struct gprs_ns2_nse *nse = nsvc->nse;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ns2_sns_notify_alive(nse, nsvc, unblocked);</span><br><span> ns2_nse_data_sum(nse);</span><br><span> </span><br><span> if (unblocked == nse->alive)</span><br><span>diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h</span><br><span>index 6462907..ff95c81 100644</span><br><span>--- a/src/gb/gprs_ns2_internal.h</span><br><span>+++ b/src/gb/gprs_ns2_internal.h</span><br><span>@@ -350,7 +350,8 @@</span><br><span> int ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp);</span><br><span> struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,</span><br><span> const char *id);</span><br><span style="color: hsl(0, 100%, 40%);">-void ns2_sns_free_nsvc(struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+void ns2_sns_replace_nsvc(struct gprs_ns2_vc *nsvc);</span><br><span style="color: hsl(120, 100%, 40%);">+void ns2_sns_notify_alive(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc, bool alive);</span><br><span> </span><br><span> /* vc */</span><br><span> struct osmo_fsm_inst *ns2_vc_fsm_alloc(struct gprs_ns2_vc *nsvc,</span><br><span>diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c</span><br><span>index 427a153..b80a880 100644</span><br><span>--- a/src/gb/gprs_ns2_sns.c</span><br><span>+++ b/src/gb/gprs_ns2_sns.c</span><br><span>@@ -80,6 +80,7 @@</span><br><span> GPRS_SNS_EV_DELETE,</span><br><span> GPRS_SNS_EV_CHANGE_WEIGHT,</span><br><span> GPRS_SNS_EV_NO_NSVC,</span><br><span style="color: hsl(120, 100%, 40%);">+ GPRS_SNS_EV_NSVC_ALIVE, /*!< a NS-VC became alive */</span><br><span> };</span><br><span> </span><br><span> static const struct value_string gprs_sns_event_names[] = {</span><br><span>@@ -93,6 +94,7 @@</span><br><span> { GPRS_SNS_EV_DELETE, "DELETE" },</span><br><span> { GPRS_SNS_EV_CHANGE_WEIGHT, "CHANGE_WEIGHT" },</span><br><span> { GPRS_SNS_EV_NO_NSVC, "NO_NSVC" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { GPRS_SNS_EV_NSVC_ALIVE, "NSVC_ALIVE"},</span><br><span> { 0, NULL }</span><br><span> };</span><br><span> </span><br><span>@@ -122,6 +124,8 @@</span><br><span> int bind_offset;</span><br><span> /* timer N */</span><br><span> int N;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* true if at least one nsvc is alive */</span><br><span style="color: hsl(120, 100%, 40%);">+ bool alive;</span><br><span> </span><br><span> /* local configuration to send to the remote end */</span><br><span> struct gprs_ns_ie_ip4_elem *ip4_local;</span><br><span>@@ -227,13 +231,13 @@</span><br><span> return &gss->initial->saddr;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! called when a nsvc is beeing freed */</span><br><span style="color: hsl(0, 100%, 40%);">-void ns2_sns_free_nsvc(struct gprs_ns2_vc *nsvc)</span><br><span style="color: hsl(120, 100%, 40%);">+/*! called when a nsvc is beeing freed or the nsvc became dead */</span><br><span style="color: hsl(120, 100%, 40%);">+void ns2_sns_replace_nsvc(struct gprs_ns2_vc *nsvc)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct gprs_ns2_nse *nse;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_nse *nse = nsvc->nse;</span><br><span> struct gprs_ns2_vc *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fsm_inst *fi = nse->bss_sns_fi;</span><br><span> struct ns2_sns_state *gss;</span><br><span style="color: hsl(0, 100%, 40%);">- struct osmo_fsm_inst *fi = nsvc->nse->bss_sns_fi;</span><br><span> </span><br><span> if (!fi)</span><br><span> return;</span><br><span>@@ -242,17 +246,26 @@</span><br><span> if (nsvc != gss->sns_nsvc)</span><br><span> return;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- nse = nsvc->nse;</span><br><span style="color: hsl(0, 100%, 40%);">- if (nse->alive) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* choose a different sns nsvc */</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->sns_nsvc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gss->alive) {</span><br><span> llist_for_each_entry(tmp, &nse->nsvc, list) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (ns2_vc_is_unblocked(tmp))</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ns2_vc_is_unblocked(tmp)) {</span><br><span> gss->sns_nsvc = tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> } else {</span><br><span style="color: hsl(0, 100%, 40%);">- gss->sns_nsvc = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_NO_NSVC, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* the SNS is waiting for its first NS-VC to come up</span><br><span style="color: hsl(120, 100%, 40%);">+ * choose any other nsvc */</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(tmp, &nse->nsvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nsvc != tmp) {</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->sns_nsvc = tmp;</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> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_NO_NSVC, NULL);</span><br><span> }</span><br><span> </span><br><span> static void ns2_clear_ipv46_entries(struct ns2_sns_state *gss)</span><br><span>@@ -715,6 +728,7 @@</span><br><span> if (old_state != GPRS_SNS_ST_UNCONFIGURED)</span><br><span> ns2_prim_status_ind(gss->nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_FAILURE);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ gss->alive = false;</span><br><span> ns2_clear_ipv46_entries(gss);</span><br><span> </span><br><span> /* no initial available */</span><br><span>@@ -873,6 +887,18 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* calculate the timeout of the configured state. the configured</span><br><span style="color: hsl(120, 100%, 40%);">+ * state will fail if not at least one NS-VC is alive within X second.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline int ns_sns_configured_timeout(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int secs;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_inst *nsi = nse_inst_from_fi(fi)->nsi;</span><br><span style="color: hsl(120, 100%, 40%);">+ secs = nsi->timeout[NS_TOUT_TNS_ALIVE] * nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES];</span><br><span style="color: hsl(120, 100%, 40%);">+ secs += nsi->timeout[NS_TOUT_TNS_TEST];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return secs;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> static void ns_sns_st_config_sgsn_ip4(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span> {</span><br><span>@@ -917,7 +943,7 @@</span><br><span> ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);</span><br><span> /* start the test procedure on ALL NSVCs! */</span><br><span> gprs_ns2_start_alive_all_nsvcs(nse);</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, ns_sns_configured_timeout(fi), 3);</span><br><span> } else {</span><br><span> /* just send CONFIG-ACK */</span><br><span> ns2_tx_sns_config_ack(gss->sns_nsvc, NULL);</span><br><span>@@ -1259,6 +1285,9 @@</span><br><span> case GPRS_SNS_EV_CHANGE_WEIGHT:</span><br><span> ns2_sns_st_configured_change(fi, gss, tp);</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GPRS_SNS_EV_NSVC_ALIVE:</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_del(&fi->timer);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span> }</span><br><span> }</span><br><span> </span><br><span>@@ -1307,7 +1336,8 @@</span><br><span> [GPRS_SNS_ST_CONFIGURED] = {</span><br><span> .in_event_mask = S(GPRS_SNS_EV_ADD) |</span><br><span> S(GPRS_SNS_EV_DELETE) |</span><br><span style="color: hsl(0, 100%, 40%);">- S(GPRS_SNS_EV_CHANGE_WEIGHT),</span><br><span style="color: hsl(120, 100%, 40%);">+ S(GPRS_SNS_EV_CHANGE_WEIGHT) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(GPRS_SNS_EV_NSVC_ALIVE),</span><br><span> .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |</span><br><span> S(GPRS_SNS_ST_SIZE),</span><br><span> .name = "CONFIGURED",</span><br><span>@@ -1340,6 +1370,10 @@</span><br><span> osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS, nsi->timeout[NS_TOUT_TSNS_PROV], 2);</span><br><span> }</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case 3:</span><br><span style="color: hsl(120, 100%, 40%);">+ 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 style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SELECT_ENDPOINT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span> }</span><br><span> return 0;</span><br><span> }</span><br><span>@@ -1709,6 +1743,46 @@</span><br><span> return count;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void ns2_sns_notify_alive(struct gprs_ns2_nse *nse, struct gprs_ns2_vc *nsvc, bool alive)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ns2_sns_state *gss;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_ns2_vc *tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!nse->bss_sns_fi)</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 = nse->bss_sns_fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ if(nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED)</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%);">+ if (alive == gss->alive)</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%);">+ /* check if this is the current SNS NS-VC */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nsvc == gss->sns_nsvc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* only replace the SNS NS-VC if there are other alive NS-VC.</span><br><span style="color: hsl(120, 100%, 40%);">+ * There aren't any other alive NS-VC when the SNS fsm just reached CONFIGURED</span><br><span style="color: hsl(120, 100%, 40%);">+ * and couldn't confirm yet if the NS-VC comes up */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gss->alive && !alive)</span><br><span style="color: hsl(120, 100%, 40%);">+ ns2_sns_replace_nsvc(nsvc);</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 (alive) {</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->alive = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_NSVC_ALIVE, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* is there at least another alive nsvc? */</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(tmp, &nse->nsvc, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ns2_vc_is_unblocked(tmp))</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%);">+ /* all NS-VC have failed */</span><br><span style="color: hsl(120, 100%, 40%);">+ gss->alive = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_NO_NSVC, 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%);">+</span><br><span> /* initialize osmo_ctx on main tread */</span><br><span> static __attribute__((constructor)) void on_dso_load_ctx(void)</span><br><span> {</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/22742">change 22742</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/+/22742"/><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: Ie72da9adeefe0c2850d49a9208b2d0a4556f9101 </div>
<div style="display:none"> Gerrit-Change-Number: 22742 </div>
<div style="display:none"> Gerrit-PatchSet: 8 </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-CC: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>