pespin has uploaded this change for review.

View Change

Create dynamic routes for AS statically configured routing-key

We already do so for routing-keys registered through RKM.
Let's do it too for statically configured ones.

This makes it easier to configure default routing on an STP, since
there's no need to set up "update route" for the most usual cases.
If specific routing is required (eg. combined linkset loadsharing use
over multiple AS on a given PC), it can still be configured manually
using a higher prio in the routing table.

The newly created dynamic routes contain the "match_as_routing_key"
setting, which means they are only usable to route a given message if
its routing label matches the routing-key of the AS.

This opens the door to improved traffic forwarding security as well as
more fine-grained traffic routing selection based on eg. OPC.

So far only matching on DPC and optionaly on OPC is supported.
Matching on SI and SSN is left as TODO work for the future.

Related: OS#7070
Change-Id: Ie74f4b502d4e5beacbf1ac5cd772b8735ea853ed
---
M src/ss7_as_vty.c
M src/ss7_combined_linkset.c
M src/ss7_route.c
M src/ss7_route.h
M src/ss7_vty.c
5 files changed, 50 insertions(+), 10 deletions(-)

git pull ssh://gerrit.osmocom.org:29418/libosmo-sigtran refs/changes/31/43831/1
diff --git a/src/ss7_as_vty.c b/src/ss7_as_vty.c
index 7d5eea0..b10abe6 100644
--- a/src/ss7_as_vty.c
+++ b/src/ss7_as_vty.c
@@ -436,6 +436,9 @@
ssn = OSSMO_SS7_RKEY_SSN_UNSET;
}

+ /* Drop previous route if exists: */
+ ss7_as_routing_key_delete_route(as);
+
rkey->context = rctx;
/* truncate mask to maximum. Let's avoid callers specifying arbitrary large
* masks to ensure we don't fail duplicate detection with longer mask lengths */
@@ -444,6 +447,13 @@
rkey->opc_mask = osmo_ss7_pc_normalize(&as->inst->cfg.pc_fmt, opc_mask);
rkey->si = si;
rkey->ssn = ssn;
+
+ /* Add fully qualified route for routing-key: */
+ if (ss7_as_routing_key_create_route(as) < 0) {
+ vty_out(vty, "Failed adding dynamic match-routing-key route for AS %s!%s",
+ as->cfg.name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
return CMD_SUCCESS;
}

diff --git a/src/ss7_combined_linkset.c b/src/ss7_combined_linkset.c
index 9f53b7b..59c7007 100644
--- a/src/ss7_combined_linkset.c
+++ b/src/ss7_combined_linkset.c
@@ -193,11 +193,12 @@
}

/* ITU Q.704 4.2.1: "current link set (combined link set)". Pick available already selected route */
-struct osmo_ss7_route *current_rt(const struct osmo_ss7_esls_entry *eslse)
+struct osmo_ss7_route *current_rt(const struct osmo_ss7_esls_entry *eslse,
+ const struct osmo_ss7_route_label *rtlabel)
{
- if (eslse->normal_rt && ss7_route_is_available(eslse->normal_rt))
+ if (eslse->normal_rt && ss7_route_is_available_for_rtlabel(eslse->normal_rt, rtlabel))
return eslse->normal_rt;
- if (eslse->alt_rt && ss7_route_is_available(eslse->alt_rt))
+ if (eslse->alt_rt && ss7_route_is_available_for_rtlabel(eslse->alt_rt, rtlabel))
return eslse->alt_rt;
return NULL;
}
@@ -223,13 +224,14 @@
}

