pespin has submitted this change. ( 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_hmrt.c M src/ss7_combined_linkset.h M src/xua_snm.c M tests/ss7/ss7_test.c M tests/vty/osmo_stp_route_prio.vty 6 files changed, 67 insertions(+), 21 deletions(-)
Approvals: Jenkins Builder: Verified pespin: Looks good to me, approved osmith: Looks good to me, but someone else must approve
diff --git a/src/osmo_ss7_combined_linkset.c b/src/osmo_ss7_combined_linkset.c index 90a54f6..99b0c79 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_hmrt.c b/src/osmo_ss7_hmrt.c index 1e000b4..72d5adc 100644 --- a/src/osmo_ss7_hmrt.c +++ b/src/osmo_ss7_hmrt.c @@ -180,12 +180,6 @@ dpc, osmo_ss7_pointcode_print(inst, dpc), rt_name); }
- if (osmo_ss7_as_down(as)) { - LOGP(DLSS7, LOGL_ERROR, "Unable to route HMRT message: the AS %s is down\n", - as->cfg.name); - return -ENETDOWN; - } - rate_ctr_inc2(as->ctrg, SS7_AS_CTR_TX_MSU_TOTAL);
switch (as->cfg.proto) { 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/xua_snm.c b/src/xua_snm.c index acdfe0c..1481178 100644 --- a/src/xua_snm.c +++ b/src/xua_snm.c @@ -347,7 +347,7 @@ .sls = 0, };
- /* FIXME: don't just check for a route; but also check if the route is "active" */ + /* Check if there's an "active" route available: */ if (ss7_instance_lookup_route(s7i, &rtlabel)) is_available = true;
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); diff --git a/tests/vty/osmo_stp_route_prio.vty b/tests/vty/osmo_stp_route_prio.vty index 6f60d9a..2b7cec6 100644 --- a/tests/vty/osmo_stp_route_prio.vty +++ b/tests/vty/osmo_stp_route_prio.vty @@ -87,6 +87,6 @@ 3.2.1/14 INACC 0 5 as2 UNAVAIL ? UNAVAIL 3.2.1/14 INACC 7 6 as1 UNAVAIL ? UNAVAIL
-OsmoSTP(config-cs7-rt)# ! NOW TEST LOOKUP WORKS AS DESIRED (as3 PICKED): +OsmoSTP(config-cs7-rt)# ! NOW TEST LOOKUP FAILS AS EXPECTED (all route links are down): OsmoSTP(config-cs7-rt)# do show cs7 instance 0 route-lookup 3.2.1 from 0.0.1 sls 0 -pc=6161=3.2.1 mask=0x3fff=7.255.7 via AS as3 proto=m3ua +No route found for label 'OPC=1=0.0.1,DPC=6161=3.2.1,SLS=0'