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

Change subject: gprs_ns2: inform the NS user (BSSGP) about the MTU of a NSE
......................................................................

gprs_ns2: inform the NS user (BSSGP) about the MTU of a NSE

The BSSGP layer needs to know the MTU of the NS UNIDATA payload.
The MTU can be 0 if the NSE doesn't contain any NSVC.
Every status indication will contain the mtu value.
The MTU in the status indication contains the maximum transfer
unit of a BSSGP message. From NS side the maximum SDU.

Related: OS#4889
Change-Id: I5016b295db6185ec131d83089cf6c806e34ef1b6
---
M include/osmocom/gprs/frame_relay.h
M include/osmocom/gprs/gprs_ns2.h
M src/gb/gprs_ns2.c
M src/gb/gprs_ns2_fr.c
M src/gb/gprs_ns2_frgre.c
M src/gb/gprs_ns2_internal.h
M src/gb/gprs_ns2_udp.c
M tests/gb/gprs_ns2_test.c
M tests/gb/gprs_ns2_test.ok
9 files changed, 130 insertions(+), 4 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
  lynxis lazus: Looks good to me, approved



diff --git a/include/osmocom/gprs/frame_relay.h 
b/include/osmocom/gprs/frame_relay.h
index 1be37ee..e316707 100644
--- a/include/osmocom/gprs/frame_relay.h
+++ b/include/osmocom/gprs/frame_relay.h
@@ -39,6 +39,11 @@
        FR_ROLE_NETWORK_EQUIPMENT,
 };

+/* 48.016 ยง 6.1.4.2 default maximum information field size of 1600 octets */
+#define FRAME_RELAY_MTU 1600
+/* FR DLC header is 2 byte */
+#define FRAME_RELAY_SDU (FRAME_RELAY_MTU - 2)
+
 extern const struct value_string osmo_fr_role_names[];

 static inline const char *osmo_fr_role_str(enum osmo_fr_role role) {
diff --git a/include/osmocom/gprs/gprs_ns2.h b/include/osmocom/gprs/gprs_ns2.h
index 07e6c45..b406bb0 100644
--- a/include/osmocom/gprs/gprs_ns2.h
+++ b/include/osmocom/gprs/gprs_ns2.h
@@ -84,6 +84,7 @@
        GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED,
        GPRS_NS2_AFF_CAUSE_SNS_FAILURE,
        GPRS_NS2_AFF_CAUSE_SNS_NO_ENDPOINTS,
+       GPRS_NS2_AFF_CAUSE_MTU_CHANGE,
 };

 extern const struct value_string gprs_ns2_aff_cause_prim_strs[];
@@ -135,6 +136,8 @@
                        /* Only true on the first time it's available.
                         * Allow the BSSGP layer to reset persistent NSE */
                        bool first;
+                       /* MTU of a NS SDU. It's the lowest MTU of all (alive & 
dead) NSVCs */
+                       uint16_t mtu;
                } status;
        } u;
 };
diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c
index 99a7415..9302a16 100644
--- a/src/gb/gprs_ns2.c
+++ b/src/gb/gprs_ns2.c
@@ -217,6 +217,7 @@
        { GPRS_NS2_AFF_CAUSE_RECOVERY,          "NSE recovery" },
        { GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED,    "NSE SNS configured" },
        { GPRS_NS2_AFF_CAUSE_SNS_FAILURE,       "NSE SNS failure" },
+       { GPRS_NS2_AFF_CAUSE_MTU_CHANGE,        "NSE MTU changed" },
        { 0, NULL }
 };

@@ -496,15 +497,20 @@
        nsp.u.status.transfer = ns2_count_transfer_cap(nse, bvci);
        nsp.u.status.first = nse->first;
        nsp.u.status.persistent = nse->persistent;
+       if (nse->mtu < 4)
+               nsp.u.status.mtu = 0;
+       else
+               nsp.u.status.mtu = nse->mtu - 4; /* 1 Byte NS PDU type, 1 Byte 
NS SDU control, 2 Byte BVCI */
+
        if (nsvc) {
                nsp.u.status.nsvc = gprs_ns2_ll_str_buf(nsvc_str, 
sizeof(nsvc_str), nsvc);
-               LOGNSVC(nsvc, LOGL_NOTICE, "NS-STATUS.ind(bvci=%05u): cause=%s, 
transfer=%d, first=%d\n",
+               LOGNSVC(nsvc, LOGL_NOTICE, "NS-STATUS.ind(bvci=%05u): cause=%s, 
transfer=%d, first=%d, mtu=%d\n",
                        nsp.bvci, 
gprs_ns2_aff_cause_prim_str(nsp.u.status.cause),
-                       nsp.u.status.transfer, nsp.u.status.first);
+                       nsp.u.status.transfer, nsp.u.status.first, nse->mtu);
        } else {
-               LOGNSE(nse, LOGL_NOTICE, "NS-STATUS.ind(bvci=%05u): cause=%s, 
transfer=%d, first=%d\n",
+               LOGNSE(nse, LOGL_NOTICE, "NS-STATUS.ind(bvci=%05u): cause=%s, 
transfer=%d, first=%d, mtu=%d\n",
                        nsp.bvci, 
gprs_ns2_aff_cause_prim_str(nsp.u.status.cause),
-                       nsp.u.status.transfer, nsp.u.status.first);
+                       nsp.u.status.transfer, nsp.u.status.first, nse->mtu);
        }

        osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_STATUS, 
