lynxis lazus has submitted this change. ( 
https://gerrit.osmocom.org/c/libosmocore/+/22901 )

Change subject: gprs_ns2: implement a simple load sharing for UDP
......................................................................

gprs_ns2: implement a simple load sharing for UDP

Implement the load sharing based on modulo of the LSP. As long the gprs_ns2 
doesn't
support the resource distribution function (48.016 ยง 4.4a) this simple
approach is good enought.

Fixes: OS#4836
Change-Id: I8c2fe5d647694886ac600470fca6ea5d5d210a85
---
M src/gb/gprs_ns2.c
M tests/gb/gprs_ns2_test.c
M tests/gb/gprs_ns2_test.ok
3 files changed, 142 insertions(+), 1 deletion(-)

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



diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c
index bc4db53..e290734 100644
--- a/src/gb/gprs_ns2.c
+++ b/src/gb/gprs_ns2.c
@@ -384,6 +384,45 @@
        return NULL;
 }

+/* 4.4.2 Load Sharing function for the IP Sub-Network
+ *
+ * Implement a simple approach for UDP load sharing of data weight based on 
the modulo of the lsp.
+ *
+ * E.g. 3 NSVC: 1st weight 5, 2nd weight 3, 3rd weight 1, lsp = 3.
+ * sum all weights = 9
+ * target_weight = lsp % sum = 3
+ *
+ * 1st NSVC will be the target for 0-4
+ * 2nd NSVC will be the target for 5-7
+ * 3rd NSVC will be the target for 8
+ *
+ * The 1st NSVC will be used.
+ * E.g. lsp = 7. The 2nd NSVC will used.
+ */
+static struct gprs_ns2_vc *ns2_load_sharing_weight_modulo(
+               struct gprs_ns2_nse *nse,
+               uint16_t bvci,
+               uint32_t load_selector)
+{
+       struct gprs_ns2_vc *tmp;
+       uint32_t mod;
+       uint32_t i = 0;
+
+       if (nse->nsvc_count == 0)
+               return NULL;
+
+       mod = (bvci + load_selector) % nse->sum_data_weight;
+       llist_for_each_entry(tmp, &nse->nsvc, list) {
+               if (!ns2_vc_is_unblocked(tmp))
+                       continue;
+               if (i == mod || mod < i + tmp->data_weight)
+                       return tmp;
+               i += tmp->data_weight;
+       }
+
+       return NULL;
+}
+
 /* pick the first available data NSVC - no load sharing */
 struct gprs_ns2_vc *ns2_load_sharing_first(struct gprs_ns2_nse *nse)
 {
@@ -421,7 +460,7 @@
                        nsvc = ns2_load_sharing_signal(nse);
                } else {
                        /* data with load sharing parameter */
-                       nsvc = ns2_load_sharing_first(nse);
+                       nsvc = ns2_load_sharing_weight_modulo(nse, bvci, 
link_selector);
                }
                break;
        }
diff --git a/tests/gb/gprs_ns2_test.c b/tests/gb/gprs_ns2_test.c
index 6d71a8c..d8ed06f 100644
--- a/tests/gb/gprs_ns2_test.c
+++ b/tests/gb/gprs_ns2_test.c
@@ -60,6 +60,18 @@
        return 0;
 }

+static int gp_send_to_ns(struct gprs_ns2_inst *nsi, struct msgb *msg, uint16_t 
nsei, uint16_t bvci, uint32_t lsp)
+{
+       struct osmo_gprs_ns2_prim nsp = {};
+       nsp.nsei = nsei;
+       nsp.bvci = bvci;
+       nsp.u.unitdata.link_selector = lsp;
+       osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA,
+                       PRIM_OP_REQUEST, msg);
+       return gprs_ns2_recv_prim(nsi, &nsp.oph);
+}
+
+
 static struct msgb *get_pdu(struct gprs_ns2_vc_bind *bind, enum ns_pdu_type 
pdu_type)
 {
        struct gprs_ns_hdr *nsh;
@@ -88,6 +100,12 @@
        return false;
 }

+static unsigned int count_pdus(struct gprs_ns2_vc_bind *bind)
+{
+       struct osmo_wqueue *queue = bind->priv;
+       return llist_count(&queue->msg_queue);
+}
+
 static void clear_pdus(struct gprs_ns2_vc_bind *bind)
 {
        struct osmo_wqueue *queue = bind->priv;
@@ -370,6 +388,81 @@
        printf("--- Finish unitdata test\n");
 }

