Change in libosmocore[master]: gprs_ns2: implement BLOCK/UNBLOCK of a NSVC by vty

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/.

laforge gerrit-no-reply at lists.osmocom.org
Wed Jan 20 14:06:51 UTC 2021


laforge has submitted this change. ( https://gerrit.osmocom.org/c/libosmocore/+/22210 )

Change subject: gprs_ns2: implement BLOCK/UNBLOCK of a NSVC by vty
......................................................................

gprs_ns2: implement BLOCK/UNBLOCK of a NSVC by vty

The vty should be able to block or unblock a specific NSVC.
Further more this case is special for the UNITDATA as those
can be still received until the other side response to the BLOCK PDU.

Related: OS#4939
Change-Id: Ic0ce3c5fabc8644cc1ee71a8f6dd783fadf7b84d
---
M src/gb/gprs_ns2_internal.h
M src/gb/gprs_ns2_vc_fsm.c
M src/gb/gprs_ns2_vty2.c
M tests/gb/gprs_ns2_test.c
M tests/gb/gprs_ns2_test.ok
5 files changed, 206 insertions(+), 8 deletions(-)

Approvals:
  Jenkins Builder: Verified
  pespin: Looks good to me, but someone else must approve
  daniel: Looks good to me, but someone else must approve
  laforge: Looks good to me, approved



diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h
index 5404ed3..cb5c2bd 100644
--- a/src/gb/gprs_ns2_internal.h
+++ b/src/gb/gprs_ns2_internal.h
@@ -318,6 +318,8 @@
 int gprs_ns2_vc_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp);
 int gprs_ns2_vc_is_alive(struct gprs_ns2_vc *nsvc);
 int gprs_ns2_vc_is_unblocked(struct gprs_ns2_vc *nsvc);
+int ns2_vc_block(struct gprs_ns2_vc *nsvc);
+int ns2_vc_unblock(struct gprs_ns2_vc *nsvc);
 
 /* nse */
 void ns2_nse_notify_unblocked(struct gprs_ns2_vc *nsvc, bool unblocked);
diff --git a/src/gb/gprs_ns2_vc_fsm.c b/src/gb/gprs_ns2_vc_fsm.c
index 641fcc3..8604bbe 100644
--- a/src/gb/gprs_ns2_vc_fsm.c
+++ b/src/gb/gprs_ns2_vc_fsm.c
@@ -59,6 +59,10 @@
 	 * It can change during runtime. The side which blocks an unblocked side.*/
 	bool initiate_block;
 	bool initiate_reset;
+	/* if blocked by O&M/vty */
+	bool om_blocked;
+	/* if unitdata is forwarded to the user */
+	bool accept_unitdata;
 
 	/* the alive counter is present in all states */
 	struct {
@@ -111,7 +115,9 @@
 
 	GPRS_NS2_EV_UNITDATA,
 
-	GPRS_NS2_EV_FORCE_UNCONFIGURED, /* called via vty for tests */
+	GPRS_NS2_EV_FORCE_UNCONFIGURED,	/* called via vty for tests */
+	GPRS_NS2_EV_REQ_OM_BLOCK,	/* vty cmd: block */
+	GPRS_NS2_EV_REQ_OM_UNBLOCK,	/* vty cmd: unblock*/
 };
 
 static const struct value_string gprs_ns2_vc_event_names[] = {
@@ -127,6 +133,8 @@
 	{ GPRS_NS2_EV_STATUS,			"STATUS" },
 	{ GPRS_NS2_EV_UNITDATA,			"UNITDATA" },
 	{ GPRS_NS2_EV_FORCE_UNCONFIGURED,	"FORCE_UNCONFIGURED" },
+	{ GPRS_NS2_EV_REQ_OM_BLOCK,		"REQ-O&M-BLOCK"},
+	{ GPRS_NS2_EV_REQ_OM_UNBLOCK,		"REQ-O&M-UNBLOCK"},
 	{ 0, NULL }
 };
 
@@ -245,6 +253,7 @@
 	if (old_state != GPRS_NS2_ST_RESET)
 		priv->N = 0;
 
+	priv->accept_unitdata = false;
 	if (priv->initiate_reset)
 		ns2_tx_reset(priv->nsvc, NS_CAUSE_OM_INTERVENTION);
 
@@ -283,8 +292,16 @@
 	if (old_state != GPRS_NS2_ST_BLOCKED)
 		priv->N = 0;
 
-	if (priv->initiate_block)
+	if (priv->om_blocked) {
+		/* we are already blocked after a RESET */
+		if (old_state == GPRS_NS2_ST_RESET) {
+			osmo_timer_del(&fi->timer);
+		} else {
+			ns2_tx_block(priv->nsvc, NS_CAUSE_OM_INTERVENTION);
+		}
+	} else if (priv->initiate_block) {
 		ns2_tx_unblock(priv->nsvc);
+	}
 
 	start_test_procedure(priv);
 }
