Implement initial shutdown + reconnect FSM

The shutdown_fsm doesn't do much right now, but it's included there in
order to allow easy clean up of resources upon Iuh reconnect in the
future, as well as reset the lower layers.

Change-Id: Id35d692218af366843186b0966b62f65bb9eb620
This commit is contained in:
Pau Espin 2021-11-23 16:00:25 +01:00
parent fd440b7a67
commit 807e52a2da
7 changed files with 202 additions and 1 deletions

View File

@ -1,4 +1,5 @@
noinst_HEADERS = \
hnb_shutdown_fsm.h \
hnbap.h \
hnodeb.h \
iuh.h \

View File

@ -0,0 +1,42 @@
/* hNodeB shutdown FSM */
/* (C) 2021 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <stdbool.h>
#include <osmocom/core/fsm.h>
enum hnb_shutdown_fsm_states {
HNB_SHUTDOWN_ST_NONE,
HNB_SHUTDOWN_ST_EXIT,
};
enum hnb_shutdown_fsm_events {
HNB_SHUTDOWN_EV_START,
};
extern struct osmo_fsm hnb_shutdown_fsm;
struct hnb;
void hnb_shutdown(struct hnb *hnb, const char *reason, bool exit_proc);
bool hnb_shutdown_in_progress(const struct hnb *hnb);

View File

@ -26,6 +26,7 @@
#include <osmocom/core/write_queue.h>
#include <osmocom/core/logging.h>
#include <osmocom/gsm/gsm23003.h>
#include <osmocom/netif/stream.h>
enum {
DMAIN,
@ -62,6 +63,9 @@ struct hnb {
uint32_t ctx_id;
struct osmo_fsm_inst *shutdown_fi; /* FSM instance to manage shutdown procedure during process exit */
bool shutdown_fi_exit_proc; /* exit process when shutdown_fsm is finished? */
struct {
struct hnb_chan *chan;
} cs;

View File

@ -33,6 +33,7 @@ osmo_hnodeb_SOURCES = \
debug.c \
hnbap.c \
hnb.c \
hnb_shutdown_fsm.c \
iuh.c \
nas.c \
ranap.c \

View File

@ -26,6 +26,7 @@
#include <osmocom/hnodeb/hnodeb.h>
#include <osmocom/hnodeb/iuh.h>
#include <osmocom/hnodeb/hnb_shutdown_fsm.h>
struct hnb *hnb_alloc(void *tall_ctx)
@ -41,6 +42,10 @@ struct hnb *hnb_alloc(void *tall_ctx)
.mcc = 1,
.mnc = 1,
};
hnb->shutdown_fi = osmo_fsm_inst_alloc(&hnb_shutdown_fsm, hnb, hnb,
LOGL_INFO, NULL);
hnb_iuh_alloc(hnb);
return hnb;
@ -48,6 +53,10 @@ struct hnb *hnb_alloc(void *tall_ctx)
void hnb_free(struct hnb *hnb)
{
if (hnb->shutdown_fi) {
osmo_fsm_inst_free(hnb->shutdown_fi);
hnb->shutdown_fi = NULL;
}
hnb_iuh_free(hnb);
talloc_free(hnb);
}

View File

