summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2017-07-19 18:41:09 +0200
committerHarald Welte <laforge@gnumonks.org>2017-07-22 09:08:13 +0000
commitdae7491c14f5e7bdfecb25fba5c2624127daadc8 (patch)
tree8780c71d3873a5771bffb08cf001455bf8df8969
parent9fc351de69a2f3f451a2c44145fbabb156ef410a (diff)
sccp: make simple client configurable via VTY
The osmo_sccp_simple_client_on_ss7_id and osmo_sccp_simple_client are not entirely configurable via VTY commands. The relation to the VTY is implicit. The user may set up instance objects via VTY (cs7/ss7, AS, ASP), which are then automatically created on startup. Each cs7 instance gets its own ID via the VTY configuration. When osmo_sccp_simple_client_on_ss7_id() is called with the cs7 instance id. (for osmo_sccp_simple_client() the ID will be hardcoded to 1), the function automatically checks if the CS7 instance is present, if not it will create one automatically using the caller supplied parameters as a defult. If a CS7 instance is present, the function checks for the presence of an AS and an ASP. These objects are present, they will be used. If not, new objects will be created. Both functions must not be called if an SCCP instance is already present. Since there can only be one SCCP instance per CS7 instance, this is an error condition. Add additional logic that checks to detect an already existing, valid configuration. If no or an insufficient configuration is detected, use the caller supplied parameters as default configuration. Change-Id: I293f3526ce6182dca74a169a23449dbc7af57c7c
-rw-r--r--include/osmocom/sigtran/osmo_ss7.h5
-rw-r--r--src/osmo_ss7.c52
-rw-r--r--src/sccp_user.c137
3 files changed, 156 insertions, 38 deletions
diff --git a/include/osmocom/sigtran/osmo_ss7.h b/include/osmocom/sigtran/osmo_ss7.h
index 57a4e06..87ace4a 100644
--- a/include/osmocom/sigtran/osmo_ss7.h
+++ b/include/osmocom/sigtran/osmo_ss7.h
@@ -307,6 +307,8 @@ struct osmo_ss7_as *
osmo_ss7_as_find_by_rctx(struct osmo_ss7_instance *inst, uint32_t rctx);
struct osmo_ss7_as *
osmo_ss7_as_find_by_l_rk_id(struct osmo_ss7_instance *inst, uint32_t l_rk_id);
+struct osmo_ss7_as *osmo_ss7_as_find_by_proto(struct osmo_ss7_instance *inst,
+ enum osmo_ss7_asp_protocol proto);
struct osmo_ss7_as *
osmo_ss7_as_find_or_create(struct osmo_ss7_instance *inst, const char *name,
enum osmo_ss7_asp_protocol proto);
@@ -383,6 +385,9 @@ struct osmo_ss7_asp {
struct osmo_ss7_asp *
osmo_ss7_asp_find_by_name(struct osmo_ss7_instance *inst, const char *name);
+struct osmo_ss7_asp
+*osmo_ss7_asp_find_by_proto(struct osmo_ss7_as *as,
+ enum osmo_ss7_asp_protocol proto);
struct osmo_ss7_asp *
osmo_ss7_asp_find_or_create(struct osmo_ss7_instance *inst, const char *name,
uint16_t remote_port, uint16_t local_port,
diff --git a/src/osmo_ss7.c b/src/osmo_ss7.c
index c13c588..eb5a4ef 100644
--- a/src/osmo_ss7.c
+++ b/src/osmo_ss7.c
@@ -833,6 +833,41 @@ osmo_ss7_as_find_by_l_rk_id(struct osmo_ss7_instance *inst, uint32_t l_rk_id)
return NULL;
}
+/*! \brief Find Application Server (AS) by given protocol.
+ * \param[in] inst SS7 Instance on which we operate
+ * \param[in] proto Protocol identifier that must match
+ * \returns pointer to AS on success; NULL otherwise
+ * If an AS has an ASP also matching the given protocol, that AS is preferred.
+ * If there are multiple matches, return the first matching AS. */
+struct osmo_ss7_as *osmo_ss7_as_find_by_proto(struct osmo_ss7_instance *inst,
+ enum osmo_ss7_asp_protocol proto)
+{
+ struct osmo_ss7_as *as;
+ struct osmo_ss7_as *as_without_asp = NULL;
+
+ OSMO_ASSERT(ss7_initialized);
+
+ /* Loop through the list with AS and try to find one where the proto
+ matches up */
+ llist_for_each_entry(as, &inst->as_list, list) {
+ if (as->cfg.proto == proto) {
+
+ /* Put down the first AS that matches the proto, just in
+ * case we will not find any matching ASP */
+ if (!as_without_asp)
+ as_without_asp = as;
+
+ /* Check if the candicate we have here has any suitable
+ * ASP */
+ if (osmo_ss7_asp_find_by_proto(as, proto))
+ return as;
+ }
+ }
+
+ /* Return with the second best find, if there is any */
+ return as_without_asp;
+}
+
/*! \brief Find or Create Application Server
* \param[in] inst SS7 Instance on which we operate
* \param[in] name Name of Application Server
@@ -1044,6 +1079,23 @@ osmo_ss7_asp_find_by_socket_addr(int fd)
return NULL;
}
+/*! \brief Find an ASP that matches the given protocol.
+ * \param[in] as Application Server in which to look for \ref asp
+ * \returns SS7 ASP in case a matching one is found; NULL otherwise */
+struct osmo_ss7_asp
+*osmo_ss7_asp_find_by_proto(struct osmo_ss7_as *as,
+ enum osmo_ss7_asp_protocol proto)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(as->cfg.asps); i++) {
+ if (as->cfg.asps[i] && as->cfg.asps[i]->cfg.proto == proto)
+ return as->cfg.asps[i];
+ }
+
+ return NULL;
+}
+
struct osmo_ss7_asp *
osmo_ss7_asp_find_or_create(struct osmo_ss7_instance *inst, const char *name,
uint16_t remote_port, uint16_t local_port,
diff --git a/src/sccp_user.c b/src/sccp_user.c
index b21a756..c9443a2 100644
--- a/src/sccp_user.c
+++ b/src/sccp_user.c
@@ -242,54 +242,113 @@ osmo_sccp_simple_client_on_ss7_id(void *ctx, uint32_t ss7_id, const char *name,
int remote_port, const char *remote_ip)
{
struct osmo_ss7_instance *ss7;
+ bool ss7_created = false;
struct osmo_ss7_as *as;
+ bool as_created = false;
struct osmo_ss7_route *rt;
+ bool rt_created = false;
struct osmo_ss7_asp *asp;
- char *as_name, *asp_name;
+ bool asp_created = false;
+ char *as_name, *asp_name = NULL;
+ /* Choose default ports when the caller does not supply valid port
+ * numbers. */
if (!remote_port || remote_port < 0)
remote_port = osmo_ss7_asp_protocol_port(prot);
if (local_port < 0)
local_port = osmo_ss7_asp_protocol_port(prot);
- /* allocate + initialize SS7 instance */
- ss7 = osmo_ss7_instance_find_or_create(ctx, ss7_id);
+ /* Check if there is already an ss7 instance present under
+ * the given id. If not, we will create a new one. */
+ ss7 = osmo_ss7_instance_find(ss7_id);
if (!ss7) {
- LOGP(DLSCCP, LOGL_ERROR, "Failed to find or create SS7 instance\n");
- return NULL;
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Creating SS7 instance\n",
+ name);
+
+ /* Create a new ss7 instance */
+ ss7 = osmo_ss7_instance_find_or_create(ctx, ss7_id);
+ if (!ss7) {
+ LOGP(DLSCCP, LOGL_ERROR,
+ "Failed to find or create SS7 instance\n");
+ return NULL;
+ }
+
+ /* Setup primary pointcode
+ * NOTE: This means that the user must set the pointcode to a
+ * proper value when a cs7 instance is defined via the VTY. */
+ ss7->cfg.primary_pc = pc;
+ ss7_created = true;
+ }
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Using SS7 instance %u, pc:%s\n", name,
+ ss7->cfg.id, osmo_ss7_pointcode_print(ss7, ss7->cfg.primary_pc));
+
+ /* There must not be an existing SCCP istance, regarless if the simple
+ * client has created the SS7 instance or if it was already present.
+ * An already existing SCCP instance would be an indication that this
+ * function has been called twice with the same SS7 instance, which
+ * must not be the case! */
+ OSMO_ASSERT(ss7->sccp == NULL);
+
+ /* Check if there is already an application server that matches
+ * the protocol we intend to use. If not, we will create one. */
+ as = osmo_ss7_as_find_by_proto(ss7, prot);
+ if (!as) {
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Creating AS instance\n",
+ name);
+ as_name = talloc_asprintf(ctx, "as-clnt-%s", name);
+ as = osmo_ss7_as_find_or_create(ss7, as_name, prot);
+ talloc_free(as_name);
+ if (!as)
+ goto out_ss7;
+ as_created = true;
+
+ as->cfg.routing_key.pc = ss7->cfg.primary_pc;
+
+ /* install default route */
+ rt = osmo_ss7_route_create(ss7->rtable_system, 0, 0,
+ as->cfg.name);
+ if (!rt)
+ goto out_as;
+ rt_created = true;
+ }
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Using AS instance %s\n", name,
+ as->cfg.name);
+
+ /* Check if we do already have an application server process
+ * that is associated with the application server we have choosen
+ * the application server process must also match the protocol
+ * we intend to use. */
+ asp = osmo_ss7_asp_find_by_proto(as, prot);
+ if (!asp) {
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Creating ASP instance\n",
+ name);
+ asp_name = talloc_asprintf(ctx, "asp-clnt-%s", name);
+ asp =
+ osmo_ss7_asp_find_or_create(ss7, asp_name, remote_port,
+ local_port, prot);
+ talloc_free(asp_name);
+ if (!asp)
+ goto out_rt;
+ asp_created = true;
+
+ asp->cfg.local.host = talloc_strdup(asp, local_ip);
+ asp->cfg.remote.host = talloc_strdup(asp, remote_ip);
+
+ osmo_ss7_as_add_asp(as, asp->cfg.name);
}
- ss7->cfg.primary_pc = pc;
-
- as_name = talloc_asprintf(ctx, "as-clnt-%s", name);
- asp_name = talloc_asprintf(ctx, "asp-clnt-%s", name);
-
- /* application server */
- as = osmo_ss7_as_find_or_create(ss7, as_name, prot);
- if (!as)
- goto out_strings;
-
- as->cfg.routing_key.pc = pc;
- /* install default route */
- rt = osmo_ss7_route_create(ss7->rtable_system, 0, 0, as_name);
- if (!rt)
- goto out_as;
- talloc_free(as_name);
+ /* Ensure that the ASP we use is set to client mode. */
+ asp->cfg.is_server = false;
- /* application server process */
- asp = osmo_ss7_asp_find_or_create(ss7, asp_name, remote_port, local_port,
- prot);
- if (!asp)
- goto out_rt;
- asp->cfg.local.host = talloc_strdup(asp, local_ip);
- asp->cfg.remote.host = talloc_strdup(asp, remote_ip);
- osmo_ss7_as_add_asp(as, asp_name);
+ /* Restart ASP */
if (prot != OSMO_SS7_ASP_PROT_IPA)
osmo_ss7_asp_use_default_lm(asp, LOGL_DEBUG);
- talloc_free(asp_name);
osmo_ss7_asp_restart(asp);
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Using ASP instance %s\n", name,
+ asp->cfg.name);
- /* Allocate SCCP stack + SCCP user */
+ /* Allocate SCCP instance */
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Creating SCCP instance\n", name);
ss7->sccp = osmo_sccp_instance_create(ss7, NULL);
if (!ss7->sccp)
goto out_asp;
@@ -297,15 +356,17 @@ osmo_sccp_simple_client_on_ss7_id(void *ctx, uint32_t ss7_id, const char *name,
return ss7->sccp;
out_asp:
- osmo_ss7_asp_destroy(asp);
+ if (asp_created)
+ osmo_ss7_asp_destroy(asp);
out_rt:
- osmo_ss7_route_destroy(rt);
+ if (rt_created)
+ osmo_ss7_route_destroy(rt);
out_as:
- osmo_ss7_as_destroy(as);
-out_strings:
- talloc_free(as_name);
- talloc_free(asp_name);
- osmo_ss7_instance_destroy(ss7);
+ if (as_created)
+ osmo_ss7_as_destroy(as);
+out_ss7:
+ if (ss7_created)
+ osmo_ss7_instance_destroy(ss7);
return NULL;
}