Change in libosmocore[master]: WIP: ns2: Support "Foreign" SNS IP endpoints for fail-over scenarios

laforge gerrit-no-reply at lists.osmocom.org
Mon Mar 29 11:27:11 UTC 2021


laforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmocore/+/23521 )


Change subject: WIP: ns2: Support "Foreign" SNS IP endpoints for fail-over scenarios
......................................................................

WIP: ns2: Support "Foreign" SNS IP endpoints for fail-over scenarios

In fail-over scenarios, we want to be able to advertise "foreign"
IP endpoints, i.e. endpoints which do not have local sockets but
which are advertised as additional endpoints on "our" side of the
link.

This patch introduces support for them within pre-configured NSEs,
such as it is the case for the PCU/BSS role.

For the SGSN role, where typically we create the NSEs for BSS/PCU
dynamically as they create, another mechanism needs to be developed.

Change-Id: If9c4d3f62bfc2a47518dce90188e5fa85e21e4cc
Related: OS#4522
---
M include/osmocom/gprs/gprs_ns2.h
M src/gb/gprs_ns2_sns.c
M src/gb/gprs_ns2_vty.c
3 files changed, 234 insertions(+), 1 deletion(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/21/23521/1

diff --git a/include/osmocom/gprs/gprs_ns2.h b/include/osmocom/gprs/gprs_ns2.h
index be59a67..d58d537 100644
--- a/include/osmocom/gprs/gprs_ns2.h
+++ b/include/osmocom/gprs/gprs_ns2.h
@@ -233,6 +233,10 @@
 				   const struct osmo_sockaddr *saddr);
 int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse,
 				   const struct osmo_sockaddr *saddr);
+int gprs_ns2_sns_add_foreign_endpoint(struct gprs_ns2_nse *nse, const struct osmo_sockaddr *saddr,
+				      uint16_t sig_weight, uint16_t data_weight);
+int gprs_ns2_sns_del_foreign_endpoint(struct gprs_ns2_nse *nse,
+				      const struct osmo_sockaddr *saddr);
 int gprs_ns2_sns_add_bind(struct gprs_ns2_nse *nse, struct gprs_ns2_vc_bind *bind);
 int gprs_ns2_sns_del_bind(struct gprs_ns2_nse *nse, struct gprs_ns2_vc_bind *bind);
 const struct osmo_sockaddr *gprs_ns2_nse_sns_remote(struct gprs_ns2_nse *nse);
diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c
index 144ab21..3b2b938 100644
--- a/src/gb/gprs_ns2_sns.c
+++ b/src/gb/gprs_ns2_sns.c
@@ -117,6 +117,13 @@
 	struct osmo_sockaddr saddr;
 };
 
+struct sns_foreign_endpoint {
+	struct llist_head list;
+	struct osmo_sockaddr saddr;
+	uint16_t sig_weight;
+	uint16_t data_weight;
+};
+
 struct ns2_sns_bind {
 	struct llist_head list;
 	struct gprs_ns2_vc_bind *bind;
@@ -132,6 +139,8 @@
 	struct llist_head sns_endpoints;
 	/* list of used struct ns2_sns_bind  */
 	struct llist_head binds;
+	/* list of foreign local IP endpoints */
+	struct llist_head foreign_local_endpoints;
 	/* pointer to the bind which was used to initiate the SNS connection */
 	struct ns2_sns_bind *initial_bind;
 	/* prevent recursive reselection */
@@ -790,6 +799,7 @@
 	const struct osmo_sockaddr *remote;
 	const struct osmo_sockaddr *sa;
 	struct osmo_sockaddr local;
+	struct sns_foreign_endpoint *flep;
 	int count;
 
 	ns2_clear_ipv46_entries_local(gss);
@@ -803,7 +813,7 @@
 		remote = gprs_ns2_ip_vc_remote(gss->sns_nsvc);
 
 	/* count how many bindings are available (only UDP binds) */
-	count = llist_count(&gss->binds);
+	count = llist_count(&gss->binds) + llist_count(&gss->foreign_local_endpoints);
 	if (count == 0) {
 		LOGPFSML(fi, LOGL_ERROR, "No local binds for this NSE -> cannot determine IP endpoints\n");
 		return;
@@ -841,6 +851,19 @@
 			ip4_elems++;
 		}
 
+		llist_for_each_entry(flep, &gss->foreign_local_endpoints, list) {
+			sa = &flep->saddr;
+
+			if (sa->u.sas.ss_family != AF_INET)
+				continue;
+
+			ip4_elems->ip_addr = sa->u.sin.sin_addr.s_addr;
+			ip4_elems->udp_port = sa->u.sin.sin_port;
+			ip4_elems->sig_weight = flep->sig_weight;
+			ip4_elems->data_weight = flep->data_weight;
+			ip4_elems++;
+		}
+
 		gss->num_ip4_local = count;
 		gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip4_remote * gss->num_ip4_local, 8);
 		break;
@@ -877,6 +900,21 @@
 
 			ip6_elems++;
 		}
