sccp: Use tdef to implement osmo_sccp_timers

Related: OS#4372
Change-Id: I1dbe49a83a1bcddf074d5e638babd065834a0ebd
This commit is contained in:
Pau Espin 2023-07-07 17:14:16 +02:00
parent 1532791798
commit c086a8ed42
4 changed files with 56 additions and 121 deletions

View File

@ -4,6 +4,7 @@
#include <osmocom/core/prim.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/linuxrbtree.h>
#include <osmocom/core/tdef.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/sigtran/osmo_ss7.h>
#include <osmocom/sigtran/protocol/mtp.h>
@ -12,7 +13,8 @@
/* Appendix C.4 of Q.714 */
enum osmo_sccp_timer {
OSMO_SCCP_TIMER_CONN_EST,
/* 0 kept unused on purpose since it's handled specially by osmo_fsm */
OSMO_SCCP_TIMER_CONN_EST = 1,
OSMO_SCCP_TIMER_IAS,
OSMO_SCCP_TIMER_IAR,
OSMO_SCCP_TIMER_REL,
@ -22,24 +24,15 @@ enum osmo_sccp_timer {
OSMO_SCCP_TIMER_RESET,
OSMO_SCCP_TIMER_REASSEMBLY,
/* This must remain the last item: */
OSMO_SCCP_TIMERS_COUNT
OSMO_SCCP_TIMERS_LEN
};
struct osmo_sccp_timer_val {
uint32_t s;
uint32_t us;
};
extern const struct osmo_sccp_timer_val osmo_sccp_timer_defaults[];
extern const struct osmo_tdef osmo_sccp_timer_defaults[OSMO_SCCP_TIMERS_LEN];
extern const struct value_string osmo_sccp_timer_names[];
static inline const char *osmo_sccp_timer_name(enum osmo_sccp_timer val)
{ return get_value_string(osmo_sccp_timer_names, val); }
extern const struct value_string osmo_sccp_timer_descriptions[];
static inline const char *osmo_sccp_timer_description(enum osmo_sccp_timer val)
{ return get_value_string(osmo_sccp_timer_descriptions, val); }
/* an instance of the SCCP stack */
struct osmo_sccp_instance {
/* entry in global list of ss7 instances */
@ -57,7 +50,7 @@ struct osmo_sccp_instance {
struct osmo_ss7_user ss7_user;
struct osmo_sccp_timer_val timers[OSMO_SCCP_TIMERS_COUNT];
struct osmo_tdef *tdefs;
uint32_t max_optional_data;
};
@ -129,10 +122,6 @@ extern struct osmo_fsm sccp_scoc_fsm;
void sccp_scoc_show_connections(struct vty *vty, struct osmo_sccp_instance *inst);
const struct osmo_sccp_timer_val *osmo_sccp_timer_get(const struct osmo_sccp_instance *inst,
enum osmo_sccp_timer timer,
bool default_if_unset);
void osmo_sccp_vty_write_cs7_node(struct vty *vty, const char *indent, struct osmo_sccp_instance *inst);
/* Local Broadcast (LBCS) */

View File

@ -234,6 +234,31 @@ static const struct osmo_prim_event_map scu_scoc_event_map[] = {
* Timer Handling
***********************************************************************/
/* Mostly pasted from Appendix C.4 of ITU-T Q.714 (05/2001) -- some of their descriptions are quite
* unintelligible out of context, for which we have our own description here. */
const struct osmo_tdef osmo_sccp_timer_defaults[OSMO_SCCP_TIMERS_LEN] = {
{ .T = OSMO_SCCP_TIMER_CONN_EST, .default_val = 1*60, .unit = OSMO_TDEF_S,
.desc = "Waiting for connection confirm message, 1 to 2 minutes" },
{ .T = OSMO_SCCP_TIMER_IAS, .default_val = 7*60, .unit = OSMO_TDEF_S,
.desc = "Send keep-alive: on an idle connection, delay before sending an Idle Timer message, 5 to 10 minutes" }, /* RFC 3868 Ch. 8. */
{ .T = OSMO_SCCP_TIMER_IAR, .default_val = 15*60, .unit = OSMO_TDEF_S,
.desc = "Receive keep-alive: on an idle connection, delay until considering a connection as stale, 11 to 21 minutes" }, /* RFC 3868 Ch. 8. */
{ .T = OSMO_SCCP_TIMER_REL, .default_val = 10, .unit = OSMO_TDEF_S,
.desc = "Waiting for release complete message, 10 to 20 seconds" },
{ .T = OSMO_SCCP_TIMER_REPEAT_REL, .default_val = 10, .unit = OSMO_TDEF_S,
.desc = "Waiting for release complete message; or to repeat sending released message after the initial expiry, 10 to 20 seconds" },
{ .T = OSMO_SCCP_TIMER_INT, .default_val = 1*60, .unit = OSMO_TDEF_S,
.desc = "Waiting for release complete message; or to release connection resources, freeze the LRN and "
"alert a maintenance function after the initial expiry, extending to 1 minute" },
{ .T = OSMO_SCCP_TIMER_GUARD, .default_val = 23*60, .unit = OSMO_TDEF_S,
.desc = "Waiting to resume normal procedure for temporary connection sections during the restart procedure, 23 to 25 minutes" },
{ .T = OSMO_SCCP_TIMER_RESET, .default_val = 10, .unit = OSMO_TDEF_S,
.desc = "Waiting to release temporary connection section or alert maintenance function after reset request message is sent, 10 to 20 seconds" },
{ .T = OSMO_SCCP_TIMER_REASSEMBLY, .default_val = 10, .unit = OSMO_TDEF_S,
.desc = "Waiting to receive all the segments of the remaining segments, single segmented message after receiving the first segment, 10 to 20 seconds" },
{}
};
/* Appendix C.4 of ITU-T Q.714 */
const struct value_string osmo_sccp_timer_names[] = {
{ OSMO_SCCP_TIMER_CONN_EST, "conn_est" },
@ -248,93 +273,16 @@ const struct value_string osmo_sccp_timer_names[] = {
{}
};
/* Mostly pasted from Appendix C.4 of ITU-T Q.714 (05/2001) -- some of their descriptions are quite
* unintelligible out of context, for which we have our own description here. */
const struct value_string osmo_sccp_timer_descriptions[] = {
{ OSMO_SCCP_TIMER_CONN_EST,
"Waiting for connection confirm message, 1 to 2 minutes" },
{ OSMO_SCCP_TIMER_IAS,
"Send keep-alive: on an idle connection, delay before sending an Idle Timer message,"
" 5 to 10 minutes" },
{ OSMO_SCCP_TIMER_IAR,
"Receive keep-alive: on an idle connection, delay until considering a connection as stale,"
" 11 to 21 minutes" },
{ OSMO_SCCP_TIMER_REL,
"Waiting for release complete message, 10 to 20 seconds" },
{ OSMO_SCCP_TIMER_REPEAT_REL,
"Waiting for release complete message; or to repeat sending released message after the initial"
" expiry, 10 to 20 seconds" },
{ OSMO_SCCP_TIMER_INT,
"Waiting for release complete message; or to release connection resources, freeze the LRN and"
" alert a maintenance function after the initial expiry, extending to 1 minute" },
{ OSMO_SCCP_TIMER_GUARD,
"Waiting to resume normal procedure for temporary connection sections during the restart"
" procedure, 23 to 25 minutes" },
{ OSMO_SCCP_TIMER_RESET,
"Waiting to release temporary connection section or alert maintenance function after reset"
" request message is sent, 10 to 20 seconds" },
{ OSMO_SCCP_TIMER_REASSEMBLY,
"Waiting to receive all the segments of the remaining segments, single segmented message after"
" receiving the first segment, 10 to 20 seconds" },
{}
};
/* Appendix C.4 of ITU-T Q.714 */
const struct osmo_sccp_timer_val osmo_sccp_timer_defaults[] = {
[OSMO_SCCP_TIMER_CONN_EST] = { .s = 1 * 60, },
[OSMO_SCCP_TIMER_IAS] = { .s = 7 * 60, }, /* RFC 3868 Ch. 8. */
[OSMO_SCCP_TIMER_IAR] = { .s = 15 * 60, }, /* RFC 3868 Ch. 8. */
[OSMO_SCCP_TIMER_REL] = { .s = 10, },
[OSMO_SCCP_TIMER_REPEAT_REL] = { .s = 10, },
[OSMO_SCCP_TIMER_INT] = { .s = 1 * 60, },
[OSMO_SCCP_TIMER_GUARD] = { .s = 23 * 60, },
[OSMO_SCCP_TIMER_RESET] = { .s = 10, },
[OSMO_SCCP_TIMER_REASSEMBLY] = { .s = 10, },
};
osmo_static_assert(ARRAY_SIZE(osmo_sccp_timer_defaults) == OSMO_SCCP_TIMERS_COUNT,
osmo_static_assert(ARRAY_SIZE(osmo_sccp_timer_defaults) == (OSMO_SCCP_TIMERS_LEN) &&
ARRAY_SIZE(osmo_sccp_timer_names) == (OSMO_SCCP_TIMERS_LEN),
assert_osmo_sccp_timers_count);
/* Look up an SCCP timer value as configured in the osmo_ss7_instance.
* If no user defined value is set, return the global default from osmo_sccp_timer_defaults instead.
* However, if default_if_unset is passed false, return NULL in case there is no user defined setting, or
* in case it is identical to the global default. */
const struct osmo_sccp_timer_val *osmo_sccp_timer_get(const struct osmo_sccp_instance *inst,
enum osmo_sccp_timer timer,
bool default_if_unset)
{
const struct osmo_sccp_timer_val *val;
const struct osmo_sccp_timer_val *def;
OSMO_ASSERT(timer >= 0
&& timer < ARRAY_SIZE(inst->timers)
&& timer < ARRAY_SIZE(osmo_sccp_timer_defaults));
val = &inst->timers[timer];
def = &osmo_sccp_timer_defaults[timer];
/* Assert that all timer definitions have a sane global default */
OSMO_ASSERT(def->s || def->us);
if (val->s || val->us) {
if (!default_if_unset && val->s == def->s && val->us == def->us)
return NULL;
return val;
}
if (!default_if_unset)
return NULL;
/* If unset, use the global default. */
return def;
}
static void sccp_timer_schedule(const struct sccp_connection *conn,
struct osmo_timer_list *timer,
enum osmo_sccp_timer timer_name)
{
const struct osmo_sccp_timer_val *val = osmo_sccp_timer_get(conn->inst, timer_name, true);
osmo_timer_schedule(timer, val->s, val->us);
const unsigned long val_sec = osmo_tdef_get(conn->inst->tdefs, timer_name, OSMO_TDEF_S, -1);
osmo_timer_schedule(timer, val_sec, 0);
}
/* T(ias) has expired, send a COIT message to the peer */

View File

@ -238,6 +238,10 @@ osmo_sccp_instance_create(struct osmo_ss7_instance *ss7, void *priv)
inst->ss7_user.priv = inst;
inst->max_optional_data = SCCP_MAX_OPTIONAL_DATA;
inst->tdefs = talloc_memdup(inst, osmo_sccp_timer_defaults,
sizeof(osmo_sccp_timer_defaults));
osmo_tdefs_reset(inst->tdefs);
rc = sccp_scmg_init(inst);
if (rc < 0) {
talloc_free(inst);

View File

@ -150,9 +150,8 @@ DEFUN_ATTR(sccp_timer, sccp_timer_cmd,
{
struct osmo_ss7_instance *ss7 = vty->index;
enum osmo_sccp_timer timer = get_string_value(osmo_sccp_timer_names, argv[0]);
struct osmo_sccp_timer_val set_val = { .s = atoi(argv[1]) };
if (timer < 0 || timer >= OSMO_SCCP_TIMERS_COUNT) {
if (timer <= 0 || timer >= OSMO_SCCP_TIMERS_LEN) {
vty_out(vty, "%% Invalid timer: %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
@ -163,7 +162,8 @@ DEFUN_ATTR(sccp_timer, sccp_timer_cmd,
return CMD_WARNING;
}
ss7->sccp->timers[timer] = set_val;
OSMO_ASSERT(ss7->sccp->tdefs);
osmo_tdef_set(ss7->sccp->tdefs, timer, atoi(argv[1]), OSMO_TDEF_S);
return CMD_SUCCESS;
}
@ -197,14 +197,6 @@ DEFUN_ATTR(sccp_max_optional_data, sccp_max_optional_data_cmd,
return CMD_SUCCESS;
}
static const char *osmo_sccp_timer_val_name(const struct osmo_sccp_timer_val *val)
{
static char buf[16];
snprintf(buf, sizeof(buf), "%u", val->s);
return buf;
}
static void gen_sccp_timer_cmd_strs(struct cmd_element *cmd)
{
int i;
@ -219,19 +211,19 @@ static void gen_sccp_timer_cmd_strs(struct cmd_element *cmd)
"Configure SCCP timer values, see ITU-T Q.714\n");
for (i = 0; osmo_sccp_timer_names[i].str; i++) {
const struct osmo_sccp_timer_val *def;
const struct osmo_tdef *def;
enum osmo_sccp_timer timer;
timer = osmo_sccp_timer_names[i].value;
def = &osmo_sccp_timer_defaults[timer];
OSMO_ASSERT(timer >= 0 && timer < OSMO_SCCP_TIMERS_COUNT);
def = osmo_tdef_get_entry((struct osmo_tdef *)&osmo_sccp_timer_defaults, timer);
OSMO_ASSERT(def);
osmo_talloc_asprintf(tall_vty_ctx, cmd_str, "%s%s",
i ? "|" : "",
osmo_sccp_timer_name(timer));
osmo_talloc_asprintf(tall_vty_ctx, doc_str, "%s (default: %s)\n",
osmo_sccp_timer_description(timer),
osmo_sccp_timer_val_name(def));
osmo_sccp_timer_names[i].str);
osmo_talloc_asprintf(tall_vty_ctx, doc_str, "%s (default: %lu)\n",
def->desc,
def->default_val);
}
osmo_talloc_asprintf(tall_vty_ctx, cmd_str, ") <1-999999>");
@ -247,12 +239,14 @@ static void write_sccp_timers(struct vty *vty, const char *indent,
{
int i;
for (i = 0; i < ARRAY_SIZE(inst->timers); i++) {
const struct osmo_sccp_timer_val *val = osmo_sccp_timer_get(inst, i, default_if_unset);
if (!val)
for (i = 0; osmo_sccp_timer_names[i].str; i++) {
const struct osmo_tdef *tdef = osmo_tdef_get_entry(inst->tdefs, osmo_sccp_timer_names[i].value);
if (!tdef)
continue;
vty_out(vty, "%ssccp-timer %s %s%s", indent, osmo_sccp_timer_name(i),
osmo_sccp_timer_val_name(val), VTY_NEWLINE);
if (!default_if_unset && tdef->val == tdef->default_val)
continue;
vty_out(vty, "%ssccp-timer %s %lu%s", indent, osmo_sccp_timer_names[i].str,
tdef->val, VTY_NEWLINE);
}
}