pespin has uploaded this change for review.
Implement ITU Q.704 timer T8
Related: OS#6892
Change-Id: I27ebf7327448554a6e4600e45a4ab0343ab846a4
---
M src/mtp3_rtpc.c
M src/ss7_instance.c
M src/ss7_instance.h
M src/ss7_vty.c
4 files changed, 190 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-sigtran refs/changes/26/41526/1
diff --git a/src/mtp3_rtpc.c b/src/mtp3_rtpc.c
index 1ce5c25..34d40e7 100644
--- a/src/mtp3_rtpc.c
+++ b/src/mtp3_rtpc.c
@@ -68,7 +68,15 @@
struct osmo_ss7_route_label rtlabel;
struct osmo_ss7_route *rt;
- /* TODO: Start T8 */
+ /* Start T8 */
+ if (ss7_instance_t8_inaccessible_sp_running(inst, orig_xua->mtp.dpc)) {
+ /* T8 is running for this SP, inhibit Tx of transfer prohibited */
+ LOGSS7(inst, LOGL_DEBUG, "Tx TFP (DUNA) inaccessible SP %u=%s to concerned SP %u=%s: inhibit due to T8\n",
+ orig_xua->mtp.dpc, osmo_ss7_pointcode_print_buf(buf_orig_dpc, sizeof(buf_orig_dpc), inst, orig_xua->mtp.dpc),
+ orig_xua->mtp.opc, osmo_ss7_pointcode_print_buf(buf_orig_opc, sizeof(buf_orig_opc), inst, orig_xua->mtp.opc));
+ return 0;
+ }
+ ss7_instance_t8_inaccessible_sp_start(inst, orig_xua->mtp.dpc);
/* "transfer prohibited RTPC -> HMRT", "To concerned SP or STP".
* See also Q.704 13.2 Transfer-prohibited. */
diff --git a/src/ss7_instance.c b/src/ss7_instance.c
index f8c78b4..b51f1b9 100644
--- a/src/ss7_instance.c
+++ b/src/ss7_instance.c
@@ -63,6 +63,25 @@
.ctr_desc = ss7_inst_rcd,
};
+const struct osmo_tdef ss7_instance_xua_timer_defaults[SS7_INST_XUA_TIMERS_LEN] = {
+ { .T = SS7_INST_XUA_T8, .default_val = SS7_INST_XUA_DEFAULT_T8_MSEC, .unit = OSMO_TDEF_MS,
+ .desc = "T8 - Transfer prohibited inhibition timer (transient solution) (ms)",
+ .min_val = 800, .max_val = 1200},
+ {}
+};
+
+/* ITU Q.704 16.8 Timers and timer values */
+const struct value_string ss7_instance_xua_timer_names[] = {
+ { SS7_INST_XUA_T8, "T8" },
+ {}
+};
+
+osmo_static_assert(ARRAY_SIZE(ss7_instance_xua_timer_defaults) == (SS7_INST_XUA_TIMERS_LEN) &&
+ ARRAY_SIZE(ss7_instance_xua_timer_names) == (SS7_INST_XUA_TIMERS_LEN),
+ assert_ss7_instance_xua_timer_count);
+
+static void t8_inaccessible_sp_timer_cb(void *_inst);
+
struct osmo_ss7_instance *
ss7_instance_alloc(void *ctx, uint32_t id)
{
@@ -84,6 +103,13 @@
INIT_LLIST_HEAD(&inst->asp_list);
INIT_LLIST_HEAD(&inst->rtable_list);
INIT_LLIST_HEAD(&inst->xua_servers);
+ INIT_LLIST_HEAD(&inst->t8_inaccessible_sp.list);
+
+ osmo_timer_setup(&inst->t8_inaccessible_sp.timer, t8_inaccessible_sp_timer_cb, inst);
+
+ inst->cfg.T_defs_xua = talloc_memdup(inst, ss7_instance_xua_timer_defaults,
+ sizeof(ss7_instance_xua_timer_defaults));
+ osmo_tdefs_reset(inst->cfg.T_defs_xua);
inst->ctrg = rate_ctr_group_alloc(inst, &ss7_inst_rcgd, id);
if (!inst->ctrg) {
@@ -124,6 +150,9 @@
llist_for_each_entry_safe(lset, lset2, &inst->linksets, list)
ss7_linkset_destroy(lset);
+ osmo_timer_del(&inst->t8_inaccessible_sp.timer);
+ /* Talloc takes care of freeing inst->t8_inaccessible_sp.list and its entries */
+
rate_ctr_group_free(inst->ctrg);
llist_del(&inst->list);
talloc_free(inst);
@@ -803,3 +832,61 @@
return NULL;
}
+
+
+static void t8_inaccessible_sp_timer_cb(void *_inst)
+{
+ struct osmo_ss7_instance *inst = _inst;
+ struct t8_inaccessible_sp_entry *it;
+ struct timespec ts_now, ts_t8;
+ char buf_dpc[MAX_PC_STR_LEN];
+
+ unsigned int t8_msec = osmo_tdef_get(inst->cfg.T_defs_xua, SS7_INST_XUA_T8, OSMO_TDEF_MS, -1);
+ ts_t8.tv_sec = (t8_msec/1000);
+ ts_t8.tv_nsec = (t8_msec%1000)*1000*1000;
+ osmo_clock_gettime(CLOCK_MONOTONIC, &ts_now);
+
+ while ((it = llist_first_entry_or_null(&inst->t8_inaccessible_sp.list, struct t8_inaccessible_sp_entry, entry))) {
+ struct timespec ts_expire;
+ timespecadd(&it->ts_started, &ts_t8, &ts_expire);
+ if (timespeccmp(&ts_expire, &ts_now, >)) {
+ struct timespec ts_diff;
+ timespecsub(&ts_expire, &ts_now, &ts_diff);
+ osmo_timer_schedule(&inst->t8_inaccessible_sp.timer, ts_diff.tv_sec, ts_diff.tv_nsec / 1000);
+ break;
+ }
+ LOGSS7(inst, LOGL_DEBUG, "T8: SP %u=%s: Timeout\n", it->dpc, osmo_ss7_pointcode_print_buf(buf_dpc, sizeof(buf_dpc), inst, it->dpc));
+ llist_del(&it->entry);
+ talloc_free(it);
+ }
+}
+
+bool ss7_instance_t8_inaccessible_sp_running(const struct osmo_ss7_instance *inst, uint32_t dpc)
+{
+ struct t8_inaccessible_sp_entry *it;
+ llist_for_each_entry(it, &inst->t8_inaccessible_sp.list, entry) {
+ if (it->dpc == dpc)
+ return true;
+ }
+ return false;
+}
+
+void ss7_instance_t8_inaccessible_sp_start(struct osmo_ss7_instance *inst, uint32_t dpc)
+{
+ struct t8_inaccessible_sp_entry *it;
+ char buf_dpc[MAX_PC_STR_LEN];
+
+ LOGSS7(inst, LOGL_DEBUG, "T8: SP %u=%s: Start\n",
+ dpc, osmo_ss7_pointcode_print_buf(buf_dpc, sizeof(buf_dpc), inst, dpc));
+
+ OSMO_ASSERT(!ss7_instance_t8_inaccessible_sp_running(inst, dpc));
+
+ it = talloc_zero(inst, struct t8_inaccessible_sp_entry);
+ it->dpc = dpc;
+ osmo_clock_gettime(CLOCK_MONOTONIC, &it->ts_started);
+ if (llist_empty(&inst->t8_inaccessible_sp.list)) {
+ unsigned int timeout_msec = osmo_tdef_get(inst->cfg.T_defs_xua, SS7_INST_XUA_T8, OSMO_TDEF_MS, -1);
+ osmo_timer_schedule(&inst->t8_inaccessible_sp.timer, (timeout_msec/1000), ((timeout_msec%1000)*10));
+ }
+ llist_add_tail(&it->entry, &inst->t8_inaccessible_sp.list);
+}
diff --git a/src/ss7_instance.h b/src/ss7_instance.h
index 3045403..29310f4 100644
--- a/src/ss7_instance.h
+++ b/src/ss7_instance.h
@@ -3,6 +3,9 @@
#include <stdint.h>
#include <stdbool.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/timer_compat.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/sigtran/protocol/mtp.h>
@@ -16,6 +19,17 @@
struct osmo_ss7_route_label;
struct osmo_sccp_instance;
+enum ss7_instance_xua_timer {
+ /* 0 kept unused on purpose since it's handled specially by osmo_fsm */
+ SS7_INST_XUA_T8 = 1, /* Q.704 T8 */
+ /* This must remain the last item: */
+ SS7_INST_XUA_TIMERS_LEN
+};
+extern const struct value_string ss7_instance_xua_timer_names[];
+extern const struct osmo_tdef ss7_instance_xua_timer_defaults[SS7_INST_XUA_TIMERS_LEN];
+/* According to SUA RFC3868 Section 8, M3UA RFC4666 Section 4.3.4.1 */
+#define SS7_INST_XUA_DEFAULT_T8_MSEC 1000
+
enum ss7_instance_ctr {
SS7_INST_CTR_PKT_RX_TOTAL,
SS7_INST_CTR_PKT_RX_UNKNOWN,
@@ -51,6 +65,13 @@
struct rate_ctr_group *ctrg;
+ /* Q.704 Figure 44 and section 13.2: List to store remote PCs with T8 started */
+ struct {
+ /* list of struct t8_inaccessible_sp_entry, sorted by entry->ts_started */
+ struct llist_head list;
+ struct osmo_timer_list timer;
+ } t8_inaccessible_sp;
+
struct {
uint32_t id;
char *name;
@@ -71,6 +92,9 @@
* to skip for routing decisions.
* range 0-3, defaults to 0, which means take all 4 bits. */
uint8_t sls_shift;
+
+ /* T_defs defined at instance level: */
+ struct osmo_tdef *T_defs_xua;
} cfg;
};
@@ -85,3 +109,15 @@
LOGP(subsys, level, "%u: " fmt, inst ? (inst)->cfg.id : 0, ## args)
#define LOGSS7(inst, level, fmt, args ...) \
_LOGSS7(inst, DLSS7, level, fmt, ## args)
+
+
+/***********************************************************************
+ * ITUQ.704 13.2.2: Timer T8 concerning one SP
+ ***********************************************************************/
+struct t8_inaccessible_sp_entry {
+ struct llist_head entry; /* item in (struct osmo_ss7_instance)->t8_inaccessible_sp.list */
+ uint32_t dpc; /* SP inaccessible */
+ struct timespec ts_started; /* Timestamp T8 was started for this SP */
+};
+bool ss7_instance_t8_inaccessible_sp_running(const struct osmo_ss7_instance *inst, uint32_t dpc);
+void ss7_instance_t8_inaccessible_sp_start(struct osmo_ss7_instance *inst, uint32_t dpc);
diff --git a/src/ss7_vty.c b/src/ss7_vty.c
index 98c6073..ff95f4f 100644
--- a/src/ss7_vty.c
+++ b/src/ss7_vty.c
@@ -279,6 +279,61 @@
return CMD_SUCCESS;
}
+/* timer xua <name> <1-999999>
+ * (cmdstr and doc are dynamically generated from ss7_instance_xua_timer_names.) */
+DEFUN_ATTR(cs7_timer_xua, cs7_timer_xua_cmd,
+ NULL, NULL, CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_instance *inst = vty->index;
+ enum ss7_instance_xua_timer timer = get_string_value(ss7_instance_xua_timer_names, argv[0]);
+
+ if (timer <= 0 || timer >= SS7_INST_XUA_TIMERS_LEN) {
+ vty_out(vty, "%% Invalid timer: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ osmo_tdef_set(inst->cfg.T_defs_xua, timer, atoi(argv[1]), OSMO_TDEF_S);
+ return CMD_SUCCESS;
+}
+
+static void gen_cs7_timer_xua_cmd_strs(struct cmd_element *cmd)
+{
+ int i;
+ char *cmd_str = NULL;
+ char *doc_str = NULL;
+
+ OSMO_ASSERT(cmd->string == NULL);
+ OSMO_ASSERT(cmd->doc == NULL);
+
+ osmo_talloc_asprintf(tall_vty_ctx, cmd_str, "timer xua (");
+ osmo_talloc_asprintf(tall_vty_ctx, doc_str,
+ "Configure CS7 Instance default timer values\n"
+ "Configure CS7 Instance default xua timer values\n");
+
+ for (i = 0; ss7_instance_xua_timer_names[i].str; i++) {
+ const struct osmo_tdef *def;
+ enum ss7_asp_xua_timer timer;
+
+ timer = ss7_instance_xua_timer_names[i].value;
+ def = osmo_tdef_get_entry((struct osmo_tdef *)&ss7_instance_xua_timer_defaults, timer);
+ OSMO_ASSERT(def);
+
+ osmo_talloc_asprintf(tall_vty_ctx, cmd_str, "%s%s",
+ i ? "|" : "",
+ ss7_instance_xua_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>");
+ osmo_talloc_asprintf(tall_vty_ctx, doc_str,
+ "Timer value, in seconds\n");
+
+ cmd->string = cmd_str;
+ cmd->doc = doc_str;
+}
+
static void write_one_cs7(struct vty *vty, struct osmo_ss7_instance *inst, bool show_dyn_config);
static int write_all_cs7(struct vty *vty, bool show_dyn_config)
@@ -1482,6 +1537,9 @@
cs7_role = CS7_ROLE_SG;
vty_init_shared(ctx);
+ gen_cs7_timer_xua_cmd_strs(&cs7_timer_xua_cmd);
+ install_lib_element(L_CS7_NODE, &cs7_timer_xua_cmd);
+
install_node(&rtable_node, NULL);
install_lib_element(L_CS7_NODE, &cs7_route_table_cmd);
install_lib_element(L_CS7_RTABLE_NODE, &cfg_description_cmd);
To view, visit change 41526. To unsubscribe, or for help writing mail filters, visit settings.