From e393c1f7c660aac76ee2f33f86a452edcbc57441 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 17 Jan 2021 22:04:36 +0100 Subject: NS_Emulation: Respect data_weight==0 or signalling_weight==0 * allow configuration of signalling + data weight for each NS-VC * advertise per-NSVC signalling/data weight in SNS-CONFIG * keep track of unblocked NS-VCS separately for data / signalling * transmit BVCI=0 traffic only over signalling NS-VC * transmit BVCI>0 traffic only over data NS-VC * accept incoming BVCI=0 traffic only if signalling_weight > 0 * accept incoming BVCI>0 traffic only if data_weight > 0 Related: OS#4953 Change-Id: I9798e639b4bc8658482945970775b012b5840779 --- gbproxy/GBProxy_Tests.ttcn | 21 ++++++-- library/NS_Emulation.ttcnpp | 113 +++++++++++++++++++++++++++++++++++------- library/Osmocom_Gb_Types.ttcn | 10 ++++ pcu/PCU_Tests.cfg | 14 ++++-- pcu/PCU_Tests_SNS.cfg | 12 +++-- pcu/PCU_Tests_SNSv6.cfg | 2 + sgsn/SGSN_Tests.ttcn | 12 +++-- 7 files changed, 152 insertions(+), 32 deletions(-) diff --git a/gbproxy/GBProxy_Tests.ttcn b/gbproxy/GBProxy_Tests.ttcn index 013dc93c..39d7432f 100644 --- a/gbproxy/GBProxy_Tests.ttcn +++ b/gbproxy/GBProxy_Tests.ttcn @@ -67,11 +67,14 @@ modulepar { local_udp_port := 7777, local_ip := "127.0.0.10", remote_udp_port := 23000, - remote_ip := "127.0.0.1" + remote_ip := "127.0.0.1", + data_weight := 0, + signalling_weight := 1 } }, nsvci := 101 } + } }, { nsei := 102, @@ -85,7 +88,9 @@ modulepar { local_udp_port := 8888, local_ip := "127.0.0.11", remote_udp_port := 23000, - remote_ip := "127.0.0.1" + remote_ip := "127.0.0.1", + data_weight := 0, + signalling_weight := 1 } }, nsvci := 102 @@ -109,7 +114,9 @@ modulepar { local_udp_port := 21010, local_ip := "127.0.1.1", remote_udp_port := 23000, - remote_ip := "127.0.0.1" + remote_ip := "127.0.0.1", + data_weight := 1, + signalling_weight := 1 } }, nsvci := 2101 @@ -128,7 +135,9 @@ modulepar { local_udp_port := 21020, local_ip := "127.0.2.1", remote_udp_port := 23000, - remote_ip := "127.0.0.1" + remote_ip := "127.0.0.1", + data_weight := 1, + signalling_weight := 1 } }, nsvci := 2102 @@ -147,7 +156,9 @@ modulepar { local_udp_port := 21030, local_ip := "127.0.3.1", remote_udp_port := 23000, - remote_ip := "127.0.0.1" + remote_ip := "127.0.0.1", + data_weight := 1, + signalling_weight := 1 } }, nsvci := 2103 diff --git a/library/NS_Emulation.ttcnpp b/library/NS_Emulation.ttcnpp index 03aeb6aa..61ebe95b 100644 --- a/library/NS_Emulation.ttcnpp +++ b/library/NS_Emulation.ttcnpp @@ -1,5 +1,5 @@ /* GPRS-NS Emulation in TTCN-3 - * (C) 2018-2020 Harald Welte + * (C) 2018-2021 Harald Welte * contributions by sysmocom - s.f.m.c. GmbH * All rights reserved. * @@ -152,7 +152,9 @@ module NS_Emulation { PortNumber local_udp_port, charstring local_ip, PortNumber remote_udp_port, - charstring remote_ip + charstring remote_ip, + uint8_t data_weight, + uint8_t signalling_weight }; type record NSVCConfigurationFR { charstring netdev, /* HDLC net-device for AF_PACKET socket */ @@ -192,10 +194,11 @@ module NS_Emulation { /* references to the per-NSVC components */ var NsvcTable g_nsvcs := {}; /* list of indexes to g_nsvcs[] of currently unblocked NSVCs */ - var ro_integer g_unblocked_nsvcs := {}; + var ro_integer g_unblocked_nsvcs_sig := {}; + var ro_integer g_unblocked_nsvcs_data := {}; }; type record NsvcTableEntry { - Nsvci nsvci, + NSVCConfiguration cfg, NSVC_CT vc_conn, NsvcState state }; @@ -244,7 +247,7 @@ module NS_Emulation { var charstring nsvc_id := g_id & "-NSVCI" & int2str(nsvc_cfg.nsvci); var NsvcTableEntry te; - te.nsvci := nsvc_cfg.nsvci; + te.cfg := nsvc_cfg; te.vc_conn := NSVC_CT.create(nsvc_id); te.state := NSVC_S_DEAD_BLOCKED; @@ -258,7 +261,7 @@ module NS_Emulation { function f_nsvc_find_idx(Nsvci nsvci) runs on NS_CT return integer { var integer i; for (i := 0; i < lengthof(g_nsvcs); i := i+1) { - if (g_nsvcs[i].nsvci == nsvci) { + if (g_nsvcs[i].cfg.nsvci == nsvci) { return i; } } @@ -281,16 +284,32 @@ module NS_Emulation { } if (g_nsvcs[i].state != NSVC_S_ALIVE_UNBLOCKED and state == NSVC_S_ALIVE_UNBLOCKED) { /* add index to list of unblocked NSVCs */ - g_unblocked_nsvcs := g_unblocked_nsvcs & {i}; + if (not ischosen(g_nsvcs[i].cfg.provider.ip) or + g_nsvcs[i].cfg.provider.ip.signalling_weight > 0) { + g_unblocked_nsvcs_sig := g_unblocked_nsvcs_sig & {i}; + } + if (not ischosen(g_nsvcs[i].cfg.provider.ip) or + g_nsvcs[i].cfg.provider.ip.data_weight > 0) { + g_unblocked_nsvcs_data := g_unblocked_nsvcs_data & {i}; + } } else if (g_nsvcs[i].state == NSVC_S_ALIVE_UNBLOCKED and state != NSVC_S_ALIVE_UNBLOCKED) { /* remove index to list of unblocked NSVCs */ - var ro_integer new_unblocked_nsvcs := {}; - for (var integer j := 0; j < lengthof(g_unblocked_nsvcs); j := j+1) { - if (g_unblocked_nsvcs[j] != i) { - new_unblocked_nsvcs := new_unblocked_nsvcs & {j}; + var ro_integer new_unblocked_nsvcs_sig := {}; + for (var integer j := 0; j < lengthof(g_unblocked_nsvcs_sig); j := j+1) { + if (g_unblocked_nsvcs_sig[j] != i) { + new_unblocked_nsvcs_sig := new_unblocked_nsvcs_sig & {j}; + } + } + g_unblocked_nsvcs_sig := new_unblocked_nsvcs_sig; + + var ro_integer new_unblocked_nsvcs_data := {}; + for (var integer j := 0; j < lengthof(g_unblocked_nsvcs_data); j := j+1) { + if (g_unblocked_nsvcs_data[j] != i) { + new_unblocked_nsvcs_data := new_unblocked_nsvcs_data & {j}; } } - g_unblocked_nsvcs := new_unblocked_nsvcs; + g_unblocked_nsvcs_data := new_unblocked_nsvcs_data; + } g_nsvcs[i].state := state; } @@ -365,11 +384,17 @@ module NS_Emulation { log2str("Received UnitDataInd for invalid NSEI: ", rx_nsudi)); } /* from user down to NS-VC */ + [] NS_SP.receive(tr_NsUdReq(g_config.nsei, 0, ?, ?, *)) -> value rx_nsudr { + /* load distribution function */ + var integer nsvc_idx := g_unblocked_nsvcs_sig[rx_nsudr.lsp mod lengthof(g_unblocked_nsvcs_sig)]; + NSVC.send(rx_nsudr) to g_nsvcs[nsvc_idx].vc_conn; + } [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, ?, *)) -> value rx_nsudr { /* load distribution function */ - var integer nsvc_idx := g_unblocked_nsvcs[rx_nsudr.lsp mod lengthof(g_unblocked_nsvcs)]; + var integer nsvc_idx := g_unblocked_nsvcs_data[rx_nsudr.lsp mod lengthof(g_unblocked_nsvcs_data)]; NSVC.send(rx_nsudr) to g_nsvcs[nsvc_idx].vc_conn; } + [] NS_SP.receive(tr_NsUdReq(?, ?, ?, ?, *)) -> value rx_nsudr { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received NsUnitdataReq for invalid NSEI: ", rx_nsudr)); @@ -392,10 +417,14 @@ module NS_Emulation { } if (nsvc_cfg.provider.ip.address_family == AF_INET) { v4 := v4 & { valueof(ts_SNS_IPv4(nsvc_cfg.provider.ip.local_ip, - nsvc_cfg.provider.ip.local_udp_port)) }; + nsvc_cfg.provider.ip.local_udp_port, + nsvc_cfg.provider.ip.signalling_weight, + nsvc_cfg.provider.ip.data_weight)) }; } else if (nsvc_cfg.provider.ip.address_family == AF_INET6) { v6 := v6 & { valueof(ts_SNS_IPv6(nsvc_cfg.provider.ip.local_ip, - nsvc_cfg.provider.ip.local_udp_port)) }; + nsvc_cfg.provider.ip.local_udp_port, + nsvc_cfg.provider.ip.signalling_weight, + nsvc_cfg.provider.ip.data_weight)) }; } } @@ -690,18 +719,66 @@ module NS_Emulation { /* tolerate a late NS-UNBLOCK-ACK from peer */ [] NSCP.receive(t_NS_UNBLOCK_ACK) -> value rf { } + + [not ischosen(g_nsvc_config.provider.ip) or + g_nsvc_config.provider.ip.data_weight > 0] as_alive_unblocked_data(); + + [not ischosen(g_nsvc_config.provider.ip) or + g_nsvc_config.provider.ip.signalling_weight > 0] as_alive_unblocked_sig(); + + /* catch any violations of above rule */ + [ischosen(g_nsvc_config.provider.ip)] NSCP.receive(tr_NS_UNITDATA(?, ?, ?)) -> value rf { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("Unexpected Rx NS-UNITDATA on NSVC with data_weight=", + g_nsvc_config.provider.ip.data_weight, ", sig_weight=", + g_nsvc_config.provider.ip.signalling_weight, ": ", rf)); + } + [ischosen(g_nsvc_config.provider.ip)] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, *, *)) -> value ud_req { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("Unexpected Rx TX-UNITDATA on NSVC with data_weight=", + g_nsvc_config.provider.ip.data_weight, ", sig_weight=", + g_nsvc_config.provider.ip.signalling_weight, ": ", ud_req)); + } + } + + /* user data transfer; only permitted for some NS-VC */ + private altstep as_alive_unblocked_data() runs on NSVC_CT { + var NsUnitdataRequest ud_req; + var PDU_NS rf; + /* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */ + [] NSCP.receive(tr_NS_UNITDATA_User(?, ?)) -> value rf { + NS_SP.send(ts_NsUdInd(g_config.nsei, g_nsvc_config.nsvci, + oct2int(rf.pDU_NS_Unitdata.bVCI), + rf.pDU_NS_Unitdata.nS_SDU)); + } + /* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */ + [] NS_SP.receive(tr_NsUdReq(g_config.nsei, t_BssgpBvciUser, ?, ?, omit)) -> value ud_req { + /* using raw octetstring PDU */ + NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu)); + } + [] NS_SP.receive(tr_NsUdReq(g_config.nsei, t_BssgpBvciUser, ?, omit, ?)) -> value ud_req { + /* using decoded BSSGP PDU that we need to encode first */ + var octetstring enc := enc_PDU_BSSGP(ud_req.bssgp); + NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc)); + } + } + + /* signalling (BVCI=0) transfer; only permitted for some NS-VC */ + private altstep as_alive_unblocked_sig() runs on NSVC_CT { + var NsUnitdataRequest ud_req; + var PDU_NS rf; /* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */ - [] NSCP.receive(tr_NS_UNITDATA(?, ?, ?)) -> value rf { + [] NSCP.receive(tr_NS_UNITDATA(?, 0, ?)) -> value rf { NS_SP.send(ts_NsUdInd(g_config.nsei, g_nsvc_config.nsvci, oct2int(rf.pDU_NS_Unitdata.bVCI), rf.pDU_NS_Unitdata.nS_SDU)); } /* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */ - [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, ?, omit)) -> value ud_req { + [] NS_SP.receive(tr_NsUdReq(g_config.nsei, 0, ?, ?, omit)) -> value ud_req { /* using raw octetstring PDU */ NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu)); } - [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, omit, ?)) -> value ud_req { + [] NS_SP.receive(tr_NsUdReq(g_config.nsei, 0, ?, omit, ?)) -> value ud_req { /* using decoded BSSGP PDU that we need to encode first */ var octetstring enc := enc_PDU_BSSGP(ud_req.bssgp); NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc)); diff --git a/library/Osmocom_Gb_Types.ttcn b/library/Osmocom_Gb_Types.ttcn index 90650978..9e4d7029 100644 --- a/library/Osmocom_Gb_Types.ttcn +++ b/library/Osmocom_Gb_Types.ttcn @@ -14,6 +14,8 @@ module Osmocom_Gb_Types { type uint16_t Nsei; type uint16_t BssgpBvci; + template (present) BssgpBvci t_BssgpBvciUser := complement (0); + /* TS 48.016 10.3.7 */ type enumerated NsPduType { NS_PDUT_NS_UNITDATA ('00000000'B), @@ -407,6 +409,14 @@ octetstring sdu) := { nS_SDU := sdu } } + template PDU_NS tr_NS_UNITDATA_User(template NS_SDU_ControlBits bits, template octetstring sdu) := { + pDU_NS_Unitdata := { + nsPduType := '00'O, + nS_SDU_ControlBits := bits, + bVCI := complement ('0000'O), + nS_SDU := sdu + } + } diff --git a/pcu/PCU_Tests.cfg b/pcu/PCU_Tests.cfg index 13bedec9..dfebb40f 100644 --- a/pcu/PCU_Tests.cfg +++ b/pcu/PCU_Tests.cfg @@ -18,7 +18,9 @@ SGSN_Components.mp_nsconfig := { local_ip := "127.0.0.1", local_udp_port := 23000, remote_ip := "127.0.0.1", - remote_udp_port := 22000 + remote_udp_port := 22000, + data_weight := 1, + signalling_weight := 1 } }, nsvci := 1234 @@ -30,7 +32,10 @@ SGSN_Components.mp_nsconfig := { local_ip := "127.0.0.1", local_udp_port := 23001, remote_ip := "127.0.0.1", - remote_udp_port := 22000 + remote_udp_port := 22000, + data_weight := 1, + signalling_weight := 1 + } } }, nsvci := 1234 @@ -42,7 +47,10 @@ SGSN_Components.mp_nsconfig := { local_ip := "127.0.0.1", local_udp_port := 23002, remote_ip := "127.0.0.1", - remote_udp_port := 22000 + remote_udp_port := 22000, + data_weight := 1, + signalling_weight := 1 + } } }, nsvci := 1234 diff --git a/pcu/PCU_Tests_SNS.cfg b/pcu/PCU_Tests_SNS.cfg index ab589c53..c36edac7 100644 --- a/pcu/PCU_Tests_SNS.cfg +++ b/pcu/PCU_Tests_SNS.cfg @@ -17,7 +17,9 @@ SGSN_Components.mp_nsconfig := { local_ip := "127.0.0.1", local_udp_port := 23000, remote_ip := "127.0.0.1", - remote_udp_port := 22000 + remote_udp_port := 22000, + data_weight := 1, + signalling_weight := 1 } }, nsvci := 1234 @@ -29,7 +31,9 @@ SGSN_Components.mp_nsconfig := { local_ip := "127.0.0.1", local_udp_port := 23001, remote_ip := "127.0.0.1", - remote_udp_port := 22000 + remote_udp_port := 22000, + data_weight := 1, + signalling_weight := 1 } }, nsvci := 1234 @@ -41,7 +45,9 @@ SGSN_Components.mp_nsconfig := { local_ip := "127.0.0.1", local_udp_port := 23002, remote_ip := "127.0.0.1", - remote_udp_port := 22000 + remote_udp_port := 22000, + data_weight := 1, + signalling_weight := 1 } }, nsvci := 1234 diff --git a/pcu/PCU_Tests_SNSv6.cfg b/pcu/PCU_Tests_SNSv6.cfg index cae9a75f..3747f0a4 100644 --- a/pcu/PCU_Tests_SNSv6.cfg +++ b/pcu/PCU_Tests_SNSv6.cfg @@ -18,6 +18,8 @@ SGSN_Components.mp_nsconfig := { local_udp_port := 23000, remote_ip := "::1", remote_udp_port := 22000, + data_weight := 1, + signalling_weight := 1 } }, nsvci := 1234 diff --git a/sgsn/SGSN_Tests.ttcn b/sgsn/SGSN_Tests.ttcn index fe31ffcb..7d47a1ff 100644 --- a/sgsn/SGSN_Tests.ttcn +++ b/sgsn/SGSN_Tests.ttcn @@ -80,7 +80,9 @@ modulepar { local_udp_port := 21010, local_ip := "127.0.0.1", remote_udp_port := 23000, - remote_ip := "127.0.0.1" + remote_ip := "127.0.0.1", + data_weight := 1, + signalling_weight := 1 } }, nsvci := 97 @@ -99,7 +101,9 @@ modulepar { local_udp_port := 21011, local_ip := "127.0.0.1", remote_udp_port := 23000, - remote_ip := "127.0.0.1" + remote_ip := "127.0.0.1", + data_weight := 1, + signalling_weight := 1 } }, nsvci := 98 @@ -118,7 +122,9 @@ modulepar { local_udp_port := 21012, local_ip := "127.0.0.1", remote_udp_port := 23000, - remote_ip := "127.0.0.1" + remote_ip := "127.0.0.1", + data_weight := 1, + signalling_weight := 1 } }, nsvci := 99 -- cgit v1.2.3