Change in osmo-mgw[master]: endp: add E1 endpoint interlocking

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

dexter gerrit-no-reply at lists.osmocom.org
Thu Jun 18 10:35:06 UTC 2020


dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-mgw/+/18898 )


Change subject: endp: add E1 endpoint interlocking
......................................................................

endp: add E1 endpoint interlocking

E1 endpoint names also represent different rates, this may mean that
some rate / subslot combinations are not possible because they overlap
withi nthe timeslot. When the equipment (BSC) is properly configured,
this will be no problem, however invalid configuration may cause the
selection of overlapping endpoints and this needs to be prevented, and
logged. Also rate counters need to be in place.

Change-Id: I18e90b10648a7e504371179ad144645fc82e1c27
Related: OS#2547
---
M include/osmocom/mgcp/mgcp_endp.h
M include/osmocom/mgcp/mgcp_ratectr.h
M src/libosmo-mgcp/mgcp_endp.c
M src/libosmo-mgcp/mgcp_protocol.c
M src/libosmo-mgcp/mgcp_ratectr.c
M src/libosmo-mgcp/mgcp_vty.c
6 files changed, 279 insertions(+), 2 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-mgw refs/changes/98/18898/1

diff --git a/include/osmocom/mgcp/mgcp_endp.h b/include/osmocom/mgcp/mgcp_endp.h
index 0f9110c..a58053a 100644
--- a/include/osmocom/mgcp/mgcp_endp.h
+++ b/include/osmocom/mgcp/mgcp_endp.h
@@ -110,3 +110,4 @@
 					      const struct mgcp_trunk *trunk);
 struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 					struct mgcp_config *cfg);
+bool mgcp_endp_avail(struct mgcp_endpoint *endp);
diff --git a/include/osmocom/mgcp/mgcp_ratectr.h b/include/osmocom/mgcp/mgcp_ratectr.h
index a579f5b..d0bc628 100644
--- a/include/osmocom/mgcp/mgcp_ratectr.h
+++ b/include/osmocom/mgcp/mgcp_ratectr.h
@@ -28,6 +28,7 @@
 	MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS,
 	MGCP_CRCX_FAIL_CODEC_NEGOTIATION,
 	MGCP_CRCX_FAIL_BIND_PORT,
+	MGCP_CRCX_FAIL_AVAIL,
 };
 
 /* Global MCGP MDCX related rate counters */
@@ -45,7 +46,8 @@
 	MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
 	MGCP_MDCX_FAIL_START_RTP,
 	MGCP_MDCX_FAIL_REJECTED_BY_POLICY,
-	MGCP_MDCX_DEFERRED_BY_POLICY
+	MGCP_MDCX_DEFERRED_BY_POLICY,
+	MGCP_MDCX_FAIL_AVAIL,
 };
 
 /* Global MCGP DLCX related rate counters */
@@ -58,6 +60,7 @@
 	MGCP_DLCX_FAIL_UNHANDLED_PARAM,
 	MGCP_DLCX_FAIL_REJECTED_BY_POLICY,
 	MGCP_DLCX_DEFERRED_BY_POLICY,
+	MGCP_DLCX_FAIL_AVAIL,
 };
 
 /* NOTE: When adding counters, also the dump_ratectr_* routines in vty.c must be updated. */
diff --git a/src/libosmo-mgcp/mgcp_endp.c b/src/libosmo-mgcp/mgcp_endp.c
index 94d4083..5607c31 100644
--- a/src/libosmo-mgcp/mgcp_endp.c
+++ b/src/libosmo-mgcp/mgcp_endp.c
@@ -25,6 +25,10 @@
 #include <osmocom/mgcp/mgcp_endp.h>
 #include <osmocom/mgcp/mgcp_trunk.h>
 
+#define E1_TIMESLOTS 32
+#define E1_RATE_MAX 64
+#define E1_OFFS_MAX 8
+
 /* Endpoint typeset definition */
 const struct mgcp_endpoint_typeset ep_typeset = {
 	/* Specify endpoint properties for RTP endpoint */
@@ -213,7 +217,9 @@
 
 	for (i = 0; i < trunk->number_endpoints; i++) {
 		endp = trunk->endpoints[i];
-		if (endp->callid == NULL)
+		/* A free endpoint must not serve a call already and it must
+		 * be available. */
+		if (endp->callid == NULL && mgcp_endp_avail(endp))
 			return endp;
 	}
 
@@ -362,3 +368,251 @@
 		*cause = 0;
 	return endp;
 }