@ -0,0 +1,134 @@
/* hNodeB shutdown FSM */
/* (C) 2021 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/core/fsm.h>
#include <osmocom/core/tdef.h>
#include <osmocom/hnodeb/hnb_shutdown_fsm.h>
#include <osmocom/hnodeb/hnodeb.h>
#include <osmocom/hnodeb/iuh.h>
#define X(s) (1 << (s))
#define hnb_shutdown_fsm_state_chg(fi, NEXT_STATE) \
osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
static void st_none_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct hnb *hnb = (struct hnb *)fi->priv;
hnb_iuh_connect(hnb); /* Start reconnect once we are done with shutdown and we didn't exit process */
}
static void st_none(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct hnb *hnb = (struct hnb *)fi->priv;
switch (event) {
case HNB_SHUTDOWN_EV_START:
/* TODO: here we may want to communicate t lower layers over UDsocket that we are shutting down...
* TODO: Also, if Iuh link is still up, maybe send a Hnb deregister req towards HNBGW
* TODO: also signal the hnb object somehow that we are starting to shut down?
*/
if (osmo_stream_cli_is_connected(hnb->iuh.client))
osmo_stream_cli_close(hnb->iuh.client);
hnb_shutdown_fsm_state_chg(fi, HNB_SHUTDOWN_ST_EXIT);
break;
}
}
static void st_exit_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct hnb *hnb = (struct hnb *)fi->priv;
/* TODO: here we may want to signal the hnb object somehow that we have completed the shut down? */
if (hnb->shutdown_fi_exit_proc) {
LOGPFSML(fi, LOGL_NOTICE, "Shutdown process completed successfully, exiting process\n");
exit(0);
}
hnb_shutdown_fsm_state_chg(fi, HNB_SHUTDOWN_ST_NONE);
}
static struct osmo_fsm_state hnb_shutdown_fsm_states[] = {
[HNB_SHUTDOWN_ST_NONE] = {
.in_event_mask =
X(HNB_SHUTDOWN_EV_START),
.out_state_mask =
X(HNB_SHUTDOWN_ST_EXIT),
.name = "NONE",
.onenter = st_none_on_enter,
.action = st_none,
},
[HNB_SHUTDOWN_ST_EXIT] = {
.name = "EXIT",
.out_state_mask =
X(HNB_SHUTDOWN_ST_NONE),
.onenter = st_exit_on_enter,
}
};
const struct value_string hnb_shutdown_fsm_event_names[] = {
OSMO_VALUE_STRING(HNB_SHUTDOWN_EV_START),
{ 0, NULL }
};
int hnb_shutdown_fsm_timer_cb(struct osmo_fsm_inst *fi)
{
switch (fi->state) {
default:
OSMO_ASSERT(false);
}
return 0;
}
struct osmo_fsm hnb_shutdown_fsm = {
.name = "HNB_SHUTDOWN",
.states = hnb_shutdown_fsm_states,
.num_states = ARRAY_SIZE(hnb_shutdown_fsm_states),
.event_names = hnb_shutdown_fsm_event_names,
.log_subsys = DMAIN,
.timer_cb = hnb_shutdown_fsm_timer_cb,
};
static __attribute__((constructor)) void hnb_shutdown_fsm_init(void)
{
OSMO_ASSERT(osmo_fsm_register(&hnb_shutdown_fsm) == 0);
}
bool hnb_shutdown_in_progress(const struct hnb *hnb)
{
const struct osmo_fsm_inst *fi = hnb->shutdown_fi;
return fi->state != HNB_SHUTDOWN_ST_NONE;
}
void hnb_shutdown(struct hnb *hnb, const char *reason, bool exit_proc)
{
struct osmo_fsm_inst *fi = hnb->shutdown_fi;
if (hnb_shutdown_in_progress(hnb)) {
LOGPFSML(fi, LOGL_NOTICE, "hNodeB is already being shutdown.\n");
if (exit_proc)
hnb->shutdown_fi_exit_proc = true;
return;
}
hnb->shutdown_fi_exit_proc = exit_proc;
LOGPFSML(fi, LOGL_NOTICE, "Shutting down hNodeB, exit %u, reason: %s\n",
exit_proc, reason);
osmo_fsm_inst_dispatch(fi, HNB_SHUTDOWN_EV_START, NULL);
}

View File

@ -37,6 +37,7 @@
#include <osmocom/hnodeb/hnbap.h>
#include <osmocom/hnodeb/rua.h>
#include <osmocom/hnodeb/hnodeb.h>
#include <osmocom/hnodeb/hnb_shutdown_fsm.h>
static int get_logevel_by_sn_type(int sn_type)
{
@ -100,12 +101,13 @@ static int hnb_iuh_read_cb(struct osmo_stream_cli *conn)
NULL, NULL, &sinfo, &flags);
if (rc < 0) {
LOGP(DSCTP, LOGL_ERROR, "Error during sctp_recvmsg()\n");
/* FIXME: clean up after disappeared HNB */
osmo_stream_cli_close(conn);
hnb_shutdown(hnb, "sctp_recvmsg() error", false);
goto free_ret;
} else if (rc == 0) {
LOGP(DSCTP, LOGL_INFO, "Connection to HNBGW closed\n");
osmo_stream_cli_close(conn);
hnb_shutdown(hnb, "Iuh HNBGW conn closed", false);
rc = -1;
goto free_ret;
} else {
@ -115,6 +117,14 @@ static int hnb_iuh_read_cb(struct osmo_stream_cli *conn)
if (flags & MSG_NOTIFICATION) {
union sctp_notification *notif = (union sctp_notification *) msgb_data(msg);
log_sctp_notification(notif);
switch (notif->sn_header.sn_type) {
case SCTP_SHUTDOWN_EVENT:
osmo_fsm_inst_dispatch(hnb->shutdown_fi, HNB_SHUTDOWN_EV_START, NULL);
hnb_shutdown(hnb, "Iuh HNBGW conn notification (SCTP_SHUTDOWN_EVENT)", false);
break;
default:
break;
}
rc = 0;
goto free_ret;
}