+
+		llist_for_each_entry(flep, &gss->foreign_local_endpoints, list) {
+			sa = &flep->saddr;
+
+			if (sa->u.sas.ss_family != AF_INET6)
+				continue;
+
+			ip6_elems->ip_addr = sa->u.sin6.sin6_addr;
+			ip6_elems->udp_port = sa->u.sin6.sin6_port;
+			ip6_elems->sig_weight = flep->sig_weight;
+			ip6_elems->data_weight = flep->data_weight;
+			ip6_elems++;
+		}
+
+
 		gss->num_ip6_local = count;
 		gss->num_max_nsvcs = OSMO_MAX(gss->num_max_ip6_remote * gss->num_ip6_local, 8);
 		break;
@@ -1735,6 +1773,7 @@
 	struct ns2_sns_state *gss;
 	struct osmo_sockaddr_str addr_str;
 	struct sns_endpoint *endpoint;
+	struct sns_foreign_endpoint *fendpoint;
 
 	if (!nse->bss_sns_fi)
 		return;
@@ -1746,6 +1785,13 @@
 			addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
 		vty_out(vty, "  ip-sns-remote %s %u%s", addr_str.ip, addr_str.port, VTY_NEWLINE);
 	}
+	llist_for_each_entry(fendpoint, &gss->foreign_local_endpoints, list) {
+		if (osmo_sockaddr_str_from_sockaddr(&addr_str, &fendpoint->saddr.u.sas) != 0)
+			addr_str = (struct osmo_sockaddr_str) { .ip = "<INVALID>" };
+		vty_out(vty, "  ip-sns-foreign %s %u signalling-weight %u data-weight %u%s",
+			addr_str.ip, addr_str.port, fendpoint->sig_weight, fendpoint->data_weight,
+			VTY_NEWLINE);
+	}
 }
 
 static struct sns_endpoint *ns2_get_sns_endpoint(struct ns2_sns_state *state,
@@ -1761,6 +1807,19 @@
 	return NULL;
 }
 
