diff --git a/include/osmocom/hnodeb/Makefile.am b/include/osmocom/hnodeb/Makefile.am index 23adb2a..b1acb7e 100644 --- a/include/osmocom/hnodeb/Makefile.am +++ b/include/osmocom/hnodeb/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = \ + hnb_shutdown_fsm.h \ hnbap.h \ hnodeb.h \ iuh.h \ diff --git a/include/osmocom/hnodeb/hnb_shutdown_fsm.h b/include/osmocom/hnodeb/hnb_shutdown_fsm.h new file mode 100644 index 0000000..dc9b357 --- /dev/null +++ b/include/osmocom/hnodeb/hnb_shutdown_fsm.h @@ -0,0 +1,42 @@ +/* hNodeB shutdown FSM */ + +/* (C) 2021 by sysmocom - s.m.f.c. GmbH + * Author: Pau Espin Pedrol + * + * 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 . + * + */ + +#pragma once + +#include + +#include + +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); diff --git a/include/osmocom/hnodeb/hnodeb.h b/include/osmocom/hnodeb/hnodeb.h index deb683f..3bc2fb3 100644 --- a/include/osmocom/hnodeb/hnodeb.h +++ b/include/osmocom/hnodeb/hnodeb.h @@ -26,6 +26,7 @@ #include #include #include +#include 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; diff --git a/src/osmo-hnodeb/Makefile.am b/src/osmo-hnodeb/Makefile.am index 88f2571..7325728 100644 --- a/src/osmo-hnodeb/Makefile.am +++ b/src/osmo-hnodeb/Makefile.am @@ -33,6 +33,7 @@ osmo_hnodeb_SOURCES = \ debug.c \ hnbap.c \ hnb.c \ + hnb_shutdown_fsm.c \ iuh.c \ nas.c \ ranap.c \ diff --git a/src/osmo-hnodeb/hnb.c b/src/osmo-hnodeb/hnb.c index 3344cfb..b7be4ea 100644 --- a/src/osmo-hnodeb/hnb.c +++ b/src/osmo-hnodeb/hnb.c @@ -26,6 +26,7 @@ #include #include +#include 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); } diff --git a/src/osmo-hnodeb/hnb_shutdown_fsm.c b/src/osmo-hnodeb/hnb_shutdown_fsm.c new file mode 100644 index 0000000..55de64c --- /dev/null +++ b/src/osmo-hnodeb/hnb_shutdown_fsm.c @@ -0,0 +1,134 @@ +/* hNodeB shutdown FSM */ + +/* (C) 2021 by sysmocom - s.m.f.c. GmbH + * Author: Pau Espin Pedrol + * + * 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 . + * + */ + +#include +#include + +#include +#include +#include +#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); +} diff --git a/src/osmo-hnodeb/iuh.c b/src/osmo-hnodeb/iuh.c index 3153206..79df371 100644 --- a/src/osmo-hnodeb/iuh.c +++ b/src/osmo-hnodeb/iuh.c @@ -37,6 +37,7 @@ #include #include #include +#include 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; }