@@ -293,7 +310,24 @@
 {
 	struct gprs_ns2_vc_priv *priv = fi->priv;
 
-	if (priv->initiate_block) {
+	if (priv->om_blocked) {
+		switch (event) {
+		case GPRS_NS2_EV_BLOCK_ACK:
+			priv->accept_unitdata = false;
+			osmo_timer_del(&fi->timer);
+			break;
+		case GPRS_NS2_EV_BLOCK:
+			priv->accept_unitdata = false;
+			ns2_tx_block_ack(priv->nsvc);
+			osmo_timer_del(&fi->timer);
+			break;
+		case GPRS_NS2_EV_UNBLOCK:
+			priv->accept_unitdata = false;
+			ns2_tx_block(priv->nsvc, NS_CAUSE_OM_INTERVENTION);
+			osmo_timer_add(&fi->timer);
+			break;
+		}
+	} else if (priv->initiate_block) {
 		switch (event) {
 		case GPRS_NS2_EV_BLOCK:
 			/* TODO: BLOCK is a UNBLOCK_NACK */
@@ -303,6 +337,7 @@
 			ns2_tx_unblock_ack(priv->nsvc);
 			/* fall through */
 		case GPRS_NS2_EV_UNBLOCK_ACK:
+			priv->accept_unitdata = true;
 			osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_UNBLOCKED,
 						0, NS_TOUT_TNS_TEST);
 			break;
@@ -325,6 +360,7 @@
 	struct gprs_ns2_vc *nsvc = priv->nsvc;
 	struct gprs_ns2_nse *nse = nsvc->nse;
 
+	priv->accept_unitdata = true;
 	ns2_nse_notify_unblocked(nsvc, true);
 	ns2_prim_status_ind(nse, nsvc, 0, NS_AFF_CAUSE_VC_RECOVERY);
 }
@@ -446,10 +482,19 @@
 	case GPRS_NS2_ST_BLOCKED:
 		if (priv->initiate_block) {
 			priv->N++;
-			if (priv->N <= nsi->timeout[NS_TOUT_TNS_BLOCK_RETRIES]) {
-				osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_BLOCKED, nsi->timeout[NS_TOUT_TNS_BLOCK], 0);
+			if (priv->om_blocked) {
+				if (priv->N <= nsi->timeout[NS_TOUT_TNS_BLOCK_RETRIES]) {
+					osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_BLOCKED, nsi->timeout[NS_TOUT_TNS_BLOCK], 0);
+				} else {
+					/* 7.2 stop accepting data when BLOCK PDU not responded */
+					priv->accept_unitdata = false;
+				}
 			} else {
-				osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_RESET, nsi->timeout[NS_TOUT_TNS_RESET], 0);
+				if (priv->N <= nsi->timeout[NS_TOUT_TNS_BLOCK_RETRIES]) {
+					osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_BLOCKED, nsi->timeout[NS_TOUT_TNS_BLOCK], 0);
+				} else {
+					osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_RESET, nsi->timeout[NS_TOUT_TNS_RESET], 0);
+				}
 			}
 		}
 		break;
@@ -550,7 +595,7 @@
 		switch (fi->state) {
 		case GPRS_NS2_ST_BLOCKED:
 			/* 7.2.1: the BLOCKED_ACK might be lost */
-			if (priv->initiate_block) {
+			if (priv->accept_unitdata) {
 				gprs_ns2_recv_unitdata(fi, msg);
 				return;
 			}
@@ -576,6 +621,20 @@
 			return;
 		}
 		break;
+	case GPRS_NS2_EV_REQ_OM_BLOCK:
+		/* vty cmd: block */
+		priv->initiate_block = true;
+		priv->om_blocked = true;
+		osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_BLOCKED, nsi->timeout[NS_TOUT_TNS_BLOCK], 0);
+		break;
+	case GPRS_NS2_EV_REQ_OM_UNBLOCK:
+		/* vty cmd: unblock*/
+		if (!priv->om_blocked)
+			return;
+		priv->om_blocked = false;
+		if (fi->state == GPRS_NS2_ST_BLOCKED)
+			osmo_fsm_inst_state_chg(fi, GPRS_NS2_ST_BLOCKED, nsi->timeout[NS_TOUT_TNS_BLOCK], 0);
+		break;
 	}
 }
 
@@ -595,7 +654,9 @@
 			       S(GPRS_NS2_EV_RESET) |
 			       S(GPRS_NS2_EV_ALIVE) |
 			       S(GPRS_NS2_EV_ALIVE_ACK) |