+void test_unitdata_weights(void *ctx)
+{
+       struct gprs_ns2_inst *nsi;
+       struct gprs_ns2_vc_bind *bind[3];
+       struct gprs_ns2_vc_bind *loopbind;
+       struct gprs_ns2_nse *nse;
+       struct gprs_ns2_vc *nsvc[3];
+       struct gprs_ns2_vc *loop[3];
+
+       struct msgb *msg, *other;
+       char idbuf[32];
+       int i;
+
+       printf("--- Testing unitdata weight test\n");
+       osmo_wqueue_clear(unitdata);
+       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");
+       bind[2] = dummy_bind(nsi, "bblock3");
+       loopbind = loopback_bind(nsi, "loopback");
+       nse = gprs_ns2_create_nse(nsi, 1004, GPRS_NS2_LL_UDP, 
GPRS_NS2_DIALECT_STATIC_ALIVE);
+       OSMO_ASSERT(nse);
+
+       /* data weights are
+        * nsvc[0] = 1
+        * nsvc[1] = 2
+        * nsvc[2] = 3
+        */
+       for (i = 0; i < 3; i++) {
+               printf("---- Create NSVC[%d]\n", i);
+               snprintf(idbuf, sizeof(idbuf), "NSE%05u-dummy-%i", nse->nsei, 
i);
+               nsvc[i] = ns2_vc_alloc(bind[i], nse, false, 
GPRS_NS2_VC_MODE_ALIVE, idbuf);
+               loop[i] = loopback_nsvc(loopbind, nsvc[i]);
+               OSMO_ASSERT(nsvc[i]);
+               nsvc[i]->data_weight = i + 1;
+               ns2_vc_fsm_start(nsvc[i]);
+               OSMO_ASSERT(!ns2_vc_is_unblocked(nsvc[i]));
+               ns2_tx_alive_ack(loop[i]);
+               OSMO_ASSERT(ns2_vc_is_unblocked(nsvc[i]));
+       }
+
+       /* all nsvcs are alive */
+       printf("---- Send UNITDATA to all NSVCs\n");
+       for (i = 0; i < 3; i++) {
+               msg = generate_unitdata("test_unitdata_weight");
+               ns2_recv_vc(nsvc[i], msg);
+               other = msgb_dequeue(&unitdata->msg_queue);
+               OSMO_ASSERT(msg == other);
+               other = msgb_dequeue(&unitdata->msg_queue);
+               OSMO_ASSERT(NULL == other);
+               msgb_free(msg);
+       }
+
+       /* nsvc[1] should be still good */
+       printf("---- Send BSSGP data to the NSE to test unitdata over 
NSVC[1]\n");
+       for (i = 0; i < 3; i++)
+               clear_pdus(bind[i]);
+
+       for (i = 0; i < 12; i++) {
+               msg = generate_unitdata("test_unitdata_weight2");
+               gp_send_to_ns(nsi, msg, 1004, 1, i + 1);
+       }
+
+       for (i = 0; i < 3; i++)
+               fprintf(stderr, "count_pdus(bind[%d]) = %d\n", i, 
count_pdus(bind[i]));
+
+       for (i = 0; i < 3; i++) {
+               OSMO_ASSERT(count_pdus(bind[i]) == nsvc[i]->data_weight * 2);
+       }
+
+       gprs_ns2_free(nsi);
+       printf("--- Finish unitdata weight test\n");
+}
+
 void test_mtu(void *ctx)
 {
        struct gprs_ns2_inst *nsi;
@@ -440,6 +533,7 @@
        test_nse_transfer_cap(ctx);
        test_block_unblock_nsvc(ctx);
        test_unitdata(ctx);
+       test_unitdata_weights(ctx);
        test_mtu(ctx);
        printf("===== NS2 protocol test END\n\n");

diff --git a/tests/gb/gprs_ns2_test.ok b/tests/gb/gprs_ns2_test.ok
index f40579f..40a1528 100644
--- a/tests/gb/gprs_ns2_test.ok
+++ b/tests/gb/gprs_ns2_test.ok
@@ -20,6 +20,14 @@
 ---- Try to receive over blocked NSVC[0]
 ---- Receive over NSVC[1]
 --- Finish unitdata test
+--- Testing unitdata weight test
+---- Create NSE + Binds
+---- Create NSVC[0]
+---- Create NSVC[1]
+---- Create NSVC[2]
+---- Send UNITDATA to all NSVCs
+---- Send BSSGP data to the NSE to test unitdata over NSVC[1]
+--- Finish unitdata weight test
 --- Testing mtu test
 ---- Create NSE + Binds
 ---- Create NSVC[0]

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

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: I8c2fe5d647694886ac600470fca6ea5d5d210a85
Gerrit-Change-Number: 22901
Gerrit-PatchSet: 12
Gerrit-Owner: lynxis lazus <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: lynxis lazus <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-MessageType: merged

Reply via email to