PRIM_OP_INDICATION, NULL);
@@ -548,6 +554,7 @@

        llist_add(&nsvc->list, &nse->nsvc);
        llist_add(&nsvc->blist, &bind->nsvc);
+       ns2_nse_update_mtu(nse);

        return nsvc;

@@ -746,6 +753,7 @@
        nse->nsei = nsei;
        nse->nsi = nsi;
        nse->first = true;
+       nse->mtu = 0;
        llist_add(&nse->list, &nsi->nse);
        INIT_LLIST_HEAD(&nse->nsvc);

@@ -1334,6 +1342,31 @@
        array[i] = bind;
 }

+void ns2_nse_update_mtu(struct gprs_ns2_nse *nse)
+{
+       struct gprs_ns2_vc *nsvc;
+       int mtu = 0;
+
+       if (llist_empty(&nse->nsvc)) {
+               nse->mtu = 0;
+               return;
+       }
+
+       llist_for_each_entry(nsvc, &nse->nsvc, list) {
+               if (mtu == 0)
+                       mtu = nsvc->bind->mtu;
+               else if (mtu > nsvc->bind->mtu)
+                       mtu = nsvc->bind->mtu;
+       }
+
+       if (nse->mtu == mtu)
+               return;
+
+       nse->mtu = mtu;
+       if (nse->alive)
+               ns2_prim_status_ind(nsvc->nse, NULL, 0, 
GPRS_NS2_AFF_CAUSE_MTU_CHANGE);
+}
+
 /*! calculate the transfer capabilities for a nse
  *  \param nse the nse to count the transfer capability
  *  \param bvci a bvci - unused
diff --git a/src/gb/gprs_ns2_fr.c b/src/gb/gprs_ns2_fr.c
index 7e6db2a..445f00a 100644
--- a/src/gb/gprs_ns2_fr.c
+++ b/src/gb/gprs_ns2_fr.c
@@ -801,6 +801,7 @@
        bind->send_vc = fr_vc_sendmsg;
        bind->free_vc = free_vc;
        bind->dump_vty = dump_vty;
+       bind->mtu = FRAME_RELAY_SDU;
        priv = bind->priv = talloc_zero(bind, struct priv_bind);
        if (!priv) {
                rc = -ENOMEM;
diff --git a/src/gb/gprs_ns2_frgre.c b/src/gb/gprs_ns2_frgre.c
index 177aeb2..62d87a4 100644
--- a/src/gb/gprs_ns2_frgre.c
+++ b/src/gb/gprs_ns2_frgre.c
@@ -572,6 +572,10 @@
        bind->send_vc = frgre_vc_sendmsg;
        bind->free_vc = free_vc;
        bind->nsi = nsi;
+       /* TODO: allow to set the MTU via vty. It can not be automatic detected 
because it goes over an
+        * ethernet device and the MTU here must match the FR side of the 
FR-to-GRE gateway.
+        */
+       bind->mtu = FRAME_RELAY_SDU;

        priv = bind->priv = talloc_zero(bind, struct priv_bind);
        if (!priv) {
diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h
index d4764f6..7e235be 100644
--- a/src/gb/gprs_ns2_internal.h
+++ b/src/gb/gprs_ns2_internal.h
@@ -179,6 +179,9 @@

        /*! sum of all the signalling weight of _alive_ NS-VCs */
        uint32_t sum_sig_weight;
+
+       /*! MTU of a NS PDU. This is the lowest MTU of all NSVCs */
+       uint16_t mtu;
 };

 /*! Structure representing a single NS-VC */
@@ -244,6 +247,9 @@
        /*! transfer capability in mbit */
        int transfer_capability;

+       /*! MTU of a NS PDU on this bind. */
+       uint16_t mtu;
+
        /*! which link-layer are we based on? */
        enum gprs_ns2_ll ll;

@@ -298,6 +304,7 @@
                         uint16_t bvci,
                         enum gprs_ns2_affecting_cause cause);
 void ns2_nse_notify_alive(struct gprs_ns2_vc *nsvc, bool alive);
+void ns2_nse_update_mtu(struct gprs_ns2_nse *nse);

 /* message */
 int ns2_validate(struct gprs_ns2_vc *nsvc,
diff --git a/src/gb/gprs_ns2_udp.c b/src/gb/gprs_ns2_udp.c
index 0f22458..36f6a97 100644
--- a/src/gb/gprs_ns2_udp.c
+++ b/src/gb/gprs_ns2_udp.c
@@ -368,6 +368,10 @@
                                dscp, rc, errno);
        }

+       /* IPv4: max fragmented payload can be (13 bit) * 8 byte => 65535.
+        * IPv6: max payload can be 65535 (RFC 2460).
+        * UDP header = 8 byte */
+       bind->mtu = 65535 - 8;
        if (result)
                *result = bind;