+static struct sns_foreign_endpoint *
+ns2_get_sns_foreign_endpoint(struct ns2_sns_state *state, const struct osmo_sockaddr *saddr)
+{
+	struct sns_foreign_endpoint *fendpoint;
+
+	llist_for_each_entry(fendpoint, &state->foreign_local_endpoints, list) {
+		if (!osmo_sockaddr_cmp(saddr, &fendpoint->saddr))
+			return fendpoint;
+	}
+
+	return NULL;
+}
+
 /*! gprs_ns2_sns_add_endpoint
  *  \param[in] nse
  *  \param[in] sockaddr
@@ -1855,6 +1914,77 @@
 	return 0;
 }
 
+/*! Add a foreign IP endpoint to the "local" side.
+ *  This is mostly useful in fail-over situations where the current "master"
+ *  node would want to advertise the IP endpoints of a current "slave" node
+ *  together with the truly local endpoints.
+ *
+ *  \param[in] nse NS entity to which the foreign EP shall be added
+ *  \param[in] sockaddr the socket address of the foreign EP
+ *  \return 0 on success; negative on error
+ */
+int gprs_ns2_sns_add_foreign_endpoint(struct gprs_ns2_nse *nse,
+				      const struct osmo_sockaddr *foreign,
+				      uint16_t sig_weight, uint16_t data_weight)
+{
+	struct ns2_sns_state *gss;
+	struct sns_foreign_endpoint *fendpoint;
+
+	if (nse->ll != GPRS_NS2_LL_UDP) {
+		return -EINVAL;
+	}
+
+	if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
+		return -EINVAL;
+	}
+
+	gss = nse->bss_sns_fi->priv;
+
+	if (ns2_get_sns_foreign_endpoint(gss, foreign))
+		return -EADDRINUSE;
+
+	fendpoint = talloc_zero(nse->bss_sns_fi->priv, struct sns_foreign_endpoint);
+	if (!fendpoint)
+		return -ENOMEM;
+
+	fendpoint->saddr = *foreign;
+	fendpoint->sig_weight = sig_weight;
+	fendpoint->data_weight = data_weight;
+	llist_add_tail(&fendpoint->list, &gss->foreign_local_endpoints);
+
+	return 0;
+}
+
+/*! Delete a foreign IP endpoint from the "local" side.
+ *  \param[in] nse NS entity from which the foreign EP shall be deleted
+ *  \param[in] sockaddr the socket address of the foreign EP
+ *  \return 0 on success, otherwise < 0
+ */
+int gprs_ns2_sns_del_foreign_endpoint(struct gprs_ns2_nse *nse,
+				      const struct osmo_sockaddr *foreign)
+{
+	struct ns2_sns_state *gss;
+	struct sns_foreign_endpoint *fendpoint;
+
+	if (nse->ll != GPRS_NS2_LL_UDP) {
+		return -EINVAL;
+	}
+
+	if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
+		return -EINVAL;
+	}
+
+	gss = nse->bss_sns_fi->priv;
+	fendpoint = ns2_get_sns_foreign_endpoint(gss, foreign);
+	if (!fendpoint)
+		return -ENOENT;
+
+	llist_del(&fendpoint->list);
+	talloc_free(fendpoint);
+
+	return 0;
+}
+
 /*! gprs_ns2_sns_count
  *  \param[in] nse NS Entity whose IP-SNS endpoints shall be printed
  *  \return the count of endpoints or < 0 if NSE doesn't contain sns.
@@ -2280,6 +2410,7 @@
 	gss->nse = nse;
 	gss->role = GPRS_SNS_ROLE_SGSN;
 	INIT_LLIST_HEAD(&gss->sns_endpoints);
+	INIT_LLIST_HEAD(&gss->foreign_local_endpoints);
 	INIT_LLIST_HEAD(&gss->binds);
 
 	return fi;
diff --git a/src/gb/gprs_ns2_vty.c b/src/gb/gprs_ns2_vty.c
index fc060ae..6eea00d 100644
--- a/src/gb/gprs_ns2_vty.c
+++ b/src/gb/gprs_ns2_vty.c
@@ -1473,6 +1473,102 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_ns_nse_ip_sns_foreign, cfg_ns_nse_ip_sns_foreign_cmd,
+      "ip-sns-foreign " VTY_IPV46_CMD " <1-65535> signalling-weight <0-254> data-weight <0-254>",
+      "SNS Foreign Local Endpoint (for fail-over)\n"
+      "PCU Foreign IPv4 Address\n" "PCU Foreign IPv6 Address\n"
+      "PCU Foreign UDP Port\n"
+      "signalling weight used by IP-SNS dynamic configuration\n"
+      "signalling weight used by IP-SNS dynamic configuration\n"
+      "data weight used by IP-SNS dynamic configuration\n"
+      "data weight used by IP-SNS dynamic configuration\n"
+      )
+{
+	struct gprs_ns2_nse *nse = vty->index;
+	int rc;
+
+	struct osmo_sockaddr_str foreign_str;
+	struct osmo_sockaddr foreign;
+	uint16_t port = atoi(argv[1]);
+
+	if (nse->ll != GPRS_NS2_LL_UDP) {
+		vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
+		goto err;
+	}
+
+	if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
+		vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
+		goto err;
+	}
+
+	if (osmo_sockaddr_str_from_str(&foreign_str, argv[0], port)) {
+		vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
+		goto err;
+	}
+
+	if (osmo_sockaddr_str_to_sockaddr(&foreign_str, &foreign.u.sas)) {
+		vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
+		goto err;
+	}
+
+	rc = gprs_ns2_sns_add_foreign_endpoint(nse, &foreign, atoi(argv[2]), atoi(argv[3]));
+	switch (rc) {
+	case 0:
+		return CMD_SUCCESS;
+	case -EADDRINUSE:
+		vty_out(vty, "Specified SNS endpoint already part of the NSE.%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	default:
+		vty_out(vty, "Can not add specified SNS endpoint.%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+err:
+	return CMD_WARNING;
+}
+
+DEFUN(cfg_no_ns_nse_ip_sns_foreign, cfg_no_ns_nse_ip_sns_foreign_cmd,
+      "no ip-sns-foreign " VTY_IPV46_CMD " <1-65535>",
+      NO_STR
+      "Delete a SNS Foreign Local Endpoint\n"
+      "PCU Foreign IPv4 Address\n" "PCU Foreign IPv6 Address\n"
+      "PCU Foreign UDP Port\n"
+      )
+{
+	struct gprs_ns2_nse *nse = vty->index;
+	struct osmo_sockaddr_str foreign_str; /* argv[0] */
+	struct osmo_sockaddr foreign;
+	uint16_t port = atoi(argv[1]);
+
+	if (nse->ll != GPRS_NS2_LL_UDP) {
+		vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
+		vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (osmo_sockaddr_str_from_str(&foreign_str, argv[0], port)) {
+		vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (osmo_sockaddr_str_to_sockaddr(&foreign_str, &foreign.u.sas)) {
+		vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (gprs_ns2_sns_del_foreign_endpoint(nse, &foreign)) {
+		vty_out(vty, "Can not remove specified foreign SNS endpoint.%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	return CMD_SUCCESS;
+}
+
+
 DEFUN(cfg_ns_nse_ip_sns_remote, cfg_ns_nse_ip_sns_remote_cmd,
       "ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
       "SNS Initial Endpoint\n"
@@ -2230,6 +2326,8 @@
 	install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_remote_cmd);
 	install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_bind_cmd);
 	install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_bind_cmd);
+	install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_foreign_cmd);
+	install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_foreign_cmd);
 
 	return 0;
 }

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

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: If9c4d3f62bfc2a47518dce90188e5fa85e21e4cc
Gerrit-Change-Number: 23521
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <laforge at osmocom.org>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210329/89d688f6/attachment.htm>


More information about the gerrit-log mailing list