+
+/* Get the E1 timeslot number from a given E1 endpoint name
+   (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
+static uint8_t e1_ts_nr_from_epname(char *epname)
+{
+	char buf[MGCP_ENDPOINT_MAXLEN + 1];
+	char *save_ptr = NULL;
+	char *buf_ptr = buf;
+	char *token;
+	unsigned long int res = 0;
+
+	strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);
+
+	while (1) {
+		token = strtok_r(buf_ptr, "/", &save_ptr);
+		buf_ptr = NULL;
+		if (!token)
+			break;
+		if (strncmp(token, "s-", 2) == 0) {
+			res = strtoul(token + 2, NULL, 10);
+			if (errno == ERANGE || res > E1_TIMESLOTS)
+				return 0xff;
+			return (uint8_t) res;
+		}
+	}
+
+	return 0xff;
+}
+
+/* Get the E1 timeslot number from a given E1 endpoint name
+   (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
+static uint8_t e1_rate_from_epname(char *epname)
+{
+	char buf[MGCP_ENDPOINT_MAXLEN + 1];
+	char *save_ptr = NULL;
+	char *buf_ptr = buf;
+	char *token;
+	unsigned long int res = 0;
+	static const uint8_t rates[] = { 64, 32, 16, 16, 8 };
+	unsigned int i;
+
+	strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);
+
+	while (1) {
+		token = strtok_r(buf_ptr, "/", &save_ptr);
+		buf_ptr = NULL;
+		if (!token)
+			break;
+		if (strncmp(token, "su", 2) == 0) {
+			res = strtoul(token + 2, NULL, 10);
+			if (errno == ERANGE || res > E1_RATE_MAX)
+				return 0xff;
+			/* Make sure the rate is a valid rate */
+			for (i = 0; i < sizeof(rates); i++) {
+				if (res == rates[i])
+					return (uint8_t) res;
+			}
+			return 0xff;
+		}
+	}
+
+	return 0xff;
+}
+
+/* Get the E1 bitstream offset from a given E1 endpoint name
+   (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
+static uint8_t e1_offs_from_epname(char *epname)
+{
+	char buf[MGCP_ENDPOINT_MAXLEN + 1];
+	char *save_ptr = NULL;
+	char *buf_ptr = buf;
+	char *token;
+	unsigned long int res = 0;
+
+	strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);
+
+	while (1) {
+		token = strtok_r(buf_ptr, "/", &save_ptr);
+		buf_ptr = NULL;
+		if (!token)
+			break;
+		if (strncmp(token, "su", 2) == 0) {
+			token = strstr(token, "-");
+			if (!token)
+				return 0xff;
+			token += 1;
+			res = strtoul(token, NULL, 10);
+			if (errno == ERANGE || res > E1_OFFS_MAX)
+				return 0xff;
+			return (uint8_t) res;
+		}
+	}
+
+	return 0xff;
+}
+
+/* Get the E1 subslot number (internal) from a given E1 endpoint name
+   (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
+static uint8_t e1_ss_nr_from_epname(char *epname)
+{
+	uint8_t rate;
+	uint8_t offs;
+	unsigned int i;
+
+	rate = e1_rate_from_epname(epname);
+	offs = e1_offs_from_epname(epname);
+
+	/* See also comment in gen_e1_epname() */
+	static const uint8_t rates[] =
+	    { 64, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8 };
+	static const uint8_t offsets[] =
+	    { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 };
+
+	OSMO_ASSERT(sizeof(rates) == sizeof(offsets));
+
+	for (i = 0; i < sizeof(rates); i++) {
+		if ((rates[i] == rate) && (offsets[i] == offs))
+			return i;
+	}
+
+	return 0xff;
+}
+
+/* Check if the selected E1 endpoint is avalable, which means that none of
+ * the overlapping endpoints are currently serving a call. (if the system
+ * is properly configured such a situation should never ocurr!) */
+static bool endp_avail_e1(struct mgcp_endpoint *endp)
+{
+	/* The following map shows the overlapping of the subslots and their
+	 * respective rates. The numbers on the right running from top to bottom
+	 * are the bit offsets in the whole 64k timeslot. The numbers inside the
+	 * boxes symbolize the internal subsolt number (array index) and the
+	 * rate in the form: i:r where i is the subsolt number and r the
+	 * respective rate.
+	 *
+	 * +--------+--------+--------+--------+ 0
+	 * |        |        |        |  7:8k  |
+	 * |        |        + 3:16k  +--------+ 1
+	 * |        |        |        |  8:8k  |
+	 * |        | 1:32k  +--------+--------+ 2
+	 * |        |        |        |  9:8k  |
+	 * |        |        + 4:16k  +--------+ 3
+	 * |        |        |        | 10:8k  |
+	 * | 0:64k  +--------+--------+--------+ 4
+	 * |        |        |        | 11:8k  |
+	 * |        |        + 5:16k  +--------+ 5
+	 * |        |        |        | 12:8k  |
+	 * |        | 2:32k  +--------+--------+ 6
+	 * |        |        |        | 13:8k  |
+	 * |        |        + 6:16k  +--------+ 7
+	 * |        |        |        | 14:8k  |
+	 * +--------+--------+--------+--------+ 8
+	 *
+	 * The following array contains tables with the subslot numbers that must be
+	 * unused for each subslot. During this test we do not have to check the
+	 * endpoint we need to verify, only the overlaps need to be checked. This is
+	 * also the reason why the related subslot number is missing from each each
+	 * line. */
+	static const int8_t interlock_tab[15][16] =
+	    { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1 },
+	{ 0, 3, 4, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 5, 6, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 1, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 1, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 2, 11, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 2, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 2, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 2, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	{ 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }
+	};
+
+	const int8_t *interlock;
+	unsigned int i;
+	uint8_t ts_nr = 0;
+	uint8_t ss_nr = 0;
+	char *epname_check;
+	struct mgcp_endpoint *endp_check;
+	bool available = true;
+
+	/* This function must only be used with E1 type endpoints! */
+	OSMO_ASSERT(endp->trunk->trunk_type == MGCP_TRUNK_E1);
+
+	ts_nr = e1_ts_nr_from_epname(endp->name);
+	ss_nr = e1_ss_nr_from_epname(endp->name);
+	if (ts_nr == 0xff || ss_nr == 0xff) {
+		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
+			 "cannot check endpoint availability, endpoint name not parseable!\n");
+		return false;
+	}
+
+	interlock = interlock_tab[ss_nr];
+
+	for(i=0;i<15;i++) {
+		/* Detect table end */
+		if (interlock[i] == -1)
+			break;
+
+		/* Pick overlapping endpoint to check */
+		epname_check =
+		    gen_e1_epname(endp, endp->trunk->trunk_nr, ts_nr,
+				  interlock[i]);
+		endp_check = find_specific_endpoint(epname_check, endp->trunk);
+		if (!endp_check) {
+			LOGPENDP(endp, DLMGCP, LOGL_ERROR,
+				 "cannot check endpoint availability, overlapping endpoint:%s not found!\n", epname_check);
+			talloc_free(epname_check);
+			continue;
+		}
+		talloc_free(epname_check);
+
+		/* Check if overlapping endpoint currently serves another call
+		 * (This is an exceptional situation, that should not occurr
+		 * in a properly configured environment!) */
+		if (endp_check->callid) {
+			LOGPENDP(endp, DLMGCP, LOGL_ERROR,
+				 "endpoint unavailable - overlapping endpoint:%s already serves a call!\n",
+				 endp_check->name);
+			available = false;
+		}
+	}
+
+	return available;
+}
+
+/*! check if an endpoint is available for any kind of operation.
+ *  \param[in] endp endpoint to check.
+ *  \returns true if endpoint is avalable, false it is blocked for any reason. */
+bool mgcp_endp_avail(struct mgcp_endpoint *endp)
+{
+	switch (endp->trunk->trunk_type) {
+	case MGCP_TRUNK_VIRTUAL:
+		/* There are no obsticels that may render a virtual trunk
+		 * endpoint unusable, so virtual trunk endpoints are always
+		 * available */
+		return true;
+	case MGCP_TRUNK_E1:
+		return endp_avail_e1(endp);
+	default:
+		OSMO_ASSERT(false);
+	}
+
+	return false;
+}
diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c
index 1e393e2..f2fc20c 100644
--- a/src/libosmo-mgcp/mgcp_protocol.c
+++ b/src/libosmo-mgcp/mgcp_protocol.c
@@ -747,6 +747,10 @@
 	int rc;
 
 	LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