diff --git a/tests/gb/gprs_ns2_test.c b/tests/gb/gprs_ns2_test.c
index 2027e63..6d71a8c 100644
--- a/tests/gb/gprs_ns2_test.c
+++ b/tests/gb/gprs_ns2_test.c
@@ -40,10 +40,13 @@

 static struct log_info info = {};
 static struct osmo_wqueue *unitdata = NULL;
+static struct osmo_gprs_ns2_prim last_nse_recovery = {};

 static int ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
 {
+       struct osmo_gprs_ns2_prim *nsp;
        OSMO_ASSERT(oph->sap == SAP_NS);
+       nsp = container_of(oph, struct osmo_gprs_ns2_prim, oph);
        if (oph->msg) {
                if (oph->primitive == GPRS_NS2_PRIM_UNIT_DATA) {
                        osmo_wqueue_enqueue(unitdata, oph->msg);
@@ -51,6 +54,9 @@
                        msgb_free(oph->msg);
                }
        }
+       if (oph->primitive == GPRS_NS2_PRIM_STATUS && nsp->u.status.cause == 
GPRS_NS2_AFF_CAUSE_RECOVERY) {
+               last_nse_recovery = *nsp;
+       }
        return 0;
 }

@@ -113,6 +119,7 @@
        bind->transfer_capability = 42;
        bind->send_vc = vc_sendmsg;
        bind->priv = talloc_zero(bind, struct osmo_wqueue);
+       bind->mtu = 123;
        struct osmo_wqueue *queue = bind->priv;

        osmo_wqueue_init(queue, 100);
@@ -154,6 +161,7 @@
        bind->ll = GPRS_NS2_LL_UDP;
        bind->transfer_capability = 99;
        bind->send_vc = loopback_sendmsg;
+       bind->mtu = 123;
        return bind;
 }

@@ -362,6 +370,59 @@
        printf("--- Finish unitdata test\n");
 }

+void test_mtu(void *ctx)
+{
+       struct gprs_ns2_inst *nsi;
+       struct gprs_ns2_vc_bind *bind[2];
+       struct gprs_ns2_vc_bind *loopbind;
+       struct gprs_ns2_nse *nse;
+       struct gprs_ns2_vc *nsvc[2];
+       struct gprs_ns2_vc *loop[2];
+
+       struct msgb *msg, *other;
+       char idbuf[32];
+       int i;
+
+       printf("--- Testing mtu 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");
+       loopbind = loopback_bind(nsi, "loopback");
+       nse = gprs_ns2_create_nse(nsi, 1004, GPRS_NS2_LL_UDP, 
GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
+       OSMO_ASSERT(nse);
+
+       for (i=0; i<2; 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_BLOCKRESET, idbuf);
+               loop[i] = loopback_nsvc(loopbind, nsvc[i]);
+               OSMO_ASSERT(nsvc[i]);
+               ns2_vc_fsm_start(nsvc[i]);
+               OSMO_ASSERT(!ns2_vc_is_unblocked(nsvc[i]));
+               ns2_tx_reset(loop[i], NS_CAUSE_OM_INTERVENTION);
+               ns2_tx_unblock(loop[i]);
+               OSMO_ASSERT(ns2_vc_is_unblocked(nsvc[i]));
+       }
+
+       /* both nsvcs are unblocked and alive */
+       printf("---- Send a small UNITDATA to NSVC[0]\n");
+       msg = generate_unitdata("test_unitdata");
+       ns2_recv_vc(nsvc[0], msg);
+       other = msgb_dequeue(&unitdata->msg_queue);
+       OSMO_ASSERT(msg == other);
+       other = msgb_dequeue(&unitdata->msg_queue);
+       OSMO_ASSERT(NULL == other);
+       msgb_free(msg);
+
+       printf("---- Check if got mtu reported\n");
+       /* 1b NS PDU type, 1b NS SDU control, 2b BVCI */
+       OSMO_ASSERT(last_nse_recovery.u.status.mtu == 123 - 4);
+
+       gprs_ns2_free(nsi);
+       printf("--- Finish unitdata test\n");
+}

 int main(int argc, char **argv)
 {
@@ -379,6 +440,7 @@
        test_nse_transfer_cap(ctx);
        test_block_unblock_nsvc(ctx);
        test_unitdata(ctx);
+       test_mtu(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 7d12325..f40579f 100644
--- a/tests/gb/gprs_ns2_test.ok
+++ b/tests/gb/gprs_ns2_test.ok
@@ -20,5 +20,12 @@
 ---- Try to receive over blocked NSVC[0]
 ---- Receive over NSVC[1]
 --- Finish unitdata test
+--- Testing mtu test
+---- Create NSE + Binds
+---- Create NSVC[0]
+---- Create NSVC[1]
+---- Send a small UNITDATA to NSVC[0]
+---- Check if got mtu reported
+--- Finish unitdata test
 ===== NS2 protocol test END


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

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: I5016b295db6185ec131d83089cf6c806e34ef1b6
Gerrit-Change-Number: 22343
Gerrit-PatchSet: 13
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