-			       S(GPRS_NS2_EV_FORCE_UNCONFIGURED),
+			       S(GPRS_NS2_EV_FORCE_UNCONFIGURED) |
+			       S(GPRS_NS2_EV_REQ_OM_BLOCK) |
+			       S(GPRS_NS2_EV_REQ_OM_UNBLOCK),
 	.allstate_action = gprs_ns2_vc_fsm_allstate_action,
 	.cleanup = gprs_ns2_vc_fsm_clean,
 	.timer_cb = gprs_ns2_vc_fsm_timer_cb,
@@ -653,6 +714,22 @@
 	return osmo_fsm_inst_dispatch(nsvc->fi, GPRS_NS2_EV_FORCE_UNCONFIGURED, NULL);
 }
 
+/*! Block a NS-VC.
+ *  \param nsvc the virtual circuit
+ *  \return 0 on success; negative on error */
+int ns2_vc_block(struct gprs_ns2_vc *nsvc)
+{
+	return osmo_fsm_inst_dispatch(nsvc->fi, GPRS_NS2_EV_REQ_OM_BLOCK, NULL);
+}
+
+/*! Unblock a NS-VC.
+ *  \param nsvc the virtual circuit
+ *  \return 0 on success; negative on error */
+int ns2_vc_unblock(struct gprs_ns2_vc *nsvc)
+{
+	return osmo_fsm_inst_dispatch(nsvc->fi, GPRS_NS2_EV_REQ_OM_UNBLOCK, NULL);
+}
+
 /*! entry point for messages from the driver/VL
  *  \param nsvc virtual circuit on which the message was received
  *  \param msg message that was received
diff --git a/src/gb/gprs_ns2_vty2.c b/src/gb/gprs_ns2_vty2.c
index 5af8fbc..94302ef 100644
--- a/src/gb/gprs_ns2_vty2.c
+++ b/src/gb/gprs_ns2_vty2.c
@@ -1503,6 +1503,33 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(nsvc_block, nsvc_block_cmd,
+      "nsvc <0-65535> (block|unblock)",
+      "NS Virtual Connection\n"
+      NSVCI_STR
+      "Block a NSVC. As cause code O&M intervention will be used.\n"
+      "Unblock a NSVC. As cause code O&M intervention will be used.\n")
+{
+	struct gprs_ns2_inst *nsi = vty_nsi;
+	struct gprs_ns2_vc *nsvc;
+
+	uint16_t id = atoi(argv[0]);
+
+	nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
+	if (!nsvc) {
+		vty_out(vty, "Could not find NSVCI %05u%s", id, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (!strcmp(argv[1], "block")) {
+		ns2_vc_block(nsvc);
+	} else {
+		ns2_vc_unblock(nsvc);
+	}
+
+	return CMD_SUCCESS;
+}
+
 static void log_set_nse_filter(struct log_target *target,
 				struct gprs_ns2_nse *nse)
 {
@@ -1608,6 +1635,7 @@
 	install_lib_element_ve(&logging_fltr_nsvc_cmd);
 
 	install_lib_element(ENABLE_NODE, &nsvc_force_unconf_cmd);
+	install_lib_element(ENABLE_NODE, &nsvc_block_cmd);
 
 	install_lib_element(CFG_LOG_NODE, &logging_fltr_nse_cmd);
 	install_lib_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);
diff --git a/tests/gb/gprs_ns2_test.c b/tests/gb/gprs_ns2_test.c
index bcfd460..315a4d0 100644
--- a/tests/gb/gprs_ns2_test.c
+++ b/tests/gb/gprs_ns2_test.c
@@ -20,6 +20,7 @@
 
 #include <osmocom/core/fsm.h>
 #include <osmocom/core/msgb.h>
+#include <osmocom/core/utils.h>
 #include <osmocom/core/application.h>
 #include <osmocom/core/utils.h>
 #include <osmocom/core/logging.h>
@@ -44,6 +45,34 @@
 	return 0;
 }
 
+static struct msgb *get_pdu(struct gprs_ns2_vc_bind *bind, enum ns_pdu_type pdu_type)
+{
+	struct gprs_ns_hdr *nsh;
+	struct osmo_wqueue *queue = bind->priv;
+
+	while (!llist_empty(&queue->msg_queue)) {
+		struct msgb *msg = msgb_dequeue(&queue->msg_queue);
+		nsh = (struct gprs_ns_hdr *) msg->l2h;
+		if (nsh->pdu_type == pdu_type)
+			return msg;
+		msgb_free(msg);
+	}
+
+	return NULL;
+}
+
+static bool find_pdu(struct gprs_ns2_vc_bind *bind, enum ns_pdu_type pdu_type)
+{
+	struct msgb *msg;
+	msg = get_pdu(bind, pdu_type);
+	if (msg) {
+		msgb_free(msg);
+		return true;
+	}
+
+	return false;
+}
+
 static void clear_pdus(struct gprs_ns2_vc_bind *bind)
 {
 	struct osmo_wqueue *queue = bind->priv;
@@ -147,6 +176,62 @@
 
 }
 
+/* setup NSE with 2x NSVCs.
+ * block 1x NSVC
+ * unblock 1x NSVC*/
+void test_block_unblock_nsvc(void *ctx)
+{
+	struct gprs_ns2_inst *nsi;
+	struct gprs_ns2_vc_bind *bind[2];
+	struct gprs_ns2_nse *nse;
+	struct gprs_ns2_vc *nsvc[2];
+	struct gprs_ns_hdr *nsh;
+	struct msgb *msg;
+	char idbuf[32];
+
+	printf("--- Testing NSE block unblock nsvc\n");
+	printf("---- Create NSE + Binds\n");
+	nsi = gprs_ns2_instantiate(ctx, ns_prim_cb, NULL);
+	bind[0] = dummy_bind(nsi, "bblock1");
+	bind[1] = dummy_bind(nsi, "bblock2");
+	nse = gprs_ns2_create_nse(nsi, 1001, GPRS_NS2_LL_UDP, NS2_DIALECT_STATIC_RESETBLOCK);
+	OSMO_ASSERT(nse);
+
+	for (int i=0; i<2; i++) {
+		printf("---- Create NSVC[i]\n");
+		snprintf(idbuf, sizeof(idbuf), "NSE%05u-dummy-%i", nse->nsei, i);
+		nsvc[i] = ns2_vc_alloc(bind[i], nse, false, NS2_VC_MODE_BLOCKRESET, idbuf);
+		OSMO_ASSERT(nsvc[i]);
+		nsvc[i]->fi->state = 3;	/* HACK: 3 = GPRS_NS2_ST_UNBLOCKED */
+		/* ensure the fi->state works correct */
+		OSMO_ASSERT(gprs_ns2_vc_is_unblocked(nsvc[i]));
+		ns2_nse_notify_unblocked(nsvc[i], true);
+	}
+
+	/* both nsvcs are unblocked and alive. Let's block it. */
+	OSMO_ASSERT(!find_pdu(bind[0], NS_PDUT_BLOCK));
+	clear_pdus(bind[0]);
+	ns2_vc_block(nsvc[0]);
+	OSMO_ASSERT(find_pdu(bind[0], NS_PDUT_BLOCK));
+	/* state == BLOCKED */
+	clear_pdus(bind[0]);
+
+	/* now unblocking it */
+	ns2_vc_unblock(nsvc[0]);
+	OSMO_ASSERT(find_pdu(bind[0], NS_PDUT_UNBLOCK));
+	clear_pdus(bind[0]);
+
+	msg = msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM, "test_unblock");
+	msg->l2h = msgb_put(msg, sizeof(*nsh));
+	nsh = (struct gprs_ns_hdr *) msg->l2h;
+	nsh->pdu_type = NS_PDUT_UNBLOCK_ACK;
+	ns2_recv_vc(nsvc[0], msg);
+
+	OSMO_ASSERT(gprs_ns2_vc_is_unblocked(nsvc[0]));
+	gprs_ns2_free(nsi);
+	printf("--- Finish NSE block unblock nsvc\n");
+}
+
 int main(int argc, char **argv)
 {
 	void *ctx = talloc_named_const(NULL, 0, "gprs_ns2_test");
@@ -159,6 +244,7 @@
 
 	printf("===== NS2 protocol test START\n");
 	test_nse_transfer_cap(ctx);
+	test_block_unblock_nsvc(ctx);
 	printf("===== NS2 protocol test END\n\n");
 
 	talloc_free(ctx);
diff --git a/tests/gb/gprs_ns2_test.ok b/tests/gb/gprs_ns2_test.ok
index 62bbbfe..27c72fa 100644
--- a/tests/gb/gprs_ns2_test.ok
+++ b/tests/gb/gprs_ns2_test.ok
@@ -6,5 +6,10 @@
 ---- Test with NSVC[2]
 ---- Test with NSVC[1] removed
 --- Finish NSE transfer cap
+--- Testing NSE block unblock nsvc
+---- Create NSE + Binds
+---- Create NSVC[i]
+---- Create NSVC[i]
+--- Finish NSE block unblock nsvc
 ===== NS2 protocol test END
 

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

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: Ic0ce3c5fabc8644cc1ee71a8f6dd783fadf7b84d
Gerrit-Change-Number: 22210
Gerrit-PatchSet: 17
Gerrit-Owner: lynxis lazus <lynxis at fe80.eu>
Gerrit-Assignee: daniel <dwillmann at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann at sysmocom.de>
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: pespin <pespin at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210120/a7239657/attachment.htm>


More information about the gerrit-log mailing list