pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/39391?usp=email )
Change subject: AS loadsharing: Implement AS loadshare, skip unavailable AS/lset when choosing ......................................................................
AS loadsharing: Implement AS loadshare, skip unavailable AS/lset when choosing
Pick normal route containing destination AS/lset to serve a given func(<OPC,DPC,SLS>)=eSLS on a round-robin base. If normal route becomes unavailable, pick an alternative route in a similar way. This alternative route will be used until itself becomes unavailable or the normal route becomes available again.
Related: SYS#7112 Change-Id: I928fb1ef5db6922f1386a188e3fbf9e70780f25d --- M src/osmo_ss7_combined_linkset.c M src/osmo_ss7_link.c M src/osmo_ss7_linkset.c M src/osmo_ss7_route.c M src/ss7_combined_linkset.h M src/ss7_link.h M src/ss7_linkset.h M tests/ss7/ss7_test.c 8 files changed, 92 insertions(+), 19 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-sigtran refs/changes/91/39391/1
diff --git a/src/osmo_ss7_combined_linkset.c b/src/osmo_ss7_combined_linkset.c index ed0fc79..23b3ae0 100644 --- a/src/osmo_ss7_combined_linkset.c +++ b/src/osmo_ss7_combined_linkset.c @@ -49,6 +49,20 @@ * link set) or of an alternative link set (combined link set)." *****************************************************************************/
+static inline struct llist_head *_ss7_llist_round_robin(struct llist_head *list, void **state) +{ + struct llist_head *e = *state; + if (!e || e->next == list) + e = list; + e = e->next; + if (e == list) + e = NULL; + *state = e; + return e; +} +#define ss7_llist_round_robin(list, state, struct_type, entry_name) \ + llist_entry(_ss7_llist_round_robin(list, state), struct_type, entry_name) + /*! \brief Insert combined_link into its routing table * \param[in] clset Combined link to be inserted into its routing table * \returns 0 on success, negative on error @@ -135,6 +149,14 @@ clset->esls_table[i].alt_rt = NULL; }
+ /* Update round robin state */ + if (rt == clset->last_route_roundrobin) { + ss7_llist_round_robin(&clset->routes, &clset->last_route_roundrobin, struct osmo_ss7_route, list); + /* If there's only one left, remove state: */ + if (rt == clset->last_route_roundrobin) + clset->last_route_roundrobin = NULL; + } + llist_del(&rt->list); rt->clset = NULL; clset->num_routes--; @@ -172,6 +194,27 @@ return NULL; }
+static struct osmo_ss7_route *ss7_combined_linkset_select_route_roundrobin(struct osmo_ss7_combined_linkset *clset) +{ + struct osmo_ss7_route *rt; + struct osmo_ss7_route *rt_found = NULL; + unsigned int i = 0; + + while (i < clset->num_routes) { + i++; + rt = ss7_llist_round_robin(&clset->routes, &clset->last_route_roundrobin, struct osmo_ss7_route, list); + if (ss7_route_is_available(rt)) { + rt_found = rt; + break; + } + } + + if (!rt_found) + return NULL; + + return rt_found; +} + struct osmo_ss7_route * ss7_combined_linkset_lookup_route(struct osmo_ss7_combined_linkset *clset, const struct osmo_ss7_route_label *rtlabel) { @@ -192,20 +235,20 @@ return rt; }
- /* TODO: Check if the AS/linkset in rt is actually UP and can be - * used, otherwise start ITU Q.704 section 7 "forced rerouting" prcoedure: - * we need to pick a temporary dst (update the esls_table entry) while the - * original one is DOWN. */ + /* No current route available, try to find a new current route: */
- /* We need to pick a new AS/linkset from the combined linkset and cache - * it so it is always used for this eSLS: */ - /* FIXME: for now we simply take the first AS in the combined linksed, to be improved later... */ - rt = llist_first_entry_or_null(&clset->routes, struct osmo_ss7_route, list); + /* No normal route selected yet: */ + if (!eslse->normal_rt) { + rt = ss7_combined_linkset_select_route_roundrobin(clset); + /* Either a normal route was selected or none found: */ + eslse->normal_rt = rt; + return rt; + }
- /* TODO: here we'd need to actually check if dst AS/linkset in the route - * is actually UP, otherwise pick next one in the roundrobin list... */ + /* Normal route unavailable and no alternative route (or unavailable too). + * start ITU Q.704 section 7 "forced rerouting" procedure: */ + rt = ss7_combined_linkset_select_route_roundrobin(clset); if (rt) - clset->esls_table[esls].normal_rt = rt; - + eslse->alt_rt = rt; return rt; } diff --git a/src/osmo_ss7_link.c b/src/osmo_ss7_link.c index 321d72e..6310824 100644 --- a/src/osmo_ss7_link.c +++ b/src/osmo_ss7_link.c @@ -75,3 +75,11 @@
return link; } + +/* Whether link is available, ITU Q.704 section 3.2 */ +bool +ss7_link_is_available(const struct osmo_ss7_link *link) +{ + /* TODO: manage operational availability of a link... */ + return link->cfg.adm_state == OSMO_SS7_LS_ENABLED; +} diff --git a/src/osmo_ss7_linkset.c b/src/osmo_ss7_linkset.c index 5b4b316..8f63505 100644 --- a/src/osmo_ss7_linkset.c +++ b/src/osmo_ss7_linkset.c @@ -101,3 +101,14 @@
return lset; } + +bool +ss7_linkset_is_available(const struct osmo_ss7_linkset *lset) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(lset->links); i++) { + struct osmo_ss7_link *link = lset->links[i]; + if (link && ss7_link_is_available(link)) + return true; + } + return false; +} diff --git a/src/osmo_ss7_route.c b/src/osmo_ss7_route.c index 9683dd3..194d5dd 100644 --- a/src/osmo_ss7_route.c +++ b/src/osmo_ss7_route.c @@ -306,12 +306,9 @@ bool ss7_route_is_available(const struct osmo_ss7_route *rt) { OSMO_ASSERT(rt); - if (rt->dest.as) { - if (osmo_ss7_as_active(rt->dest.as)) - return true; - - } else { - /* TODO: linkset */ - } + 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; } diff --git a/src/ss7_combined_linkset.h b/src/ss7_combined_linkset.h index e2f9c9d..b80a007 100644 --- a/src/ss7_combined_linkset.h +++ b/src/ss7_combined_linkset.h @@ -33,6 +33,7 @@ /*! list of \ref osmo_ss7_route */ struct llist_head routes; unsigned int num_routes; + void *last_route_roundrobin;
struct { uint32_t pc; diff --git a/src/ss7_link.h b/src/ss7_link.h index 5ea6556..b0014c6 100644 --- a/src/ss7_link.h +++ b/src/ss7_link.h @@ -31,3 +31,5 @@ void ss7_link_destroy(struct osmo_ss7_link *link); struct osmo_ss7_link * ss7_link_find_or_create(struct osmo_ss7_linkset *lset, uint32_t id); +bool +ss7_link_is_available(const struct osmo_ss7_link *link); diff --git a/src/ss7_linkset.h b/src/ss7_linkset.h index daa442f..beb60a1 100644 --- a/src/ss7_linkset.h +++ b/src/ss7_linkset.h @@ -30,3 +30,6 @@ ss7_linkset_find_by_name(struct osmo_ss7_instance *inst, const char *name); struct osmo_ss7_linkset * ss7_linkset_find_or_create(struct osmo_ss7_instance *inst, const char *name, uint32_t pc); + +bool +ss7_linkset_is_available(const struct osmo_ss7_linkset *lset); diff --git a/tests/ss7/ss7_test.c b/tests/ss7/ss7_test.c index 95fa1b1..f61ee0a 100644 --- a/tests/ss7/ss7_test.c +++ b/tests/ss7/ss7_test.c @@ -154,6 +154,7 @@ { struct osmo_ss7_route_table *rtbl; struct osmo_ss7_linkset *lset_a, *lset_b; + struct osmo_ss7_link *l_a, *l_b; struct osmo_ss7_route *rt, *rt12, *rtdef; struct osmo_ss7_route_label route_label;
@@ -173,8 +174,15 @@
lset_a = ss7_linkset_find_or_create(s7i, "a", 100); OSMO_ASSERT(lset_a); + l_a = ss7_link_find_or_create(lset_a, 0); + OSMO_ASSERT(l_a); + l_a->cfg.adm_state = OSMO_SS7_LS_ENABLED; + lset_b = ss7_linkset_find_or_create(s7i, "b", 200); OSMO_ASSERT(lset_b); + l_b = ss7_link_find_or_create(lset_b, 0); + OSMO_ASSERT(l_b); + l_b->cfg.adm_state = OSMO_SS7_LS_ENABLED;
/* route with full mask */ route_label = RT_LABEL(0, 12, 0);