pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/40460?usp=email )
Change subject: ipa: Implement ASP Hearbeat procedure ......................................................................
ipa: Implement ASP Hearbeat procedure
This implements M3UA/SUA Heartbeat Procedure using own IPA PING & PONG messages.
Related: OS#4072 Change-Id: I0947977b192447d433ecf6b3ccb830141d8ae04d --- M src/ipa.c M src/xua_asp_fsm.c M src/xua_internal.h 3 files changed, 105 insertions(+), 18 deletions(-)
Approvals: Jenkins Builder: Verified osmith: Looks good to me, but someone else must approve laforge: Looks good to me, but someone else must approve pespin: Looks good to me, approved
diff --git a/src/ipa.c b/src/ipa.c index c04b476..58646fa 100644 --- a/src/ipa.c +++ b/src/ipa.c @@ -52,6 +52,20 @@ #include "ss7_internal.h" #include "xua_asp_fsm.h"
+/* generate a msgb containing an IPA CCM PING message */ +struct msgb *ipa_gen_ping(void) +{ + /* sufficient headroom for osmo_ipa_msg_push_header() */ + struct msgb *msg = ipa_msg_alloc(16); + if (!msg) + return NULL; + + msgb_put_u8(msg, IPAC_MSGT_PING); + ipa_prepend_header(msg, IPAC_PROTO_IPACCESS); + + return msg; +} + struct msgb *ipa_to_msg(struct xua_msg *xua) { struct xua_msg_part *data_ie; diff --git a/src/xua_asp_fsm.c b/src/xua_asp_fsm.c index 1d6b078..adc9f0e 100644 --- a/src/xua_asp_fsm.c +++ b/src/xua_asp_fsm.c @@ -879,8 +879,11 @@
/* Structure holding parsed data of the IPA CCM ID exchange */ struct ipaccess_unit *ipa_unit; - /* Timer for tracking if no PONG is received in response to PING */ - struct osmo_timer_list pong_timer; + /* Timer for tracking PING without PONG response */ + struct { + struct osmo_timer_list timer; + uint32_t unacked_beats; + } t_beat; /* Did we receive IPA ID ACK before IPA ID RESP ? */ bool ipa_id_ack_rcvd; }; @@ -907,11 +910,82 @@ return fd; }
+static void ipa_t_beat_stop(struct osmo_fsm_inst *fi) +{ + struct ipa_asp_fsm_priv *iafp = fi->priv; + + LOGPFSML(fi, LOGL_DEBUG, "T(beat) stopped\n"); + osmo_timer_del(&iafp->t_beat.timer); + iafp->t_beat.unacked_beats = 0; +} + +static void ipa_t_beat_send(struct osmo_fsm_inst *fi) +{ + struct ipa_asp_fsm_priv *iafp = fi->priv; + struct msgb *msg; + uint32_t timeout_sec; + + timeout_sec = osmo_tdef_get(iafp->asp->cfg.T_defs_xua, SS7_ASP_XUA_T_BEAT, OSMO_TDEF_S, -1); + + /* T(beat) disabled */ + if (timeout_sec == 0) { + ipa_t_beat_stop(fi); + return; + } + + LOGPFSML(fi, LOGL_DEBUG, "Tx HEARTBEAT (%u unacked)\n", iafp->t_beat.unacked_beats); + + /* Avoid increasing in case some extra gratuitous PING is transmitted: */ + if (!osmo_timer_pending(&iafp->t_beat.timer)) + iafp->t_beat.unacked_beats++; + + /* (re-)arm T(beat): */ + osmo_timer_schedule(&iafp->t_beat.timer, timeout_sec, 0); + + /* Send PING: */ + if ((msg = ipa_gen_ping())) + osmo_ss7_asp_send(iafp->asp, msg); + /* we don't own msg anymore in any case here */ +} + +static void ipa_t_beat_cb(void *_fi) +{ + struct osmo_fsm_inst *fi = _fi; + struct ipa_asp_fsm_priv *iafp = fi->priv; + + if (iafp->t_beat.unacked_beats < 2) { + if (iafp->t_beat.unacked_beats == 1) + LOGPFSML(fi, LOGL_NOTICE, + "Peer didn't respond to PING with PONG, retrying once more\n"); + ipa_t_beat_send(fi); + return; + } + + /* RFC4666 4.3.4.6: If no Heartbeat Ack message (or any other M3UA + * message) is received from the M3UA peer within 2*T(beat), the remote + * M3UA peer is considered unavailable. Transmission of Heartbeat + * messages is stopped, and the signalling process SHOULD attempt to + * re-establish communication if it is configured as the client for the + * disconnected M3UA peer. + */ + LOGPFSML(fi, LOGL_NOTICE, "Peer didn't respond to PING with PONG and became disconnected\n"); + ss7_asp_disconnect_stream(iafp->asp); + +} + /*************** ** FSM states ** ***************/
/* Server + Client: Initial State, wait for M-ASP-UP.req */ +static void ipa_asp_fsm_down_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) +{ + struct xua_asp_fsm_priv *xafp = fi->priv; + struct osmo_ss7_asp *asp = xafp->asp; + ipa_t_beat_stop(fi); + dispatch_to_all_as(fi, XUA_ASPAS_ASP_DOWN_IND, asp); +} + static void ipa_asp_fsm_down(struct osmo_fsm_inst *fi, uint32_t event, void *data) { struct ipa_asp_fsm_priv *iafp = fi->priv; @@ -1079,6 +1153,10 @@ .asp = asp, .asp_requires_notify = false, }; + + /* Now we are done with IPA handshake, Start Hearbeat Procedure, T(beat): */ + ipa_t_beat_send(fi); + dispatch_to_all_as(fi, XUA_ASPAS_ASP_INACTIVE_IND, &pars); dispatch_to_all_as(fi, XUA_ASPAS_ASP_ACTIVE_IND, asp); } @@ -1163,8 +1241,8 @@ ipaccess_send_pong(fd); break; case XUA_ASP_E_ASPSM_BEAT_ACK: - /* stop timer, if any */ - osmo_timer_del(&iafp->pong_timer); + LOGPFSML(fi, LOGL_DEBUG, "Rx HEARTBEAT ACK\n"); + iafp->t_beat.unacked_beats = 0; break; case XUA_ASP_E_AS_ASSIGNED: as = data; @@ -1183,16 +1261,6 @@ } }
-static void ipa_pong_timer_cb(void *_fi) -{ - struct osmo_fsm_inst *fi = _fi; - struct ipa_asp_fsm_priv *iafp = fi->priv; - - LOGPFSML(fi, LOGL_NOTICE, "Peer didn't respond to PING? with PONG!\n"); - /* kill ASP and (wait for) re-connect */ - osmo_ss7_asp_disconnect(iafp->asp); -} - static int ipa_asp_fsm_timer_cb(struct osmo_fsm_inst *fi) { struct ipa_asp_fsm_priv *iafp = fi->priv; @@ -1207,7 +1275,12 @@ { struct ipa_asp_fsm_priv *iafp = fi->priv;
- if (iafp && iafp->asp) + if (!iafp) + return; + + ipa_t_beat_stop(fi); + + if (iafp->asp) iafp->asp->fi = NULL; }
@@ -1219,7 +1292,7 @@ S(IPA_ASP_S_WAIT_ID_RESP), .name = "ASP_DOWN", .action = ipa_asp_fsm_down, - .onenter = xua_asp_fsm_down_onenter, + .onenter = ipa_asp_fsm_down_onenter, }, /* Server Side */ [IPA_ASP_S_WAIT_ID_RESP] = { @@ -1340,8 +1413,7 @@ iafp->asp = asp; iafp->ipa_unit = talloc_zero(iafp, struct ipaccess_unit); iafp->ipa_unit->unit_name = talloc_strdup(iafp->ipa_unit, unit_name); - iafp->pong_timer.cb = ipa_pong_timer_cb; - iafp->pong_timer.data = fi; + osmo_timer_setup(&iafp->t_beat.timer, ipa_t_beat_cb, fi);
fi->priv = iafp;
diff --git a/src/xua_internal.h b/src/xua_internal.h index 60d751c..576708f 100644 --- a/src/xua_internal.h +++ b/src/xua_internal.h @@ -116,6 +116,7 @@ int xua_find_as_for_asp(struct osmo_ss7_as **as, const struct osmo_ss7_asp *asp, const struct xua_msg_part *rctx_ie);
+struct msgb *ipa_gen_ping(void); struct msgb *ipa_to_msg(struct xua_msg *xua); int ipa_tx_xua_as(struct osmo_ss7_as *as, struct xua_msg *xua); int ipa_rx_msg(struct osmo_ss7_asp *asp, struct msgb *msg, uint8_t sls);