pespin has uploaded this change for review. (
https://gerrit.osmocom.org/c/libosmo-sigtran/+/38636?usp=email )
Change subject: sigtran: Make osmo_ss7_route struct and several APIs private
......................................................................
sigtran: Make osmo_ss7_route struct and several APIs private
The struct is in general managed internally by the library, only a few
APIs which are in use by some external users (osmo-hnbgw and osmo-bsc
vty) are left public.
Change-Id: I8a86966cb6a5361687987a2e9acd79c4ab3d97c4
---
M TODO-RELEASE
M include/osmocom/sigtran/osmo_ss7.h
M src/Makefile.am
M src/osmo_ss7.c
M src/osmo_ss7_as.c
M src/osmo_ss7_hmrt.c
A src/osmo_ss7_route.c
M src/osmo_ss7_route_table.c
M src/osmo_ss7_vty.c
M src/sccp_scrc.c
M src/sccp_user.c
A src/ss7_route.h
M src/xua_as_fsm.c
M src/xua_rkm.c
M tests/ss7/ss7_test.c
15 files changed, 383 insertions(+), 317 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-sigtran refs/changes/36/38636/1
diff --git a/TODO-RELEASE b/TODO-RELEASE
index 06d4f53..06ae923 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -9,4 +9,5 @@
#library what description / commit summary line
libosmo-sigtran API change struct osmo_ss7_instance has new member
'secondary_pc'
libosmo-sigtran add API osmo_sccp_{release,return,reset,error,refusal}_cause_name(s),
osmo_sua_sccp_cause_name
-libosmo-sigtran add API osmo_ss7_route_get_dest_as()
\ No newline at end of file
+libosmo-sigtran add API osmo_ss7_route_get_dest_as()
+libosmo-sigtran Make private osmo_ss7_route
diff --git a/include/osmocom/sigtran/osmo_ss7.h b/include/osmocom/sigtran/osmo_ss7.h
index 3b5aa4f..002117a 100644
--- a/include/osmocom/sigtran/osmo_ss7.h
+++ b/include/osmocom/sigtran/osmo_ss7.h
@@ -181,37 +181,10 @@
* SS7 Routes
***********************************************************************/
-struct osmo_ss7_route {
- /*! member in \ref osmo_ss7_route_table.routes */
- struct llist_head list;
- /*! \ref osmo_ss7_route_table to which we belong */
- struct osmo_ss7_route_table *rtable;
-
- struct {
- /*! pointer to linkset (destination) of route */
- struct osmo_ss7_linkset *linkset;
- /*! pointer to Application Server */
- struct osmo_ss7_as *as;
- } dest;
-
- struct {
- /* FIXME: presence? */
- uint32_t pc;
- uint32_t mask;
- /*! human-specified linkset name */
- char *linkset_name;
- /*! lower priority is higher */
- uint32_t priority;
- uint8_t qos_class;
- } cfg;
-};
+struct osmo_ss7_route;
struct osmo_ss7_route *
osmo_ss7_route_lookup(struct osmo_ss7_instance *inst, uint32_t dpc);
-struct osmo_ss7_route *
-osmo_ss7_route_create(struct osmo_ss7_route_table *rtbl, uint32_t dpc,
- uint32_t mask, const char *linkset_name);
-void osmo_ss7_route_destroy(struct osmo_ss7_route *rt);
const char *osmo_ss7_route_print(const struct osmo_ss7_route *rt);
const char *osmo_ss7_route_name(struct osmo_ss7_route *rt, bool list_asps);
struct osmo_ss7_as *
diff --git a/src/Makefile.am b/src/Makefile.am
index 5dddb05..af6bae8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -5,6 +5,7 @@
noinst_HEADERS = \
sccp_internal.h \
ss7_internal.h \
+ ss7_route.h \
ss7_route_table.h \
xua_asp_fsm.h \
xua_as_fsm.h \
@@ -38,6 +39,7 @@
osmo_ss7_hmrt.c \
osmo_ss7_vty.c \
osmo_ss7_xua_srv.c \
+ osmo_ss7_route.c \
osmo_ss7_route_table.c \
sccp2sua.c \
sccp_helpers.c \
diff --git a/src/osmo_ss7.c b/src/osmo_ss7.c
index 95e58a7..9ce333d 100644
--- a/src/osmo_ss7.c
+++ b/src/osmo_ss7.c
@@ -51,6 +51,7 @@
#include "sccp_internal.h"
#include "xua_internal.h"
#include "ss7_internal.h"
+#include "ss7_route.h"
#include "ss7_route_table.h"
#include "xua_asp_fsm.h"
#include "xua_as_fsm.h"
@@ -508,7 +509,7 @@
/* find any routes pointing to this AS and remove them */
llist_for_each_entry_safe(rt, rt2, &lset->inst->rtable_system->routes,
list) {
if (rt->dest.linkset == lset)
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
}
for (i = 0; i < ARRAY_SIZE(lset->links); i++) {
@@ -611,105 +612,6 @@
return link;
}
-/***********************************************************************
- * SS7 Routes
- ***********************************************************************/
-
-/*! \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
- * \param[in] mask Mask of the destination Point Code \ref pc
- * \returns Allocated route (not yet inserted into its rtbl), NULL on error
- *
- * The returned route has no linkset associated yet, user *must* associate it
- * using API ss7_route_set_linkset() before inserting the route into its
- * routing table.
- *
- * Fields priority and qos_class may be set *before* inserting the route into
- * its routing table:
- * - A default priority of 0 is configured on the route.
- * - A default qos-class of 0 is configured on the route.
- *
- * Use API ss7_route_insert() to insert the route into its routing table.
- *
- * The route entry allocated with this API can be destroyed/freed at any point using API
- * osmo_ss7_route_destroy(), regardless of it being already inserted or not in
- * its routing table.
- */
-struct osmo_ss7_route *
-ss7_route_alloc(struct osmo_ss7_route_table *rtbl, uint32_t pc, uint32_t mask)
-{
- struct osmo_ss7_route *rt;
-
- OSMO_ASSERT(ss7_initialized);
-
- rt = talloc_zero(rtbl, struct osmo_ss7_route);
- if (!rt)
- return NULL;
-
- /* Mark it as not being inserted yet in rtbl */
- INIT_LLIST_HEAD(&rt->list);
- rt->rtable = rtbl;
- /* 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);
- rt->cfg.pc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, pc);
- rt->cfg.priority = OSMO_SS7_ROUTE_PRIO_DEFAULT;
- return rt;
-}
-
-/*! \brief Check whether route has already been inserted into its routing table.
- * \returns true if already inserted, false if not.
- */
-static bool ss7_route_inserted(const struct osmo_ss7_route *rt)
-{
- return !llist_empty(&rt->list);
-}
-
-/*! \brief Set linkset on route entry
- * \param[in] rt Route to be configured
- * \param[in] linkset_name string name of the linkset to be used
- * \returns 0 on success, negative on error.
- */
-int
-ss7_route_set_linkset(struct osmo_ss7_route *rt, const char *linkset_name)
-{
- struct osmo_ss7_linkset *lset;
- struct osmo_ss7_as *as = NULL;
- struct osmo_ss7_route_table *rtbl = rt->rtable;
-
- if (rt->cfg.linkset_name) {
- LOGSS7(rtbl->inst, LOGL_ERROR, "Attempt setting linkset on route already
configured!\n");
- return -EBUSY;
- }
-
- if (ss7_route_inserted(rt)) {
- LOGSS7(rtbl->inst, LOGL_ERROR, "Attempt setting linkset on route already in the
routing table!\n");
- return -EALREADY;
- }
-
- lset = osmo_ss7_linkset_find_by_name(rtbl->inst, linkset_name);
- if (!lset) {
- as = osmo_ss7_as_find_by_name(rtbl->inst, linkset_name);
- if (!as)
- return -ENODEV;
- }
-
- rt->cfg.linkset_name = talloc_strdup(rt, linkset_name);
- if (lset) {
- rt->dest.linkset = lset;
- LOGSS7(rtbl->inst, LOGL_INFO, "Creating route: pc=%u=%s mask=0x%x via linkset
'%s'\n",
- rt->cfg.pc, osmo_ss7_pointcode_print(rtbl->inst, rt->cfg.pc),
- rt->cfg.mask, lset->cfg.name);
- } else {
- rt->dest.as = as;
- LOGSS7(rtbl->inst, LOGL_INFO, "Creating route: pc=%u=%s mask=0x%x via AS
'%s'\n",
- rt->cfg.pc, osmo_ss7_pointcode_print(rtbl->inst, rt->cfg.pc),
- rt->cfg.mask, as->cfg.name);
- }
- return 0;
-}
-
/*! \brief Find a SS7 route for given destination point code in given SS7 */
struct osmo_ss7_route *
osmo_ss7_route_lookup(struct osmo_ss7_instance *inst, uint32_t dpc)
@@ -718,170 +620,6 @@
return ss7_route_table_find_route_by_dpc(inst->rtable_system, dpc);
}
-/* insert the route in the ordered list of routes. The list is sorted by
- * mask length, so that the more specific (longer mask) routes are
- * first, while the less specific routes with shorter masks are last.
- * Within the same mask length, the routes are ordered by priority.
- * Hence, the first matching route in a linear iteration is the most
- * specific match. */
-static void route_insert_sorted(struct osmo_ss7_route_table *rtbl,
- struct osmo_ss7_route *cmp)
-{
- struct osmo_ss7_route *rt;
-
- llist_for_each_entry(rt, &rtbl->routes, list) {
- if (rt->cfg.mask == cmp->cfg.mask &&
- rt->cfg.priority > cmp->cfg.priority) {
- /* insert before the current entry */
- llist_add(&cmp->list, rt->list.prev);
- return;
- }
- if (rt->cfg.mask < cmp->cfg.mask) {
- /* insert before the current entry */
- llist_add(&cmp->list, rt->list.prev);
- return;
- }
- }
- /* not added, i.e. no smaller mask length and priority found: we are the
- * smallest mask and priority and thus should go last */
- llist_add_tail(&cmp->list, &rtbl->routes);
-}
-
-/*! \brief Insert route into its routing table
- * \param[in] rt Route to be inserted into its routing table
- * \returns 0 on success, negative on error
- *
- * A route is only really used once it has been inserted into its routing table.
- */
-int
-ss7_route_insert(struct osmo_ss7_route *rt)
-{
- struct osmo_ss7_route *prev_rt;
- struct osmo_ss7_route_table *rtbl = rt->rtable;
-
- if (ss7_route_inserted(rt)) {
- LOGSS7(rtbl->inst, LOGL_ERROR, "Attempt insert of route already in the routing
table!\n");
- return -EALREADY;
- }
-
- if (!rt->cfg.linkset_name) {
- LOGSS7(rtbl->inst, LOGL_ERROR, "Attempt insert of route with unset
linkset!\n");
- return -EINVAL;
- }
-
- /* check for duplicates */
- prev_rt = ss7_route_table_find_route_by_dpc_mask(rtbl, rt->cfg.pc, rt->cfg.mask);
- if (prev_rt && !strcmp(prev_rt->cfg.linkset_name, rt->cfg.linkset_name))
{
- LOGSS7(rtbl->inst, LOGL_ERROR,
- "Refusing to create route with existing linkset name: pc=%u=%s mask=0x%x
via linkset/AS '%s'\n",
- rt->cfg.pc, osmo_ss7_pointcode_print(rtbl->inst, rt->cfg.pc),
- rt->cfg.mask, rt->cfg.linkset_name);
- return -EADDRINUSE;
- }
-
- route_insert_sorted(rtbl, rt);
- return 0;
-}
-
-/*! \brief Create a new route in the given routing table
- * \param[in] rtbl Routing Table in which the route is to be created
- * \param[in] pc Point Code of the destination of the route
- * \param[in] mask Mask of the destination Point Code \ref pc
- * \param[in] linkset_name string name of the linkset to be used
- * \returns callee-allocated + initialized route, NULL on error
- *
- * The route allocated and returned by this API is already inserted into the
- * routing table, with priority and qos-class set to 0.
- * If you plan to use different values for priority and qos-class, avoid using
- * this API and use ss7_route_alloc() + ss7_route_set_linkset() +
- * ss7_route_insert() instead.
- */
-struct osmo_ss7_route *
-osmo_ss7_route_create(struct osmo_ss7_route_table *rtbl, uint32_t pc,
- uint32_t mask, const char *linkset_name)
-{
- struct osmo_ss7_route *rt;
- int rc;
-
- rt = ss7_route_alloc(rtbl, pc, mask);
- if (!rt)
- return NULL;
-
- if (ss7_route_set_linkset(rt, linkset_name) < 0) {
- talloc_free(rt);
- return NULL;
- }
-
- rc = ss7_route_insert(rt);
- /* Keep old behavior, return already existing route: */
- if (rc == -EADDRINUSE) {
- talloc_free(rt);
- return ss7_route_table_find_route_by_dpc_mask(rtbl, rt->cfg.pc, rt->cfg.mask);
- }
-
- return rt;
-}
-
-/*! \brief Destroy a given SS7 route */
-void osmo_ss7_route_destroy(struct osmo_ss7_route *rt)
-{
- OSMO_ASSERT(ss7_initialized);
-
- if (!rt)
- return;
-
- if (ss7_route_inserted(rt)) {
- struct osmo_ss7_instance *inst = rt->rtable->inst;
- LOGSS7(inst, LOGL_INFO,
- "Destroying route: pc=%u=%s mask=0x%x via linkset/ASP '%s'\n",
- rt->cfg.pc, osmo_ss7_pointcode_print(inst, rt->cfg.pc),
- rt->cfg.mask, rt->cfg.linkset_name);
- llist_del(&rt->list);
- }
- talloc_free(rt);
-}
-
-/* count number of consecutive leading (MSB) bits that are '1' */
-static unsigned int count_leading_one_bits(uint32_t inp, unsigned int nbits)
-{
- unsigned int i;
-
- for (i = 0; i < nbits; i++) {
- if (!(inp & (1 << (nbits-1-i))))
- return i;
- }
- return i;
-}
-
-/* determine the mask length in number of bits; negative if non-consecutive mask */
-static int u32_masklen(uint32_t mask, unsigned int nbits)
-{
- unsigned int i;
- unsigned int leading_one_bits = count_leading_one_bits(mask, nbits);
-
- /* are there any bits set after the initial bits? */
- for (i = leading_one_bits; i < nbits; i++) {
- if (mask & (1 << (nbits-1-i)))
- return -1; /* not a simple prefix mask */
- }
- return leading_one_bits;
-}
-
-const char *osmo_ss7_route_print(const struct osmo_ss7_route *rt)
-{
- const struct osmo_ss7_instance *inst = rt->rtable->inst;
- unsigned int pc_width = osmo_ss7_pc_width(&inst->cfg.pc_fmt);
- static char buf[64];
- int rc = u32_masklen(rt->cfg.mask, pc_width);
-
- if (rc < 0)
- snprintf(buf, sizeof(buf), "%s/%s", osmo_ss7_pointcode_print(inst,
rt->cfg.pc),
- osmo_ss7_pointcode_print2(inst, rt->cfg.mask));
- else
- snprintf(buf, sizeof(buf), "%s/%u", osmo_ss7_pointcode_print(inst,
rt->cfg.pc), rc);
- return buf;
-}
-
/*! \brief Get destination AS of route
* \param[in] rt Route entry holding the AS destination
* \returns pointer to Application Server on success; NULL if rt doesn't route
diff --git a/src/osmo_ss7_as.c b/src/osmo_ss7_as.c
index 87e7e04..cc61b12 100644
--- a/src/osmo_ss7_as.c
+++ b/src/osmo_ss7_as.c
@@ -33,6 +33,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/logging.h>
+#include "ss7_route.h"
#include "ss7_route_table.h"
#include "ss7_internal.h"
#include "xua_as_fsm.h"
@@ -166,7 +167,7 @@
/* find any routes pointing to this AS and remove them */
llist_for_each_entry_safe(rt, rt2, &as->inst->rtable_system->routes, list)
{
if (rt->dest.as == as)
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
}
as->inst = NULL;
diff --git a/src/osmo_ss7_hmrt.c b/src/osmo_ss7_hmrt.c
index 57d7388..55e5776 100644
--- a/src/osmo_ss7_hmrt.c
+++ b/src/osmo_ss7_hmrt.c
@@ -35,6 +35,7 @@
#include <osmocom/sigtran/protocol/m3ua.h>
#include "xua_internal.h"
+#include "ss7_route.h"
#include "ss7_route_table.h"
#include "ss7_internal.h"
diff --git a/src/osmo_ss7_route.c b/src/osmo_ss7_route.c
new file mode 100644
index 0000000..daef749
--- /dev/null
+++ b/src/osmo_ss7_route.c
@@ -0,0 +1,294 @@
+/* (C) 2015-2017 by Harald Welte <laforge(a)gnumonks.org>
+ * (C) 2023-2024 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <errno.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/sigtran/mtp_sap.h>
+#include <osmocom/sigtran/osmo_ss7.h>
+
+#include "ss7_route.h"
+#include "ss7_route_table.h"
+#include "ss7_internal.h"
+
+/***********************************************************************
+ * SS7 Routes
+ ***********************************************************************/
+
+/*! \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
+ * \param[in] mask Mask of the destination Point Code \ref pc
+ * \returns Allocated route (not yet inserted into its rtbl), NULL on error
+ *
+ * The returned route has no linkset associated yet, user *must* associate it
+ * using API ss7_route_set_linkset() before inserting the route into its
+ * routing table.
+ *
+ * Fields priority and qos_class may be set *before* inserting the route into
+ * its routing table:
+ * - A default priority of 0 is configured on the route.
+ * - A default qos-class of 0 is configured on the route.
+ *
+ * Use API ss7_route_insert() to insert the route into its routing table.
+ *
+ * The route entry allocated with this API can be destroyed/freed at any point using API
+ * ss7_route_destroy(), regardless of it being already inserted or not in
+ * its routing table.
+ */
+struct osmo_ss7_route *
+ss7_route_alloc(struct osmo_ss7_route_table *rtbl, uint32_t pc, uint32_t mask)
+{
+ struct osmo_ss7_route *rt;
+
+ OSMO_ASSERT(ss7_initialized);
+
+ rt = talloc_zero(rtbl, struct osmo_ss7_route);
+ if (!rt)
+ return NULL;
+
+ /* Mark it as not being inserted yet in rtbl */
+ INIT_LLIST_HEAD(&rt->list);
+ rt->rtable = rtbl;
+ /* 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);
+ rt->cfg.pc = osmo_ss7_pc_normalize(&rtbl->inst->cfg.pc_fmt, pc);
+ rt->cfg.priority = OSMO_SS7_ROUTE_PRIO_DEFAULT;
+ return rt;
+}
+
+/*! \brief Check whether route has already been inserted into its routing table.
+ * \returns true if already inserted, false if not.
+ */
+static bool ss7_route_inserted(const struct osmo_ss7_route *rt)
+{
+ return !llist_empty(&rt->list);
+}
+
+/*! \brief Set linkset on route entry
+ * \param[in] rt Route to be configured
+ * \param[in] linkset_name string name of the linkset to be used
+ * \returns 0 on success, negative on error.
+ */
+int
+ss7_route_set_linkset(struct osmo_ss7_route *rt, const char *linkset_name)
+{
+ struct osmo_ss7_linkset *lset;
+ struct osmo_ss7_as *as = NULL;
+ struct osmo_ss7_route_table *rtbl = rt->rtable;
+
+ if (rt->cfg.linkset_name) {
+ LOGSS7(rtbl->inst, LOGL_ERROR, "Attempt setting linkset on route already
configured!\n");
+ return -EBUSY;
+ }
+
+ if (ss7_route_inserted(rt)) {
+ LOGSS7(rtbl->inst, LOGL_ERROR, "Attempt setting linkset on route already in the
routing table!\n");
+ return -EALREADY;
+ }
+
+ lset = osmo_ss7_linkset_find_by_name(rtbl->inst, linkset_name);
+ if (!lset) {
+ as = osmo_ss7_as_find_by_name(rtbl->inst, linkset_name);
+ if (!as)
+ return -ENODEV;
+ }
+
+ rt->cfg.linkset_name = talloc_strdup(rt, linkset_name);
+ if (lset) {
+ rt->dest.linkset = lset;
+ LOGSS7(rtbl->inst, LOGL_INFO, "Creating route: pc=%u=%s mask=0x%x via linkset
'%s'\n",
+ rt->cfg.pc, osmo_ss7_pointcode_print(rtbl->inst, rt->cfg.pc),
+ rt->cfg.mask, lset->cfg.name);
+ } else {
+ rt->dest.as = as;
+ LOGSS7(rtbl->inst, LOGL_INFO, "Creating route: pc=%u=%s mask=0x%x via AS
'%s'\n",
+ rt->cfg.pc, osmo_ss7_pointcode_print(rtbl->inst, rt->cfg.pc),
+ rt->cfg.mask, as->cfg.name);
+ }
+ return 0;
+}
+
+/* insert the route in the ordered list of routes. The list is sorted by
+ * mask length, so that the more specific (longer mask) routes are
+ * first, while the less specific routes with shorter masks are last.
+ * Within the same mask length, the routes are ordered by priority.
+ * Hence, the first matching route in a linear iteration is the most
+ * specific match. */
+static void route_insert_sorted(struct osmo_ss7_route_table *rtbl,
+ struct osmo_ss7_route *cmp)
+{
+ struct osmo_ss7_route *rt;
+
+ llist_for_each_entry(rt, &rtbl->routes, list) {
+ if (rt->cfg.mask == cmp->cfg.mask &&
+ rt->cfg.priority > cmp->cfg.priority) {
+ /* insert before the current entry */
+ llist_add(&cmp->list, rt->list.prev);
+ return;
+ }
+ if (rt->cfg.mask < cmp->cfg.mask) {
+ /* insert before the current entry */
+ llist_add(&cmp->list, rt->list.prev);
+ return;
+ }
+ }
+ /* not added, i.e. no smaller mask length and priority found: we are the
+ * smallest mask and priority and thus should go last */
+ llist_add_tail(&cmp->list, &rtbl->routes);
+}
+
+/*! \brief Insert route into its routing table
+ * \param[in] rt Route to be inserted into its routing table
+ * \returns 0 on success, negative on error
+ *
+ * A route is only really used once it has been inserted into its routing table.
+ */
+int
+ss7_route_insert(struct osmo_ss7_route *rt)
+{
+ struct osmo_ss7_route *prev_rt;
+ struct osmo_ss7_route_table *rtbl = rt->rtable;
+
+ if (ss7_route_inserted(rt)) {
+ LOGSS7(rtbl->inst, LOGL_ERROR, "Attempt insert of route already in the routing
table!\n");
+ return -EALREADY;
+ }
+
+ if (!rt->cfg.linkset_name) {
+ LOGSS7(rtbl->inst, LOGL_ERROR, "Attempt insert of route with unset
linkset!\n");
+ return -EINVAL;
+ }
+
+ /* check for duplicates */
+ prev_rt = ss7_route_table_find_route_by_dpc_mask(rtbl, rt->cfg.pc, rt->cfg.mask);
+ if (prev_rt && !strcmp(prev_rt->cfg.linkset_name, rt->cfg.linkset_name))
{
+ LOGSS7(rtbl->inst, LOGL_ERROR,
+ "Refusing to create route with existing linkset name: pc=%u=%s mask=0x%x
via linkset/AS '%s'\n",
+ rt->cfg.pc, osmo_ss7_pointcode_print(rtbl->inst, rt->cfg.pc),
+ rt->cfg.mask, rt->cfg.linkset_name);
+ return -EADDRINUSE;
+ }
+
+ route_insert_sorted(rtbl, rt);
+ return 0;
+}
+
+/*! \brief Create a new route in the given routing table
+ * \param[in] rtbl Routing Table in which the route is to be created
+ * \param[in] pc Point Code of the destination of the route
+ * \param[in] mask Mask of the destination Point Code \ref pc
+ * \param[in] linkset_name string name of the linkset to be used
+ * \returns callee-allocated + initialized route, NULL on error
+ *
+ * The route allocated and returned by this API is already inserted into the
+ * routing table, with priority and qos-class set to 0.
+ * If you plan to use different values for priority and qos-class, avoid using
+ * this API and use ss7_route_alloc() + ss7_route_set_linkset() +
+ * ss7_route_insert() instead.
+ */
+struct osmo_ss7_route *
+ss7_route_create(struct osmo_ss7_route_table *rtbl, uint32_t pc,
+ uint32_t mask, const char *linkset_name)
+{
+ struct osmo_ss7_route *rt;
+ int rc;
+
+ rt = ss7_route_alloc(rtbl, pc, mask);
+ if (!rt)
+ return NULL;
+
+ if (ss7_route_set_linkset(rt, linkset_name) < 0) {
+ talloc_free(rt);
+ return NULL;
+ }
+
+ rc = ss7_route_insert(rt);
+ /* Keep old behavior, return already existing route: */
+ if (rc == -EADDRINUSE) {
+ talloc_free(rt);
+ return ss7_route_table_find_route_by_dpc_mask(rtbl, rt->cfg.pc, rt->cfg.mask);
+ }
+
+ return rt;
+}
+
+/*! \brief Destroy a given SS7 route */
+void ss7_route_destroy(struct osmo_ss7_route *rt)
+{
+ OSMO_ASSERT(ss7_initialized);
+
+ if (!rt)
+ return;
+
+ if (ss7_route_inserted(rt)) {
+ struct osmo_ss7_instance *inst = rt->rtable->inst;
+ LOGSS7(inst, LOGL_INFO,
+ "Destroying route: pc=%u=%s mask=0x%x via linkset/ASP '%s'\n",
+ rt->cfg.pc, osmo_ss7_pointcode_print(inst, rt->cfg.pc),
+ rt->cfg.mask, rt->cfg.linkset_name);
+ llist_del(&rt->list);
+ }
+ talloc_free(rt);
+}
+
+/* count number of consecutive leading (MSB) bits that are '1' */
+static unsigned int count_leading_one_bits(uint32_t inp, unsigned int nbits)
+{
+ unsigned int i;
+
+ for (i = 0; i < nbits; i++) {
+ if (!(inp & (1 << (nbits-1-i))))
+ return i;
+ }
+ return i;
+}
+
+/* determine the mask length in number of bits; negative if non-consecutive mask */
+static int u32_masklen(uint32_t mask, unsigned int nbits)
+{
+ unsigned int i;
+ unsigned int leading_one_bits = count_leading_one_bits(mask, nbits);
+
+ /* are there any bits set after the initial bits? */
+ for (i = leading_one_bits; i < nbits; i++) {
+ if (mask & (1 << (nbits-1-i)))
+ return -1; /* not a simple prefix mask */
+ }
+ return leading_one_bits;
+}
+
+const char *osmo_ss7_route_print(const struct osmo_ss7_route *rt)
+{
+ const struct osmo_ss7_instance *inst = rt->rtable->inst;
+ unsigned int pc_width = osmo_ss7_pc_width(&inst->cfg.pc_fmt);
+ static char buf[64];
+ int rc = u32_masklen(rt->cfg.mask, pc_width);
+
+ if (rc < 0)
+ snprintf(buf, sizeof(buf), "%s/%s", osmo_ss7_pointcode_print(inst,
rt->cfg.pc),
+ osmo_ss7_pointcode_print2(inst, rt->cfg.mask));
+ else
+ snprintf(buf, sizeof(buf), "%s/%u", osmo_ss7_pointcode_print(inst,
rt->cfg.pc), rc);
+ return buf;
+}
diff --git a/src/osmo_ss7_route_table.c b/src/osmo_ss7_route_table.c
index 2939bf4..4ab4594 100644
--- a/src/osmo_ss7_route_table.c
+++ b/src/osmo_ss7_route_table.c
@@ -24,6 +24,7 @@
#include <osmocom/sigtran/mtp_sap.h>
#include <osmocom/sigtran/osmo_ss7.h>
+#include "ss7_route.h"
#include "ss7_route_table.h"
#include "ss7_internal.h"
diff --git a/src/osmo_ss7_vty.c b/src/osmo_ss7_vty.c
index aa8c9bc..6c9db5a 100644
--- a/src/osmo_ss7_vty.c
+++ b/src/osmo_ss7_vty.c
@@ -46,6 +46,7 @@
#include "xua_internal.h"
#include <osmocom/sigtran/sccp_sap.h>
#include "sccp_internal.h"
+#include "ss7_route.h"
#include "ss7_route_table.h"
#include "ss7_internal.h"
@@ -443,7 +444,7 @@
return CMD_SUCCESS;
destroy_warning:
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
return CMD_WARNING;
}
@@ -477,7 +478,7 @@
return CMD_WARNING;
}
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
return CMD_SUCCESS;
}
@@ -2025,7 +2026,7 @@
if (cs7_role == CS7_ROLE_ASP) {
rt = ss7_route_table_find_route_by_dpc_mask(as->inst->rtable_system, rkey->pc,
0xffffff);
if (rt)
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
}
rkey->pc = pc;
@@ -2036,7 +2037,7 @@
/* automatically add new route (see also comment above) */
if (cs7_role == CS7_ROLE_ASP) {
- if (!osmo_ss7_route_create(as->inst->rtable_system, rkey->pc, 0xffffff,
as->cfg.name)) {
+ if (!ss7_route_create(as->inst->rtable_system, rkey->pc, 0xffffff,
as->cfg.name)) {
vty_out(vty, "Cannot create route (pc=%s, linkset=%s) to AS %s", dpc,
as->cfg.name, VTY_NEWLINE);
return CMD_WARNING;
}
diff --git a/src/sccp_scrc.c b/src/sccp_scrc.c
index be23c21..5b541d3 100644
--- a/src/sccp_scrc.c
+++ b/src/sccp_scrc.c
@@ -33,8 +33,10 @@
#include <osmocom/sigtran/protocol/mtp.h>
#include "sccp_internal.h"
+#include "ss7_route.h"
#include "xua_internal.h"
+
/***********************************************************************
* Helper Functions
***********************************************************************/
diff --git a/src/sccp_user.c b/src/sccp_user.c
index 277ca5f..6edbfd1 100644
--- a/src/sccp_user.c
+++ b/src/sccp_user.c
@@ -39,6 +39,7 @@
#include "sccp_internal.h"
#include "xua_internal.h"
+#include "ss7_route.h"
#include "ss7_route_table.h"
#include "ss7_internal.h"
@@ -589,7 +590,7 @@
rt = ss7_route_table_find_route_by_dpc_mask(ss7->rtable_system, 0, 0);
if (!rt) {
LOGP(DLSCCP, LOGL_NOTICE, "%s: Creating default route\n", name);
- rt = osmo_ss7_route_create(ss7->rtable_system, 0, 0,
+ rt = ss7_route_create(ss7->rtable_system, 0, 0,
as->cfg.name);
if (!rt)
goto out_as;
@@ -711,7 +712,7 @@
osmo_ss7_asp_destroy(asp);
out_rt:
if (rt_created)
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
out_as:
if (as_created)
osmo_ss7_as_destroy(as);
@@ -838,7 +839,7 @@
goto out_strings;
/* route only selected PC to the client */
- rt = osmo_ss7_route_create(ss7->rtable_system, pc, 0xffff, as_name);
+ rt = ss7_route_create(ss7->rtable_system, pc, 0xffff, as_name);
if (!rt)
goto out_as;
@@ -868,7 +869,7 @@
out_asp:
osmo_ss7_asp_destroy(asp);
out_rt:
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
out_as:
osmo_ss7_as_destroy(as);
out_strings:
diff --git a/src/ss7_route.h b/src/ss7_route.h
new file mode 100644
index 0000000..6e74ff0
--- /dev/null
+++ b/src/ss7_route.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <stdint.h>
+#include <osmocom/core/linuxlist.h>
+
+/***********************************************************************
+ * SS7 Routes
+ ***********************************************************************/
+
+struct osmo_ss7_instance;
+struct osmo_ss7_route_table;
+struct osmo_ss7_linkset;
+struct osmo_ss7_as;
+
+struct osmo_ss7_route {
+ /*! member in \ref osmo_ss7_route_table.routes */
+ struct llist_head list;
+ /*! \ref osmo_ss7_route_table to which we belong */
+ struct osmo_ss7_route_table *rtable;
+
+ struct {
+ /*! pointer to linkset (destination) of route */
+ struct osmo_ss7_linkset *linkset;
+ /*! pointer to Application Server */
+ struct osmo_ss7_as *as;
+ } dest;
+
+ struct {
+ /* FIXME: presence? */
+ uint32_t pc;
+ uint32_t mask;
+ /*! human-specified linkset name */
+ char *linkset_name;
+ /*! lower priority is higher */
+ uint32_t priority;
+ uint8_t qos_class;
+ } cfg;
+};
+
+struct osmo_ss7_route *
+ss7_route_find_dpc(struct osmo_ss7_route_table *rtbl, uint32_t dpc);
+struct osmo_ss7_route *
+ss7_route_find_dpc_mask(struct osmo_ss7_route_table *rtbl, uint32_t dpc,
+ uint32_t mask);
+struct osmo_ss7_route *
+ss7_route_create(struct osmo_ss7_route_table *rtbl, uint32_t dpc,
+ uint32_t mask, const char *linkset_name);
+void ss7_route_destroy(struct osmo_ss7_route *rt);
diff --git a/src/xua_as_fsm.c b/src/xua_as_fsm.c
index 2083ca0..dff0d06 100644
--- a/src/xua_as_fsm.c
+++ b/src/xua_as_fsm.c
@@ -23,6 +23,7 @@
#include <osmocom/sigtran/protocol/sua.h>
#include <osmocom/sigtran/protocol/m3ua.h>
+#include "ss7_route.h"
#include "ss7_route_table.h"
#include "xua_asp_fsm.h"
#include "xua_as_fsm.h"
@@ -236,7 +237,7 @@
/* As opposed to M3UA, there is no RKM and we have to implicitly
* automatically add a route once an IPA connection has come up */
- if (osmo_ss7_route_create(inst->rtable_system, as->cfg.routing_key.pc, 0xffffff,
as->cfg.name))
+ if (ss7_route_create(inst->rtable_system, as->cfg.routing_key.pc, 0xffffff,
as->cfg.name))
xafp->ipa_route_created = true;
}
@@ -269,7 +270,7 @@
return;
}
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
xafp->ipa_route_created = false;
}
diff --git a/src/xua_rkm.c b/src/xua_rkm.c
index 774cf3a..38fb903 100644
--- a/src/xua_rkm.c
+++ b/src/xua_rkm.c
@@ -28,6 +28,7 @@
#include <osmocom/sigtran/osmo_ss7.h>
#include <osmocom/sigtran/protocol/m3ua.h>
+#include "ss7_route.h"
#include "ss7_route_table.h"
#include "xua_internal.h"
#include "xua_as_fsm.h"
@@ -260,7 +261,7 @@
as->cfg.routing_key.context = rctx;
/* add route for that routing key */
- rt = osmo_ss7_route_create(as->inst->rtable_system, dpc, 0xFFFFFF, namebuf);
+ rt = ss7_route_create(as->inst->rtable_system, dpc, 0xFFFFFF, namebuf);
if (!rt) {
LOGPASP(asp, DLSS7, LOGL_ERROR, "RKM: Cannot insert route for DPC %s / as
%s\n",
osmo_ss7_pointcode_print(asp->inst, dpc), namebuf);
@@ -271,7 +272,7 @@
/* append to list of newly assigned as */
if (*nas_idx >= max_nas_idx) {
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
osmo_ss7_as_destroy(as);
LOGPASP(asp, DLSS7, LOGL_ERROR, "RKM: not enough room for newly assigned AS (max
%u AS)\n",
max_nas_idx+1);
@@ -392,7 +393,7 @@
* route and destroy the AS */
if (as->rkm_dyn_allocated) {
/* remove route + AS definition */
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
osmo_ss7_as_destroy(as);
}
/* report success */
diff --git a/tests/ss7/ss7_test.c b/tests/ss7/ss7_test.c
index 5f00f78..79f6912 100644
--- a/tests/ss7/ss7_test.c
+++ b/tests/ss7/ss7_test.c
@@ -1,3 +1,4 @@
+#include "../src/ss7_route.h"
#include "../src/ss7_route_table.h"
#include "../src/xua_internal.h"
#include "../src/xua_asp_fsm.h"
@@ -162,14 +163,14 @@
/* route with full mask */
OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 12) == NULL);
- rt = osmo_ss7_route_create(rtbl, 12, 0xffff, "a");
+ rt = ss7_route_create(rtbl, 12, 0xffff, "a");
printf("route with full mask: %s\n", osmo_ss7_route_print(rt));
OSMO_ASSERT(rt);
OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 12) == rt);
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
/* route with partial mask */
- rt = osmo_ss7_route_create(rtbl, 8, 0xfff8, "a");
+ rt = ss7_route_create(rtbl, 8, 0xfff8, "a");
printf("route with partial mask: %s\n", osmo_ss7_route_print(rt));
OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 8) == rt);
OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 9) == rt);
@@ -178,23 +179,23 @@
OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 16) == NULL);
/* insert more specific route for 12, must have higher priority
* than existing one */
- rt12 = osmo_ss7_route_create(rtbl, 12, 0xffff, "b");
+ rt12 = ss7_route_create(rtbl, 12, 0xffff, "b");
OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 12) == rt12);
OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 15) == rt);
OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 16) == NULL);
/* add a default route, which should have lowest precedence */
- rtdef = osmo_ss7_route_create(rtbl, 0, 0, "a");
+ rtdef = ss7_route_create(rtbl, 0, 0, "a");
OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 12) == rt12);
OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 15) == rt);
OSMO_ASSERT(ss7_route_table_find_route_by_dpc(rtbl, 16) == rtdef);
- osmo_ss7_route_destroy(rtdef);
- osmo_ss7_route_destroy(rt12);
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rtdef);
+ ss7_route_destroy(rt12);
+ ss7_route_destroy(rt);
- rt = osmo_ss7_route_create(rtbl, 8, 0xfff9, "a");
+ rt = ss7_route_create(rtbl, 8, 0xfff9, "a");
printf("route with non-consecutive mask: %s\n", osmo_ss7_route_print(rt));
- osmo_ss7_route_destroy(rt);
+ ss7_route_destroy(rt);
osmo_ss7_linkset_destroy(lset_a);
osmo_ss7_linkset_destroy(lset_b);
--
To view, visit
https://gerrit.osmocom.org/c/libosmo-sigtran/+/38636?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I8a86966cb6a5361687987a2e9acd79c4ab3d97c4
Gerrit-Change-Number: 38636
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>