/* Pick an available route from Combined Linkset in a round-robin fashion, to send a message through. */
-static struct osmo_ss7_route *ss7_combined_linkset_select_route_roundrobin(struct osmo_ss7_combined_linkset *clset)
+static struct osmo_ss7_route *ss7_combined_linkset_select_route_roundrobin(struct osmo_ss7_combined_linkset *clset,
+ const struct osmo_ss7_route_label *rtlabel)
{
struct osmo_ss7_route *rt;

for (unsigned int i = 0; i < clset->num_routes; i++) {
rt = ss7_llist_round_robin(&clset->routes, &clset->last_route_roundrobin_tx, struct osmo_ss7_route, list);
- if (rt && ss7_route_is_available(rt))
+ if (rt && ss7_route_is_available_for_rtlabel(rt, rtlabel))
return rt;
}
return NULL;
@@ -245,7 +247,7 @@
char buf[256];

/* First check if we have a cached route for this ESLS */
- rt = current_rt(eslse);
+ rt = current_rt(eslse, rtlabel);
if (rt) {
if (rt == eslse->normal_rt) {
/* We can transmit over normal route.
@@ -279,7 +281,7 @@
if (!rt)
return NULL;
eslse->normal_rt = rt;
- rt_avail = ss7_route_is_available(eslse->normal_rt);
+ rt_avail = ss7_route_is_available_for_rtlabel(eslse->normal_rt, rtlabel);
LOGPCLSET(clset, DLSS7, LOGL_INFO, "RT loookup: %s -> eSLS=%u: "
"picked Normal Route via '%s' round-robin style (%s)\n",
ss7_route_label_to_str(buf, sizeof(buf), inst, rtlabel), esls,
@@ -295,7 +297,7 @@

/* 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);
+ rt = ss7_combined_linkset_select_route_roundrobin(clset, rtlabel);
if (rt) {
eslse->alt_rt = rt;
LOGPCLSET(clset, DLSS7, LOGL_NOTICE, "RT Lookup: %s -> eSLS=%u: "
diff --git a/src/ss7_route.c b/src/ss7_route.c
index ce60bc1..347af51 100644
--- a/src/ss7_route.c
+++ b/src/ss7_route.c
@@ -147,6 +147,7 @@
rt->cfg.pc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, pc);
rt->cfg.priority = OSMO_SS7_ROUTE_PRIO_DEFAULT;
rt->cfg.dyn_allocated = dynamic;
+ rt->cfg.match_as_routing_key = false;

osmo_timer_setup(&rt->t10_audit_timer, t10_audit_timer_cb, rt);

@@ -228,7 +229,8 @@
struct osmo_ss7_route *prev_rt;
llist_for_each_entry(prev_rt, &clset->routes, list) {
if (strcmp(prev_rt->cfg.linkset_name, rt->cfg.linkset_name) == 0 &&
- prev_rt->cfg.dyn_allocated == rt->cfg.dyn_allocated) {
+ prev_rt->cfg.dyn_allocated == rt->cfg.dyn_allocated &&
+ prev_rt->cfg.match_as_routing_key == rt->cfg.match_as_routing_key) {
LOGPRT(rt, DLSS7, LOGL_ERROR,
"Refusing to create route with existing linkset/AS name '%s'\n", rt->cfg.linkset_name);
return -EADDRINUSE;
@@ -384,6 +386,8 @@

if (rt->dest.as) {
struct osmo_ss7_as *as = rt->dest.as;
+ if (rt->cfg.match_as_routing_key)
+ APPEND(" match-routing-key");
APPEND(" via AS %s proto=%s", as->cfg.name, osmo_ss7_asp_protocol_name(as->cfg.proto));

if (list_asps) {
@@ -454,6 +458,25 @@
return false;
}

+bool ss7_route_is_available_for_rtlabel(const struct osmo_ss7_route *rt,
+ const struct osmo_ss7_route_label *rtlabel)
+{
+ if (!ss7_route_dest_is_available(rt))
+ return false;
+ if (rt->cfg.match_as_routing_key) {
+ struct osmo_ss7_as *as = rt->dest.as;
+ OSMO_ASSERT(as);
+ struct osmo_ss7_routing_key *rkey = &as->cfg.routing_key;
+ if (rtlabel->dpc != rkey->pc)
+ return false;
+ if ((rtlabel->opc & rkey->opc_mask) != rkey->opc)
+ return false;
+ /* TODO: match rkey->si */
+ /* TODO: match rkey->ssn */
+ }
+ return true;
+}
+
/* Whether route mask identifies a single DPC. */
bool ss7_route_is_fully_qualified(const struct osmo_ss7_route *rt)
{
diff --git a/src/ss7_route.h b/src/ss7_route.h
index 437a5d8..fa6bdc9 100644
--- a/src/ss7_route.h
+++ b/src/ss7_route.h
@@ -10,6 +10,7 @@

struct osmo_ss7_instance;
struct osmo_ss7_route_table;
+struct osmo_ss7_route_label;
struct osmo_ss7_linkset;
struct osmo_ss7_as;

@@ -54,6 +55,7 @@
uint32_t priority;
uint8_t qos_class;
bool dyn_allocated;
+ bool match_as_routing_key;
} cfg;
};

@@ -75,6 +77,8 @@

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_available_for_rtlabel(const struct osmo_ss7_route *rt,
+ const struct osmo_ss7_route_label *rtlabel);

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)
diff --git a/src/ss7_vty.c b/src/ss7_vty.c
index eec4a80..a91d909 100644
--- a/src/ss7_vty.c
+++ b/src/ss7_vty.c
@@ -609,7 +609,7 @@
default:
OSMO_ASSERT(0);
}
- vty_out(vty, "%-16s %-5s %c %c %u %-19s %-7s %-7s %-7s %-3s%s",
+ vty_out(vty, "%-16s %-5s %c %c %u %-19s %-7s %-7s %-7s %-3s %-17s%s",
rt_str,
clsetavail_str,
' ',
@@ -620,6 +620,7 @@
nonadj_str,
rtavail_str,
rt->cfg.dyn_allocated ? "dyn" : "",
+ rt->cfg.match_as_routing_key ? "match-routing-key" : "",
VTY_NEWLINE);
}
}

To view, visit change 43831. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: newchange
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: Ie74f4b502d4e5beacbf1ac5cd772b8735ea853ed
Gerrit-Change-Number: 43831
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin@sysmocom.de>