+	if (!mgcp_endp_avail(endp)) {
+		rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_AVAIL]);
+		return create_err_response(NULL, 501, "CRCX", p->trans);
+	}
 
 	/* parse CallID C: and LocalParameters L: */
 	for_each_line(line, p->save) {
@@ -1004,6 +1008,11 @@
 
 	LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 
+	if (!mgcp_endp_avail(endp)) {
+		rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_AVAIL]);
+		return create_err_response(NULL, 501, "MDCX", p->trans);
+	}
+
 	/* Prohibit wildcarded requests */
 	if (endp->wildcarded_req) {
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
@@ -1224,6 +1233,11 @@
 	LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 		 "DLCX: deleting connection ...\n");
 
+	if (!mgcp_endp_avail(endp)) {
+		rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_FAIL_AVAIL]);
+		return create_err_response(NULL, 501, "DLCX", p->trans);
+	}
+
 	/* Prohibit wildcarded requests */
 	if (endp->wildcarded_req) {
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
diff --git a/src/libosmo-mgcp/mgcp_ratectr.c b/src/libosmo-mgcp/mgcp_ratectr.c
index 302786f..52fbf6e 100644
--- a/src/libosmo-mgcp/mgcp_ratectr.c
+++ b/src/libosmo-mgcp/mgcp_ratectr.c
@@ -63,6 +63,7 @@
 	[MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS] = { "crcx:conn_opt", "connection options invalid." },
 	[MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = { "crcx:codec_nego", "codec negotiation failure." },
 	[MGCP_CRCX_FAIL_BIND_PORT] = { "crcx:bind_port", "port bind failure." },
+	[MGCP_CRCX_FAIL_AVAIL] = { "crcx:availability", "endpoint unavailable." },
 };
 
 const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
@@ -90,6 +91,7 @@
 	[MGCP_MDCX_FAIL_START_RTP] = { "mdcx:start_rtp_failure", "failure to start RTP processing." },
 	[MGCP_MDCX_FAIL_REJECTED_BY_POLICY] = { "mdcx:conn_rejected", "connection rejected by policy." },
 	[MGCP_MDCX_DEFERRED_BY_POLICY] = { "mdcx:conn_deferred", "connection deferred by policy." },
+	[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:availability", "endpoint unavailable." },
 };
 
 const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
@@ -111,6 +113,7 @@
 	[MGCP_DLCX_FAIL_UNHANDLED_PARAM] = { "dlcx:unhandled_param", "unhandled parameter in DLCX command." },
 	[MGCP_DLCX_FAIL_REJECTED_BY_POLICY] = { "dlcx:rejected", "connection deletion rejected by policy." },
 	[MGCP_DLCX_DEFERRED_BY_POLICY] = { "dlcx:deferred", "connection deletion deferred by policy." },
+	[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:availability", "endpoint unavailable." },
 };
 
 const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
diff --git a/src/libosmo-mgcp/mgcp_vty.c b/src/libosmo-mgcp/mgcp_vty.c
index 938eef5..cbff700 100644
--- a/src/libosmo-mgcp/mgcp_vty.c
+++ b/src/libosmo-mgcp/mgcp_vty.c
@@ -199,6 +199,8 @@
 
 	vty_out(vty, "%s trunk %d endpoint %s:%s",
 		trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1", trunk_nr, endp->name, VTY_NEWLINE);
+	vty_out(vty, "   Availability: %s%s",
+		mgcp_endp_avail(endp) ? "available" : "not in service", VTY_NEWLINE);
 
 	if (llist_empty(&endp->conns)) {
 		vty_out(vty, "   No active connections%s", VTY_NEWLINE);

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-mgw/+/18898
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-mgw
Gerrit-Branch: master
Gerrit-Change-Id: I18e90b10648a7e504371179ad144645fc82e1c27
Gerrit-Change-Number: 18898
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200618/16b8d03c/attachment.htm>


More information about the gerrit-log mailing list