Change in libosmo-abis[master]: Add IPA keep-alive FSM implementation

Harald Welte gerrit-no-reply at lists.osmocom.org
Fri Mar 8 16:09:16 UTC 2019


Harald Welte has uploaded this change for review. ( https://gerrit.osmocom.org/13196


Change subject: Add IPA keep-alive FSM implementation
......................................................................

Add IPA keep-alive FSM implementation

The IPA keep-alive FSM code takes care of periodically transmitting
and IPA CCM PING and expecting an IPA CCM PONG in return.

Change-Id: I2763da49a74de85046ac07d53592c89973314ca6
---
M include/osmocom/abis/ipa.h
M src/Makefile.am
A src/input/ipa_keepalive.c
3 files changed, 319 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmo-abis refs/changes/96/13196/1

diff --git a/include/osmocom/abis/ipa.h b/include/osmocom/abis/ipa.h
index a738156..4f6081f 100644
--- a/include/osmocom/abis/ipa.h
+++ b/include/osmocom/abis/ipa.h
@@ -5,6 +5,7 @@
 #include <osmocom/core/linuxlist.h>
 #include <osmocom/core/timer.h>
 #include <osmocom/core/select.h>
+#include <osmocom/core/fsm.h>
 #include <osmocom/gsm/ipa.h>
 
 struct e1inp_line;
@@ -99,4 +100,39 @@
 
 void ipa_msg_push_header(struct msgb *msg, uint8_t proto);
 
+
+/***********************************************************************
+ * IPA Keep-Alive FSM
+ ***********************************************************************/
+
+/*! parameters describing the keep-alive FSM (timeouts). */
+struct ipa_keepalive_params {
+	/*! interval in which to send IPA CCM PING requests to the peer. */
+	unsigned int interval;
+	/*! time to wait for an IPA CCM PONG in response to a IPA CCM PING before giving up. */
+	unsigned int wait_for_resp;
+};
+
+typedef void ipa_keepalive_timeout_cb_t(struct osmo_fsm_inst *fi, void *conn);
+
+struct osmo_fsm_inst *ipa_client_conn_alloc_keepalive_fsm(struct ipa_client_conn *client,
+							  const struct ipa_keepalive_params *params,
+							  const char *id);
+
+struct osmo_fsm_inst *ipa_server_conn_alloc_keepalive_fsm(struct ipa_server_conn *server,
+							  const struct ipa_keepalive_params *params,
+							  const char *id);
+
+struct osmo_fsm_inst *ipa_keepalive_alloc_server(struct ipa_server_conn *server,
+						 const struct ipa_keepalive_params *params,
+						 const char *id);
+
+void ipa_keepalive_fsm_set_timeout_cb(struct osmo_fsm_inst *fi, ipa_keepalive_timeout_cb_t *cb);
+
+void ipa_keepalive_fsm_start(struct osmo_fsm_inst *fi);
+
+void ipa_keepalive_fsm_stop(struct osmo_fsm_inst *fi);
+
+void ipa_keepalive_fsm_pong_received(struct osmo_fsm_inst *fi);
+
 #endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 9566617..2d2424d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,6 +21,7 @@
 			 trau_frame.c \
 			 input/dahdi.c \
 			 input/ipa.c \
+			 input/ipa_keepalive.c \
 			 input/ipaccess.c \
 			 input/lapd.c \
 			 input/lapd_pcap.c \
diff --git a/src/input/ipa_keepalive.c b/src/input/ipa_keepalive.c
new file mode 100644
index 0000000..3158cb4
--- /dev/null
+++ b/src/input/ipa_keepalive.c
@@ -0,0 +1,282 @@
+/* IPA keep-alive FSM; Periodically transmit IPA_PING and expect IPA_PONG in return.
+ *
+ * (C) 2019 by Harald Welte <laforge at gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/logging.h>
+
+#include <osmocom/gsm/protocol/ipaccess.h>
+
+#include <osmocom/abis/ipa.h>
+
+#define S(x)	(1 << (x))
+
+
+/* generate a msgb containing an IPA CCM PING message */
+static struct msgb *gen_ipa_ping(void)
+{
+	struct msgb *msg = msgb_alloc_headroom(64, 32, "IPA PING");
+	if (!msg)
+		return NULL;
+
+	msgb_put_u8(msg, IPAC_MSGT_PING);
+	ipa_msg_push_header(msg, IPAC_PROTO_IPACCESS);
+
+	return msg;
+}
+
+enum osmo_ipa_keepalive_state {
+	OSMO_IPA_KA_S_INIT,
+	OSMO_IPA_KA_S_IDLE,		/* waiting for next interval */
+	OSMO_IPA_KA_S_WAIT_RESP,	/* waiting for response to keepalive */
+};
+
+enum osmo_ipa_keepalive_event {
+	OSMO_IPA_KA_E_START,
+	OSMO_IPA_KA_E_STOP,
+	OSMO_IPA_KA_E_PONG,
+};
+
+static const struct value_string ipa_keepalive_event_names[] = {
+	OSMO_VALUE_STRING(OSMO_IPA_KA_E_START),
+	OSMO_VALUE_STRING(OSMO_IPA_KA_E_STOP),
+	OSMO_VALUE_STRING(OSMO_IPA_KA_E_PONG),
+	{ 0, NULL }
+};
+
+struct ipa_fsm_priv {
+	struct ipa_keepalive_params params;
+
+	struct ipa_server_conn *srv_conn;
+	struct ipa_client_conn *client_conn;
+	ipa_keepalive_timeout_cb_t *timeout_cb;
+};
+
+static void ipa_ka_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+	struct ipa_fsm_priv *ifp = fi->priv;
+
+	switch (event) {
+	case OSMO_IPA_KA_E_START:
+		osmo_fsm_inst_state_chg(fi, OSMO_IPA_KA_S_WAIT_RESP, ifp->params.interval, 2);
+		break;
+	default:
+		OSMO_ASSERT(0);
+		break;
+	}
+}
+
+static void ipa_ka_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+	/* no permitted events aside from E_START, which is handled in allstate_events */
+}
+
+static void ipa_ka_wait_resp_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+	struct ipa_fsm_priv *ifp = fi->priv;
+	struct msgb *msg;
+
+	/* Send an IPA PING to the peer */
+	msg = gen_ipa_ping();
+	OSMO_ASSERT(msg);
+
+	if (ifp->srv_conn)
+		ipa_server_conn_send(ifp->srv_conn, msg);
+	else {
+		OSMO_ASSERT(ifp->client_conn);
+		ipa_client_conn_send(ifp->client_conn, msg);
+	}
+}
+
+static void ipa_ka_wait_resp(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+	struct ipa_fsm_priv *ifp = fi->priv;
+
+	switch (event) {
+	case OSMO_IPA_KA_E_PONG:
+		osmo_fsm_inst_state_chg(fi, OSMO_IPA_KA_S_IDLE, ifp->params.wait_for_resp, 1);
+		break;
+	default:
+		OSMO_ASSERT(0);
+	}
+}
+
+static int ipa_ka_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+	struct ipa_fsm_priv *ifp = fi->priv;
+	void *conn;
+
+	switch (fi->T) {
+	case 1:
+		/* send another PING */
+		osmo_fsm_inst_state_chg(fi, OSMO_IPA_KA_S_WAIT_RESP, ifp->params.interval, 2);
+		return 0;
+	case 2:
+		/* PONG not received within time */
+		if (ifp->srv_conn)
+			conn = ifp->srv_conn;
+		else
+			conn = ifp->client_conn;
+		if (ifp->timeout_cb)
+			ifp->timeout_cb(fi, conn);
+		/* ask fsm core to terminate us */
+		return 1;
+	default:
+		OSMO_ASSERT(0);
+	}
+}
+
+static void ipa_ka_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+	switch (event) {
+	case OSMO_IPA_KA_E_STOP:
+		osmo_fsm_inst_state_chg(fi, OSMO_IPA_KA_S_INIT, 0, 0);
+		break;
+	default:
+		OSMO_ASSERT(0);
+		break;
+	}
+}
+
+static const struct osmo_fsm_state ipa_keepalive_states[] = {
+	[OSMO_IPA_KA_S_INIT] = {
+		.name = "INIT",
+		.in_event_mask = S(OSMO_IPA_KA_E_START),
+		.out_state_mask = S(OSMO_IPA_KA_S_WAIT_RESP),
+		.action = ipa_ka_init,
+	},
+	[OSMO_IPA_KA_S_IDLE] = {
+		.name = "IDLE",
+		.out_state_mask = S(OSMO_IPA_KA_S_WAIT_RESP) | S(OSMO_IPA_KA_S_INIT),
+		.action = ipa_ka_idle,
+	},
+	[OSMO_IPA_KA_S_WAIT_RESP] = {
+		.name = "WAIT_RESP",
+		.in_event_mask = S(OSMO_IPA_KA_E_PONG),
+		.out_state_mask = S(OSMO_IPA_KA_S_IDLE) | S(OSMO_IPA_KA_S_INIT),
+		.action = ipa_ka_wait_resp,
+		.onenter = ipa_ka_wait_resp_onenter,
+	},
+};
+
+static struct osmo_fsm ipa_keepalive_fsm = {
+	.name = "IPA-KEEPALIVE",
+	.states = ipa_keepalive_states,
+	.num_states = ARRAY_SIZE(ipa_keepalive_states),
+	.log_subsys = DLINP,
+	.allstate_action = ipa_ka_allstate_action,
+	.event_names = ipa_keepalive_event_names,
+	.timer_cb = ipa_ka_fsm_timer_cb,
+};
+
+static __attribute__((constructor)) void on_dso_load(void)
+{
+	osmo_fsm_register(&ipa_keepalive_fsm);
+}
+
+
+/*! Create a new instance of an IPA keepalive FSM: Periodically transmit PING and expect PONG.
+ *  \param[in] client The client connection for which to crate the FSM. Used as talloc context.
+ *  \param[in] params Parameters describing the keepalive FSM time-outs.
+ *  \param[in] id String used as identifier for the FSM.
+ *  \returns pointer to the newly-created FSM instance; NULL in case of error. */
+struct osmo_fsm_inst *ipa_client_conn_alloc_keepalive_fsm(struct ipa_client_conn *client,
+							  const struct ipa_keepalive_params *params,
+							  const char *id)
+{
+	struct osmo_fsm_inst *fi;
+	struct ipa_fsm_priv *ifp;
+	void *ctx = client;
+
+	fi = osmo_fsm_inst_alloc(&ipa_keepalive_fsm, ctx, NULL, LOGL_DEBUG, id);
+	ifp = talloc_zero(fi, struct ipa_fsm_priv);
+	if (!ifp) {
+		osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+		return NULL;
+	}
+	memcpy(&ifp->params, params, sizeof(ifp->params));
+	ifp->client_conn = client;
+	fi->priv = ifp;
+
+	return fi;
+}
+
+/*! Create a new instance of an IPA keepalive FSM: Periodically transmit PING and expect PONG.
+ *  \param[in] server The server connection for which to crate the FSM. Used as talloc context.
+ *  \param[in] params Parameters describing the keepalive FSM time-outs.
+ *  \param[in] id String used as identifier for the FSM.
+ *  \returns pointer to the newly-created FSM instance; NULL in case of error. */
+struct osmo_fsm_inst *ipa_server_conn_alloc_keepalive_fsm(struct ipa_server_conn *server,
+							  const struct ipa_keepalive_params *params,
+							  const char *id)
+{
+	struct osmo_fsm_inst *fi;
+	struct ipa_fsm_priv *ifp;
+	void *ctx = server;
+
+	fi = osmo_fsm_inst_alloc(&ipa_keepalive_fsm, ctx, NULL, LOGL_NOTICE, id);
+	if (!fi)
+		return NULL;
+
+	ifp = talloc_zero(fi, struct ipa_fsm_priv);
+	if (!ifp) {
+		osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+		return NULL;
+	}
+	memcpy(&ifp->params, params, sizeof(ifp->params));
+	ifp->srv_conn = server;
+	fi->priv = ifp;
+
+	return fi;
+}
+
+/*! Set a timeout call-back which is to be called once the peer doesn't respond anymore */
+void ipa_keepalive_fsm_set_timeout_cb(struct osmo_fsm_inst *fi, ipa_keepalive_timeout_cb_t *cb)
+{
+	struct ipa_fsm_priv *ifp = fi->priv;
+	OSMO_ASSERT(fi->fsm == &ipa_keepalive_fsm);
+	ifp->timeout_cb = cb;
+}
+
+/*! Start the ping/pong procedure of the IPA Keepalive FSM. */
+void ipa_keepalive_fsm_pong_received(struct osmo_fsm_inst *fi)
+{
+	OSMO_ASSERT(fi->fsm == &ipa_keepalive_fsm);
+	osmo_fsm_inst_dispatch(fi, OSMO_IPA_KA_E_PONG, NULL);
+}
+
+/*! Stop the ping/pong procedure of the IPA Keepalive FSM. */
+void ipa_keepalive_fsm_start(struct osmo_fsm_inst *fi)
+{
+	OSMO_ASSERT(fi->fsm == &ipa_keepalive_fsm);
+	osmo_fsm_inst_dispatch(fi, OSMO_IPA_KA_E_START, NULL);
+}
+
+/*! Inform IPA Keepalive FSM that a PONG has been received. */
+void ipa_keepalive_fsm_stop(struct osmo_fsm_inst *fi)
+{
+	OSMO_ASSERT(fi->fsm == &ipa_keepalive_fsm);
+	osmo_fsm_inst_dispatch(fi, OSMO_IPA_KA_E_STOP, NULL);
+}

-- 
To view, visit https://gerrit.osmocom.org/13196
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: libosmo-abis
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I2763da49a74de85046ac07d53592c89973314ca6
Gerrit-Change-Number: 13196
Gerrit-PatchSet: 1
Gerrit-Owner: Harald Welte <laforge at gnumonks.org>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190308/aa98167e/attachment.html>


More information about the gerrit-log mailing list