From c450552c597b4f570ad4f3aadeccd0bc140b8b13 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 11 Nov 2020 18:55:09 +0100 Subject: NS_Emulation: Introduce Load Sharing Function The Load Sharing Function distributes traffic among all unblocked NS-VC within a NS-VCG. The sharing is done based on a LSP (Link Selector Parameter) which is passed with the NS-UNITDATA.req primitive from BSSGP to NS. Details are implementation specific, but NS must ensure that all traffic of one LSP is always sent through the same NS-VC, as long as that NS-VC is alive/unblocked. We use the LSP as follows: * Signaling BVC always only uses lsp 0 * PTP BVC messages unrelated to user straffic use a per-BVC static LSP, which is the BVCI * User traffic can set whatever LSP it wants * NS keeps an array of NSVCs currently unblocked and uses the LSP modulo the array size as an index into it Change-Id: I8b960ec4d729f50cadca353bb52685311cd45eed Related: SYS#5084 --- library/BSSGP_Emulation.ttcnpp | 65 ++++++++++++++++++++++++------------------ library/NS_Emulation.ttcnpp | 39 +++++++++++++++++++------ 2 files changed, 68 insertions(+), 36 deletions(-) (limited to 'library') diff --git a/library/BSSGP_Emulation.ttcnpp b/library/BSSGP_Emulation.ttcnpp index 1370958d..cb0c82c4 100644 --- a/library/BSSGP_Emulation.ttcnpp +++ b/library/BSSGP_Emulation.ttcnpp @@ -274,14 +274,14 @@ altstep as_sig_wait_reset() runs on BSSGP_CT { /* Respond to RESET for signalling BVCI 0 */ [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, 0, omit), 0)) -> value udi { log("Rx BVC-RESET for Signaling BVCI=0"); - BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(0, omit), 0)); + BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(0, omit), 0, 0)); f_sign_change_state(BVC_S_UNBLOCKED); } /* work-around for old, buggy libosmogb before Change-Id Ie87820537d6d616da4fd4bbf73eab06e28fda5e1 */ [mp_tolerate_bvc_reset_cellid] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, 0, g_cfg.bvc[0].cell_id), 0)) -> value udi { log("Rx BVC-RESET for Signaling BVCI=0"); - BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(0, omit), 0)); + BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(0, omit), 0, 0)); f_sign_change_state(BVC_S_UNBLOCKED); } } @@ -301,7 +301,7 @@ altstep as_sig_unblocked() runs on BSSGP_CT { BVC.send(udi) to bvc_comp_ref; } else { setverdict(fail, "Rx BSSGP for unknown PTP BVCI ", udi.bvci, ": ", udi.bssgp); - BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(udi.bvci, BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp), udi.bvci)); + BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(udi.bvci, BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp), udi.bvci, 0)); } } @@ -324,7 +324,7 @@ altstep as_sig_unblocked() runs on BSSGP_CT { BVC.send(udi) to bvc_comp_ref; } else { setverdict(fail, "Rx SIG BSSGP for unknown PTP BVCI ", ptp_bvci, ": ", udi.bssgp); - BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(udi.bvci, BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp), 0)); + BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(udi.bvci, BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp), 0, 0)); } } } @@ -362,7 +362,7 @@ altstep as_sig_wait_ns_alive_unblocked() runs on BSSGP_CT { [] BSCP.receive(NsStatusIndication:{g_cfg.nsei,?, complement (NSVC_S_ALIVE_UNBLOCKED), NSVC_S_ALIVE_UNBLOCKED, true}) -> value nsi { /* if we just became NS-unblocked, send a BCC-RESET */ if (g_cfg.sgsn_role == false) { - BSCP.send(f_BnsUdReq(ts_BVC_RESET(BSSGP_CAUSE_OM_INTERVENTION, 0, omit), 0)); + BSCP.send(f_BnsUdReq(ts_BVC_RESET(BSSGP_CAUSE_OM_INTERVENTION, 0, omit), 0, 0)); g_T2.start; /* The BVC_RESET_ACK is handled in the as_sig_allstate() below */ } @@ -383,7 +383,7 @@ altstep as_sig_allstate() runs on BSSGP_CT { /* Respond to RESET for signalling BVCI 0 */ [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, 0, omit), 0)) -> value udi { log("Rx BVC-RESET for Signaling BVCI=0"); - BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(0, omit), 0)); + BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(0, omit), 0, 0)); for (var integer i := 0; i < sizeof(BvcTable); i := i+1) { if (isbound(BvcTable[i].comp_ref) and BvcTable[i].comp_ref != null) { BVC.send(BssgpResetIndication:{0}) to BvcTable[i].comp_ref; @@ -408,14 +408,14 @@ altstep as_sig_allstate() runs on BSSGP_CT { /* Respond to BLOCK for wrong BVCI */ [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(?, ?), 0)) -> value udi { setverdict(fail, "Rx BVC-BLOCK for unknown BVCI"); - BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(0, BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp), 0)); + BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(0, BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp), 0, 0)); } /* Respond to RESET with wrong BVCI */ [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, ?, ?), 0)) -> value udi { var BssgpBvci ptp_bvci := oct2int(udi.bssgp.pDU_BSSGP_BVC_RESET.bVCI.unstructured_value); setverdict(fail, "Rx BVC-RESET for unknown BVCI ", ptp_bvci); - BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(ptp_bvci, BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp), 0)); + BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(ptp_bvci, BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp), 0, 0)); } /* BVC-RESET-ACK for BVCI=0 while T2 is running: Answer to a BVC-RESET we sent earlier */ @@ -431,14 +431,14 @@ altstep as_sig_allstate() runs on BSSGP_CT { } [] g_T2.timeout { setverdict(fail, "Timeout waiting for BVC-RESET-ACK on BVCI=0"); - BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(udi.bvci, BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp), 0)); + BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(udi.bvci, BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp), 0, 0)); g_T2.start; } /* default case of handling unknown PDUs */ [] BSCP.receive(f_BnsUdInd(?, ?)) -> value udi { setverdict(fail, "Rx Unexpected BSSGP PDU ", udi.bssgp," in state ", g_sign_bvc_state); - BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(0, BSSGP_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, udi.bssgp), 0)); + BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(0, BSSGP_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, udi.bssgp), 0, 0)); } /* Forwarding of ASP_Event to per-BVC components */ @@ -531,11 +531,12 @@ private function f_bssgp_ScanEvents() runs on BSSGP_CT { } /* generate a send template. Cannot be a real template as we want to use g_cfg.nsei */ -private function f_BnsUdReq(template PDU_BSSGP pdu, BssgpBvci bvci) +private function f_BnsUdReq(template PDU_BSSGP pdu, BssgpBvci bvci, integer lsp) runs on BSSGP_CT return NsUnitdataRequest { var NsUnitdataRequest udr := { bvci := bvci, nsei := g_cfg.nsei, + lsp := lsp, /* for some weird reason we get "Dynamic test case error: Text encoder: Encoding an * unbound integer value." when trying to send the reocrd rather than the octetstring */ //sdu := omit, @@ -610,6 +611,9 @@ type component BSSGP_BVC_CT { var BssgpBvcConfig g_cfg; var boolean g_sgsn_role; + /* default Link Selector Parameter for this BVC (for traffic unrelated to a TLLI) */ + var integer g_bvc_lsp; + var BvcState g_ptp_bvc_state := BVC_S_BLOCKED; timer g_T1 := 15.0; timer g_T2 := 60.0; @@ -871,20 +875,20 @@ private function f_dec_bssgp(PDU_BSSGP bssgp) runs on BSSGP_BVC_CT return BssgpD } private function f_ptp_sendUnblock() runs on BSSGP_BVC_CT { - BVC.send(ts_ptp_BnsUdReq(t_BVC_UNBLOCK(g_cfg.bvci), 0)); + BVC.send(ts_ptp_BnsUdReq(t_BVC_UNBLOCK(g_cfg.bvci), 0, g_bvc_lsp)); g_t1_waits_for_block_ack := false; g_T1.start; } private function f_ptp_sendBlock(BssgpCause cause) runs on BSSGP_BVC_CT { - BVC.send(ts_ptp_BnsUdReq(t_BVC_BLOCK(g_cfg.bvci, cause), 0)); + BVC.send(ts_ptp_BnsUdReq(t_BVC_BLOCK(g_cfg.bvci, cause), 0, g_bvc_lsp)); g_t1_waits_for_block_ack := true; g_T1.start; } private function f_ptp_sendStatus(BssgpCause cause, PDU_BSSGP pdu) runs on BSSGP_BVC_CT { /* FIXME: Make sure correct Signaling or PTP BVCI is used! */ - BVC.send(ts_ptp_BnsUdReq(ts_BSSGP_STATUS(g_cfg.bvci, cause, pdu), g_cfg.bvci)); + BVC.send(ts_ptp_BnsUdReq(ts_BSSGP_STATUS(g_cfg.bvci, cause, pdu), g_cfg.bvci, g_bvc_lsp)); } private function f_ptp_sendReset() runs on BSSGP_BVC_CT { @@ -900,7 +904,7 @@ private function f_ptp_sendReset() runs on BSSGP_BVC_CT { } /* BVC-RESET is always sent via the SIGNALLING BVCI, see Table 5.4.1 */ - BVC.send(ts_ptp_BnsUdReq(pdu, 0)); + BVC.send(ts_ptp_BnsUdReq(pdu, 0, g_bvc_lsp)); g_T2.start; //f_change_state(BVC_S_WAIT_RESET); } @@ -946,11 +950,11 @@ private altstep as_ptp_unblocked() runs on BSSGP_BVC_CT { /* bogus unblock, just respond with ACK */ [] BVC.receive(tr_ptp_BnsUdInd(t_BVC_UNBLOCK(g_cfg.bvci), 0)) -> value udi { - BVC.send(ts_ptp_BnsUdReq(t_BVC_UNBLOCK_ACK(g_cfg.bvci), 0)); + BVC.send(ts_ptp_BnsUdReq(t_BVC_UNBLOCK_ACK(g_cfg.bvci), 0, g_bvc_lsp)); } /* Respond to BLOCK with BLOCK-ACK + change state */ [] BVC.receive(tr_ptp_BnsUdInd(t_BVC_BLOCK(g_cfg.bvci, ?), 0)) -> value udi { - BVC.send(ts_ptp_BnsUdReq(t_BVC_BLOCK_ACK(g_cfg.bvci), 0)); + BVC.send(ts_ptp_BnsUdReq(t_BVC_BLOCK_ACK(g_cfg.bvci), 0, g_bvc_lsp)); g_T1.stop; f_ptp_change_state(BVC_S_BLOCKED); } @@ -970,7 +974,7 @@ private altstep as_ptp_unblocked() runs on BSSGP_BVC_CT { /* simply acknowledge all per-BVC Flow Control Messages */ [g_sgsn_role] BVC.receive(tr_ptp_BnsUdInd(tr_BVC_FC_BVC, g_cfg.bvci)) -> value udi { var OCT1 tag := udi.bssgp.pDU_BSSGP_FLOW_CONTROL_BVC.tag.unstructured_Value; - BVC.send(ts_ptp_BnsUdReq(t_BVC_FC_BVC_ACK(tag), g_cfg.bvci)); + BVC.send(ts_ptp_BnsUdReq(t_BVC_FC_BVC_ACK(tag), g_cfg.bvci, g_bvc_lsp)); } /* [g_sgsn_role] BVC.receive(tr_ptp_BnsUdInd(t_BVC_FC_MS, g_cfg.bvci)) { @@ -1017,44 +1021,48 @@ private altstep as_ptp_unblocked() runs on BSSGP_BVC_CT { /* ConnHdlr sends BSSGP on BVCI=0 port: forward it to BSSGP_CT */ [] BSSGP_SP_SIG.receive(PDU_BSSGP:?)-> value bs_pdu sender vc_conn { - BVC.send(ts_ptp_BnsUdReq(bs_pdu, 0)); + BVC.send(ts_ptp_BnsUdReq(bs_pdu, 0, g_bvc_lsp)); } /* ConnHdlr sends BSSGP on BVCI=PTP port: forward it to BSSGP_CT */ [] BSSGP_SP.receive(PDU_BSSGP:?)-> value bs_pdu sender vc_conn { - BVC.send(ts_ptp_BnsUdReq(bs_pdu, g_cfg.bvci)); + BVC.send(ts_ptp_BnsUdReq(bs_pdu, g_cfg.bvci, g_bvc_lsp)); } #ifdef BSSGP_EM_L3 /* ConnHdlr sends L3: Encode and send as UL_UD / DL_UD */ [g_sgsn_role] BSSGP_SP.receive(PDU_L3_SGSN_MS:?) -> value l3_mt sender vc_conn { var integer idx := f_tbl_idx_by_comp(vc_conn); + var OCT4 tlli := ClientTable[idx].tlli; var octetstring l3_enc := enc_PDU_L3_SGSN_MS(l3_mt); var BIT4 sapi := f_llc_sapi_by_l3_mt(l3_mt); var integer n_u := f_llc_get_n_u_tx(ClientTable[idx].llc[bit2int(sapi)]); var octetstring llc_enc := enc_PDU_LLC(valueof(ts_LLC_UI(l3_enc, sapi, '1'B, n_u))); - BVC.send(ts_ptp_BnsUdReq(ts_BSSGP_DL_UD(ClientTable[idx].tlli, llc_enc), g_cfg.bvci)); + BVC.send(ts_ptp_BnsUdReq(ts_BSSGP_DL_UD(tlli, llc_enc), g_cfg.bvci, oct2int(tlli))); } [not g_sgsn_role] BSSGP_SP.receive(PDU_L3_MS_SGSN:?) -> value l3_mo sender vc_conn { var integer idx := f_tbl_idx_by_comp(vc_conn); + var OCT4 tlli := ClientTable[idx].tlli; var octetstring l3_enc := enc_PDU_L3_MS_SGSN(l3_mo); var BIT4 sapi := f_llc_sapi_by_l3_mo(l3_mo); var integer n_u := f_llc_get_n_u_tx(ClientTable[idx].llc[bit2int(sapi)]); var octetstring llc_enc := enc_PDU_LLC(valueof(ts_LLC_UI(l3_enc, sapi, '1'B, n_u))); - BVC.send(ts_ptp_BnsUdReq(ts_BSSGP_UL_UD(ClientTable[idx].tlli, g_cfg.cell_id, llc_enc), g_cfg.bvci)); + BVC.send(ts_ptp_BnsUdReq(ts_BSSGP_UL_UD(tlli, g_cfg.cell_id, llc_enc), g_cfg.bvci, oct2int(tlli))); } #endif /* ConnHdlr sends raw LLC: Encode and send as UL_UD / DL_UD */ [not g_sgsn_role] BSSGP_SP.receive(PDU_LLC:?) -> value llc sender vc_conn { var integer idx := f_tbl_idx_by_comp(vc_conn); + var OCT4 tlli := ClientTable[idx].tlli; var octetstring llc_enc := enc_PDU_LLC(llc); - BVC.send(ts_ptp_BnsUdReq(ts_BSSGP_UL_UD(ClientTable[idx].tlli, g_cfg.cell_id, llc_enc), g_cfg.bvci)); + BVC.send(ts_ptp_BnsUdReq(ts_BSSGP_UL_UD(tlli, g_cfg.cell_id, llc_enc), g_cfg.bvci, oct2int(tlli))); } [g_sgsn_role] BSSGP_SP.receive(PDU_LLC:?) -> value llc sender vc_conn { var integer idx := f_tbl_idx_by_comp(vc_conn); + var OCT4 tlli := ClientTable[idx].tlli; var octetstring llc_enc := enc_PDU_LLC(llc); - BVC.send(ts_ptp_BnsUdReq(ts_BSSGP_DL_UD(ClientTable[idx].tlli, llc_enc), g_cfg.bvci)); + BVC.send(ts_ptp_BnsUdReq(ts_BSSGP_DL_UD(tlli, llc_enc), g_cfg.bvci, oct2int(tlli))); } } @@ -1081,7 +1089,7 @@ private altstep as_ptp_allstate() runs on BSSGP_BVC_CT { [g_sgsn_role] BVC.receive(tr_ptp_BnsUdInd(tr_BVC_RESET(?, g_cfg.bvci, g_cfg.cell_id), 0)) -> value udi { log("Rx BVC-RESET from BVCI=", g_cfg.bvci); /* Respond to RESET with correct BVCI but without CellID */ - BVC.send(ts_ptp_BnsUdReq(ts_BVC_RESET_ACK(g_cfg.bvci, omit), 0)); + BVC.send(ts_ptp_BnsUdReq(ts_BVC_RESET_ACK(g_cfg.bvci, omit), 0, g_bvc_lsp)); /* FIXME: reset all state? What about clients? */ f_ptp_change_state(BVC_S_UNBLOCKED); } @@ -1089,7 +1097,7 @@ private altstep as_ptp_allstate() runs on BSSGP_BVC_CT { [not g_sgsn_role] BVC.receive(tr_ptp_BnsUdInd(tr_BVC_RESET(?, g_cfg.bvci, omit), 0)) -> value udi { log("Rx BVC-RESET from BVCI=", g_cfg.bvci); /* Respond to RESET with correct BVCI with CellID */ - BVC.send(ts_ptp_BnsUdReq(ts_BVC_RESET_ACK(g_cfg.bvci, g_cfg.cell_id), 0)); + BVC.send(ts_ptp_BnsUdReq(ts_BVC_RESET_ACK(g_cfg.bvci, g_cfg.cell_id), 0, g_bvc_lsp)); /* FIXME: reset all state? What about clients? */ f_ptp_change_state(BVC_S_UNBLOCKED); } @@ -1138,13 +1146,16 @@ private function f_bssgp_bvc_ScanEvents() runs on BSSGP_BVC_CT { /* main function for per-BVC Component */ private function f_bssgp_bvc_main(BssgpBvcConfig cfg, boolean sgsn_role, charstring id) runs on BSSGP_BVC_CT { g_cfg := cfg; + g_bvc_lsp := cfg.bvci; g_sgsn_role := sgsn_role; f_bssgp_bvc_ScanEvents(); } -template (value) NsUnitdataRequest ts_ptp_BnsUdReq(template (value) PDU_BSSGP pdu, template (value) BssgpBvci bvci) := { +template (value) NsUnitdataRequest ts_ptp_BnsUdReq(template (value) PDU_BSSGP pdu, template (value) BssgpBvci bvci, + template (value) integer lsp) := { bvci := bvci, nsei := 0, // overwritten in BSSGP_CT + lsp := lsp, /* for some weird reason we get "Dynamic test case error: Text encoder: Encoding an * unbound integer value." when trying to send the reocrd rather than the octetstring */ //sdu := omit, diff --git a/library/NS_Emulation.ttcnpp b/library/NS_Emulation.ttcnpp index 79589384..19de9d32 100644 --- a/library/NS_Emulation.ttcnpp +++ b/library/NS_Emulation.ttcnpp @@ -24,24 +24,28 @@ module NS_Emulation { type record NsUnitdataRequest { BssgpBvci bvci, Nsei nsei, + integer lsp, octetstring sdu optional, PDU_BSSGP bssgp optional } - template NsUnitdataRequest tr_NsUdReq(template Nsei nsei, template BssgpBvci bvci, template octetstring sdu, - template PDU_BSSGP bssgp) := { + template NsUnitdataRequest tr_NsUdReq(template Nsei nsei, template BssgpBvci bvci, template integer lsp, + template octetstring sdu, template PDU_BSSGP bssgp) := { bvci := bvci, nsei := nsei, + lsp := lsp, sdu := sdu, bssgp := bssgp } template (value) NsUnitdataRequest ts_NsUdReq(template (value) Nsei nsei, template (value) BssgpBvci bvci, + template (value) integer lsp, template (omit) octetstring sdu, template (omit) PDU_BSSGP bssgp) := { bvci := bvci, nsei := nsei, + lsp := lsp, sdu := sdu, bssgp := bssgp } @@ -184,7 +188,8 @@ 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 := {}; }; type record NsvcTableEntry { Nsvci nsvci, @@ -192,6 +197,7 @@ module NS_Emulation { NsvcState state }; type record of NsvcTableEntry NsvcTable; + type record of integer ro_integer; /* add one NSVC (component and table entry */ function f_nsvc_add(NSVCConfiguration nsvc_cfg) runs on NS_CT { @@ -206,6 +212,7 @@ module NS_Emulation { te.vc_conn.start(NSVCStart(nsvc_cfg, g_config, nsvc_id)); g_nsvcs := g_nsvcs & { te }; + /* no need to add to g_unblocked_nsvcs, as state is always DEAD_BLOCKED above */ } function f_nsvc_find_idx(Nsvci nsvci) runs on NS_CT return integer { @@ -232,6 +239,19 @@ module NS_Emulation { if (i < 0) { return; } + 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}; + } 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}; + } + } + g_unblocked_nsvcs := new_unblocked_nsvcs; + } g_nsvcs[i].state := state; } @@ -302,11 +322,12 @@ 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, ?, ?, *)) -> value rx_nsudr { - /* FIXME: load distribution function */ - NSVC.send(rx_nsudr) to g_nsvcs[0].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)]; + NSVC.send(rx_nsudr) to g_nsvcs[nsvc_idx].vc_conn; } - [] NS_SP.receive(tr_NsUdReq(?, ?, ?, *)) -> value rx_nsudr { + [] NS_SP.receive(tr_NsUdReq(?, ?, ?, ?, *)) -> value rx_nsudr { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received NsUnitdataReq for invalid NSEI: ", rx_nsudr)); } @@ -564,11 +585,11 @@ module NS_Emulation { 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, ?, ?, ?, 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, ?, ?, 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)); -- cgit v1.2.3