pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/40556?usp=email )
Change subject: Introduce initial route status support ......................................................................
Introduce initial route status support
Mark route avail/unavail based on DAVA/DUNA from SG.
Related: OS#6754 Change-Id: Icb4f78f8da9de5a611cb6311722bf3acf1a68fc5 --- M src/ss7.c M src/ss7_combined_linkset.c M src/ss7_combined_linkset.h M src/ss7_internal.h M src/ss7_route.c M src/ss7_route.h M src/ss7_route_table.c M src/ss7_route_table.h M src/ss7_vty.c M src/xua_snm.c M tests/vty/osmo_stp_route_prio.vty 11 files changed, 178 insertions(+), 20 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-sigtran refs/changes/56/40556/1
diff --git a/src/ss7.c b/src/ss7.c index 902479d..e2f2ca9 100644 --- a/src/ss7.c +++ b/src/ss7.c @@ -89,13 +89,18 @@ return pc_fmt->component_len[0] + pc_fmt->component_len[1] + pc_fmt->component_len[2]; }
+/* Obtain a full-width mask matching a single DPC in this ss7_instance. */ +uint32_t ss7_pc_full_mask(const struct osmo_ss7_pc_fmt *pc_fmt) +{ + return (1 << osmo_ss7_pc_width(pc_fmt)) - 1; +} + /* truncate pc or mask to maximum permitted length. This solves * callers specifying arbitrary large masks which then evade duplicate * detection with longer mask lengths */ uint32_t osmo_ss7_pc_normalize(const struct osmo_ss7_pc_fmt *pc_fmt, uint32_t pc) { - uint32_t mask = (1 << osmo_ss7_pc_width(pc_fmt))-1; - return pc & mask; + return pc & ss7_pc_full_mask(pc_fmt); }
/*********************************************************************** diff --git a/src/ss7_combined_linkset.c b/src/ss7_combined_linkset.c index eb19b85..0b6dd3c 100644 --- a/src/ss7_combined_linkset.c +++ b/src/ss7_combined_linkset.c @@ -172,6 +172,20 @@ ss7_combined_linkset_free(clset); }
+/* Whether any route in the combined linkset is available: */ +bool ss7_combined_linkset_is_available(const struct osmo_ss7_combined_linkset *clset) +{ + bool avail = false; + struct osmo_ss7_route *rt; + llist_for_each_entry(rt, &clset->routes, list) { + if (ss7_route_is_available(rt)) { + avail = true; + break; + } + } + return avail; +} + static ext_sls_t osmo_ss7_instance_calc_itu_ext_sls(const struct osmo_ss7_instance *inst, const struct osmo_ss7_route_label *rtlabel) { /* Take 6 bits from OPC and DPC according to config: */ diff --git a/src/ss7_combined_linkset.h b/src/ss7_combined_linkset.h index 432ebd7..e3756b6 100644 --- a/src/ss7_combined_linkset.h +++ b/src/ss7_combined_linkset.h @@ -57,6 +57,7 @@ ss7_combined_linkset_del_route(struct osmo_ss7_route *rt); struct osmo_ss7_route * ss7_combined_linkset_lookup_route(struct osmo_ss7_combined_linkset *clset, const struct osmo_ss7_route_label *rtlabel); +bool ss7_combined_linkset_is_available(const struct osmo_ss7_combined_linkset *clset);
#define LOGPCLSET(clset, subsys, level, fmt, args ...) do { \ char _pc_str[MAX_PC_STR_LEN]; \ diff --git a/src/ss7_internal.h b/src/ss7_internal.h index d931351..cfa092a 100644 --- a/src/ss7_internal.h +++ b/src/ss7_internal.h @@ -15,6 +15,8 @@
bool ss7_ipv6_sctp_supported(const char *host, bool bind);
+uint32_t ss7_pc_full_mask(const struct osmo_ss7_pc_fmt *pc_fmt); + struct osmo_ss7_asp *ss7_asp_find_by_socket_addr(int fd, int trans_proto);
bool ss7_asp_protocol_check_trans_proto(enum osmo_ss7_asp_protocol proto, int trans_proto); diff --git a/src/ss7_route.c b/src/ss7_route.c index ec41a8a..c432c49 100644 --- a/src/ss7_route.c +++ b/src/ss7_route.c @@ -38,6 +38,14 @@ * SS7 Routes ***********************************************************************/
+ /* ITU Q.704 3.4 Status of signalling routes */ +const struct value_string ss7_route_status_names[] = { + { OSMO_SS7_ROUTE_STATUS_UNAVAILABLE, "unavailable" }, + { OSMO_SS7_ROUTE_STATUS_AVAILABLE, "available" }, + { OSMO_SS7_ROUTE_STATUS_RESTRICTED, "restricted" }, + {} +}; + /*! \brief Allocate a route entry * \param[in] rtbl Routing Table where the route belongs * \param[in] pc Point Code of the destination of the route @@ -79,6 +87,7 @@ /* Mark it as not being inserted yet in rtbl */ INIT_LLIST_HEAD(&rt->list); rt->rtable = rtbl; + rt->status = OSMO_SS7_ROUTE_STATUS_AVAILABLE; /* truncate mask to maximum. Let's avoid callers specifying arbitrary large * masks to ensure we don't fail duplicate detection with longer mask lengths */ rt->cfg.mask = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, mask); @@ -374,9 +383,29 @@ bool ss7_route_is_available(const struct osmo_ss7_route *rt) { OSMO_ASSERT(rt); + if (!ss7_route_dest_is_available(rt)) + return false; + return rt->status == OSMO_SS7_ROUTE_STATUS_AVAILABLE; +} + +bool ss7_route_dest_is_available(const struct osmo_ss7_route *rt) +{ + OSMO_ASSERT(rt); if (rt->dest.as) return osmo_ss7_as_active(rt->dest.as); if (rt->dest.linkset) return ss7_linkset_is_available(rt->dest.linkset); return false; } + +/* Whether route mask identifies a single DPC. */ +bool ss7_route_is_fully_qualified(const struct osmo_ss7_route *rt) +{ + return rt->cfg.mask == ss7_pc_full_mask(&rt->rtable->inst->cfg.pc_fmt); +} + +void ss7_route_update_route_status(struct osmo_ss7_route *rt, enum osmo_ss7_route_status status) +{ + LOGPRT(rt, DLSS7, LOGL_NOTICE, "changed to status '%s'\n", ss7_route_status_name(status)); + rt->status = status; +} diff --git a/src/ss7_route.h b/src/ss7_route.h index 7ba7ba5..2e35d1f 100644 --- a/src/ss7_route.h +++ b/src/ss7_route.h @@ -15,6 +15,16 @@
#define OSMO_SS7_ROUTE_PRIO_DEFAULT 5
+/* ITU Q.704 3.4 Status of signalling routes */ +enum osmo_ss7_route_status { + OSMO_SS7_ROUTE_STATUS_UNAVAILABLE, + OSMO_SS7_ROUTE_STATUS_AVAILABLE, + OSMO_SS7_ROUTE_STATUS_RESTRICTED, +}; +extern const struct value_string ss7_route_status_names[]; +static inline const char *ss7_route_status_name(enum osmo_ss7_route_status val) +{ return get_value_string(ss7_route_status_names, val); } + struct osmo_ss7_route { /*! member in \ref osmo_ss7_combined_linkset.routes */ struct llist_head list; @@ -23,6 +33,8 @@ /* Combined linkset this route is part of */ struct osmo_ss7_combined_linkset *clset;
+ enum osmo_ss7_route_status status; + struct { /*! pointer to linkset (destination) of route */ struct osmo_ss7_linkset *linkset; @@ -59,15 +71,26 @@ int ss7_route_set_linkset(struct osmo_ss7_route *rt, const char *linkset_name); int ss7_route_insert(struct osmo_ss7_route *rt);
+bool ss7_route_dest_is_available(const struct osmo_ss7_route *rt); bool ss7_route_is_available(const struct osmo_ss7_route *rt); + +bool ss7_route_is_fully_qualified(const struct osmo_ss7_route *rt); +static inline bool ss7_route_is_summary(const struct osmo_ss7_route *rt) +{ + return !ss7_route_is_fully_qualified(rt); +} + +void ss7_route_update_route_status(struct osmo_ss7_route *rt, enum osmo_ss7_route_status status); + #define LOGPRT(rt, subsys, level, fmt, args ...) do { \ char _pc_str[MAX_PC_STR_LEN]; \ char _mask_str[MAX_PC_STR_LEN]; \ _LOGSS7((rt)->rtable->inst, subsys, level, \ - "RT(dpc=%u=%s,mask=0x%x=%s,prio=%u,via=%s) " fmt, \ + "RT(dpc=%u=%s,mask=0x%x=%s,prio=%u,via=%s,st=%s) " fmt, \ (rt)->cfg.pc, osmo_ss7_pointcode_print_buf(_pc_str, MAX_PC_STR_LEN, (rt)->rtable->inst, (rt)->cfg.pc), \ (rt)->cfg.mask, osmo_ss7_pointcode_print_buf(_mask_str, MAX_PC_STR_LEN, (rt)->rtable->inst, (rt)->cfg.mask), \ (rt)->cfg.priority, \ (rt)->cfg.linkset_name ? (rt)->cfg.linkset_name : "", \ + ss7_route_status_name((rt)->status), \ ## args); \ } while (0) diff --git a/src/ss7_route_table.c b/src/ss7_route_table.c index 0b53889..4b5e044 100644 --- a/src/ss7_route_table.c +++ b/src/ss7_route_table.c @@ -203,6 +203,25 @@ return clset; }
+void ss7_route_table_update_route_status_by_as(struct osmo_ss7_route_table *rtbl, enum osmo_ss7_route_status status, + const struct osmo_ss7_as *as, uint32_t dpc) +{ + struct osmo_ss7_combined_linkset *clset; + + llist_for_each_entry(clset, &rtbl->combined_linksets, list) { + struct osmo_ss7_route *rt; + llist_for_each_entry(rt, &clset->routes, list) { + if (rt->dest.as != as) + continue; + if (rt->cfg.pc != dpc) + continue; + if (ss7_route_is_summary(rt)) + continue; /* Only interested in fully qualified routes */ + ss7_route_update_route_status(rt, status); + } + } +} + /* find any routes pointing to this AS and remove them */ void ss7_route_table_del_routes_by_as(struct osmo_ss7_route_table *rtbl, struct osmo_ss7_as *as) { diff --git a/src/ss7_route_table.h b/src/ss7_route_table.h index 9f27412..1155600 100644 --- a/src/ss7_route_table.h +++ b/src/ss7_route_table.h @@ -9,6 +9,7 @@ ***********************************************************************/
struct osmo_ss7_instance; +enum osmo_ss7_route_status;
struct osmo_ss7_route_label { uint32_t opc; @@ -54,5 +55,7 @@ struct osmo_ss7_combined_linkset * ss7_route_table_find_combined_linkset(struct osmo_ss7_route_table *rtbl, uint32_t dpc, uint32_t mask, uint32_t prio);
+void ss7_route_table_update_route_status_by_as(struct osmo_ss7_route_table *rtbl, enum osmo_ss7_route_status status, + const struct osmo_ss7_as *as, uint32_t dpc); void ss7_route_table_del_routes_by_as(struct osmo_ss7_route_table *rtbl, struct osmo_ss7_as *as); void ss7_route_table_del_routes_by_linkset(struct osmo_ss7_route_table *rtbl, struct osmo_ss7_linkset *lset); diff --git a/src/ss7_vty.c b/src/ss7_vty.c index ab9784c..9e9ceaa 100644 --- a/src/ss7_vty.c +++ b/src/ss7_vty.c @@ -515,23 +515,48 @@ if ((filter_pc != OSMO_SS7_PC_INVALID) && ((filter_pc & clset->cfg.mask) != clset->cfg.pc)) continue; /* Skip combined linksets not matching destination */
+ bool clset_avail = ss7_combined_linkset_is_available(clset); llist_for_each_entry(rt, &clset->routes, list) { - bool rt_avail = ss7_route_is_available(rt); + bool dst_avail = ss7_route_dest_is_available(rt); bool first_rt_in_clset = (rt == llist_first_entry(&clset->routes, struct osmo_ss7_route, list)); + const char *nonadj_str, *rtavail_str; /* Print route str only in first rt in combined linkset. * This allows users to easily determine visually combined * linksets: */ - const char *rt_str = first_rt_in_clset ? osmo_ss7_route_print(rt) : ""; + const char *rt_str, *clsetavail_str; + if (first_rt_in_clset) { + rt_str = osmo_ss7_route_print(rt); + clsetavail_str = clset_avail ? "acces" : "INACC"; + } else { + rt_str = ""; + clsetavail_str = ""; + } + switch (rt->status) { + case OSMO_SS7_ROUTE_STATUS_UNAVAILABLE: + nonadj_str = "PROHIB"; + rtavail_str = "UNAVAIL"; + break; + case OSMO_SS7_ROUTE_STATUS_AVAILABLE: + nonadj_str = "allowed"; + rtavail_str = dst_avail ? "avail" : "UNAVAIL"; + break; + case OSMO_SS7_ROUTE_STATUS_RESTRICTED: + nonadj_str = "RESTRIC"; + rtavail_str = dst_avail ? "RESTRIC" : "UNAVAIL"; + break; + default: + OSMO_ASSERT(0); + } vty_out(vty, "%-16s %-5s %c %c %u %-19s %-7s %-7s %-7s %-3s%s", rt_str, - rt_avail ? "acces" : "INACC", + clsetavail_str, ' ', '0' + rt->cfg.qos_class, rt->cfg.priority, rt->cfg.linkset_name, - rt_avail ? "avail" : "UNAVAIL", - "?", - rt_avail ? "avail" : "UNAVAIL", + dst_avail ? "avail" : "UNAVAIL", + nonadj_str, + rtavail_str, rt->cfg.dyn_allocated ? "dyn" : "", VTY_NEWLINE); } diff --git a/src/xua_snm.c b/src/xua_snm.c index f3c8bb8..42361c9 100644 --- a/src/xua_snm.c +++ b/src/xua_snm.c @@ -33,6 +33,7 @@
#include "ss7_as.h" #include "ss7_asp.h" +#include "ss7_route.h" #include "ss7_internal.h" #include "ss7_route_table.h" #include "xua_internal.h" @@ -149,6 +150,39 @@ } }
+/* Figure 43/Q.704, Figure 44/Q.704 */ +/* RFC4666 1.4.2.5: "maintain a dynamic table of available SGP routes + * for the SS7 destinations, taking into account the SS7 destination + * availability/restricted/congestion status received from the SGP "*/ +static void xua_snm_srm_pc_available(struct osmo_ss7_as *as, + const uint32_t *aff_pc, unsigned int num_aff_pc, + bool available) +{ + struct osmo_ss7_instance *s7i = as->inst; + enum osmo_ss7_route_status new_status; + + new_status = available ? OSMO_SS7_ROUTE_STATUS_AVAILABLE : + OSMO_SS7_ROUTE_STATUS_UNAVAILABLE; + + for (unsigned int i = 0; i < num_aff_pc; i++) { + /* 32bit "Affected Point Code" consists of a 7-bit mask followed by 14/16/24-bit SS7 PC, + * see RFC 4666 3.4.1 */ + uint32_t _aff_pc = ntohl(aff_pc[i]); + uint32_t pc = _aff_pc & 0xffffff; + uint8_t mask = _aff_pc >> 24; + + if (!mask) { + ss7_route_table_update_route_status_by_as(s7i->rtable_system, new_status, as, pc); + } else { + /* Update only full DPC routes. */ + uint32_t maskbits = (1 << mask) - 1; + uint32_t fullpc; + for (fullpc = (pc & ~maskbits); fullpc <= (pc | maskbits); fullpc++) + ss7_route_table_update_route_status_by_as(s7i->rtable_system, new_status, as, fullpc); + } + } +} + /* advertise availability of point codes (with masks) */ void xua_snm_pc_available(struct osmo_ss7_as *as, const uint32_t *aff_pc, unsigned int num_aff_pc, const char *info_str, bool available) @@ -158,6 +192,9 @@ uint32_t rctx[OSMO_SS7_MAX_RCTX_COUNT]; unsigned int num_rctx;
+ xua_snm_srm_pc_available(as, aff_pc, num_aff_pc, available); + + /* inform local users via a MTP-{PAUSE, RESUME} primitive */ if (s7i->sccp) xua_snm_pc_available_to_sccp(s7i->sccp, aff_pc, num_aff_pc, available); diff --git a/tests/vty/osmo_stp_route_prio.vty b/tests/vty/osmo_stp_route_prio.vty index f2bfd1e..d9e3add 100644 --- a/tests/vty/osmo_stp_route_prio.vty +++ b/tests/vty/osmo_stp_route_prio.vty @@ -92,9 +92,9 @@
Destination C Q P Linkset Name Linkset Non-adj Route ---------------------- - - - ------------------- ------- ------- ------- -3.2.1/14 INACC 0 2 as3 UNAVAIL ? UNAVAIL -3.2.1/14 INACC 0 5 as2 UNAVAIL ? UNAVAIL -3.2.1/14 INACC 7 6 as1 UNAVAIL ? UNAVAIL +3.2.1/14 INACC 0 2 as3 UNAVAIL allowed UNAVAIL +3.2.1/14 INACC 0 5 as2 UNAVAIL allowed UNAVAIL +3.2.1/14 INACC 7 6 as1 UNAVAIL allowed UNAVAIL
OsmoSTP(config-cs7-rt)# ! NOW ADD MORE GENERIC ROUTES (SMALLER BITMASK LENGTH) OsmoSTP(config-cs7-rt)# update route 3.2.0 7.255.0 linkset as3 priority 3 @@ -122,14 +122,14 @@
Destination C Q P Linkset Name Linkset Non-adj Route ---------------------- - - - ------------------- ------- ------- ------- -3.2.1/14 INACC 0 2 as3 UNAVAIL ? UNAVAIL -3.2.1/14 INACC 0 5 as2 UNAVAIL ? UNAVAIL -3.2.1/14 INACC 7 6 as1 UNAVAIL ? UNAVAIL -3.2.0/11 INACC 0 1 as1 UNAVAIL ? UNAVAIL - INACC 0 1 as2 UNAVAIL ? UNAVAIL - INACC 0 1 as3 UNAVAIL ? UNAVAIL -3.2.0/11 INACC 0 2 as3 UNAVAIL ? UNAVAIL -3.2.0/11 INACC 0 3 as3 UNAVAIL ? UNAVAIL +3.2.1/14 INACC 0 2 as3 UNAVAIL allowed UNAVAIL +3.2.1/14 INACC 0 5 as2 UNAVAIL allowed UNAVAIL +3.2.1/14 INACC 7 6 as1 UNAVAIL allowed UNAVAIL +3.2.0/11 INACC 0 1 as1 UNAVAIL allowed UNAVAIL + 0 1 as2 UNAVAIL allowed UNAVAIL + 0 1 as3 UNAVAIL allowed UNAVAIL +3.2.0/11 INACC 0 2 as3 UNAVAIL allowed UNAVAIL +3.2.0/11 INACC 0 3 as3 UNAVAIL allowed UNAVAIL
OsmoSTP(config-cs7-rt)# do show cs7 instance 0 route binding-table 3.2.1