X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=test%2Fmock_e2term_server.cc;fp=test%2Fmock_e2term_server.cc;h=90aef8fa90f64ce6be40e8b236d426a8c20b2a2d;hb=dc68642f5676cdd49f3ef92f983b319e21f16afa;hp=0000000000000000000000000000000000000000;hpb=0054ece5d9d4bcb28ecda2f0f36584f6a64fc869;p=ric-app%2Fadmin.git diff --git a/test/mock_e2term_server.cc b/test/mock_e2term_server.cc new file mode 100644 index 0000000..90aef8f --- /dev/null +++ b/test/mock_e2term_server.cc @@ -0,0 +1,528 @@ +/*================================================================================== + + Copyright (c) 2018-2019 AT&T Intellectual Property. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +================================================================================== +*/ + +/* Author : Ashwin Sridharan + Date : Feb 2019 +*/ + + +/* + + A mock e2term for testing + -- accepts a subscription request + -- accepts a delete subscription request + + + -- when subscription is active, sends out indication messages with X2AP SgNBAdditionRequest at specified rate + and monitors control request + + -- when delete is requested, stops sending ... + + +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define X2_SGNB_ADDITION_REQUEST "test-data/X2AP-PDU-SgNBAdditionRequest.per" + + +unsigned long int num_indications = 0; +unsigned long int num_controls = 0; +unsigned long int num_accepts = 0; +unsigned long int num_rejects = 0; +unsigned long int num_errors = 0; + +bool verbose_flag = false; +bool RunProgram = true; +bool subscription_active = false; +int action_type = E2N_RICindicationType::E2N_RICindicationType_report; + + + +void usage(char *command){ + std::cout <<"Usage : " << command << " "; + std::cout <<" --name[-n] xapp_instance_name "; + std::cout <<" --port[-p] port to listen on e.g tcp:4591 "; + std::cout << "--verbose "; + std::cout <<" --rate[-r] rate to send indication messages"; + std::cout << std::endl; +} + +void EndProgram(int signum){ + std::cout <<"Signal received. Stopping program ....." << std::endl; + RunProgram = false; +} + +bool Message_Handler(rmr_mbuf_t *message){ + + bool res; + int i; + unsigned char meid[32]; + unsigned char src[32]; + + subscription_helper he; + subscription_response_helper he_resp; + + subscription_request sub_req; + subscription_response sub_resp; + + subscription_delete sub_del_req; + subscription_delete_response sub_del_resp; + + ric_control_request control_req; + ric_control_response control_resp; + ric_control_helper control_data; + + e2sm_control e2sm_control_proc; + + asn_dec_rval_t retval; + size_t mlen; + + E2N_E2AP_PDU_t *e2ap_pdu_recv = 0; + X2N_X2AP_PDU_t *x2ap_pdu_recv = 0; + E2N_E2SM_gNB_X2_eventTriggerDefinition_t *event = 0; + std::vector * actions; + + bool send_msg = true; + + rmr_get_meid(message, meid); + rmr_get_src(message, src); + + switch(message->mtype){ + case RIC_SUB_REQ: + + std::cout <<"*** Received message from src = " << src << " for gNodeB = " << meid << " of size = " << message->len << " and type = " << message->mtype << std::endl; + + e2ap_pdu_recv = 0; + retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len); + + if(retval.code == RC_OK){ + he.clear(); + sub_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, he); + } + else{ + std::cerr <<"Error decoding E2AP Subscription response PDU. Reason = " << strerror(errno) << std::endl; + send_msg = false; + goto finished_sub_req; + + } + + std::cout <<"==============================\nReceived Subscription Request with ID = " << he.get_request_id() << std::endl; + //xer_fprint(stdout, &asn_DEF_E2AP_PDU, e2ap_pdu_recv); + + + // get action type (we support only one action in subscription request currently .... + actions = he.get_list(); + action_type = (*actions)[0].get_type(); + std::cout << "Action type in subscription request ID = "<< he.get_request_id() << " set to " << action_type << std::endl; + + // decode the event trigger ... + { + e2sm_event_trigger_helper event_trigger_data; + event = 0; // used for decoding + retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, (void**)&(event), (unsigned char *)he.get_event_def(), he.get_event_def_size()); + if (retval.code != RC_OK){ + std::cerr <<"Error decoding event trigger in subscription request. Reason = " << strerror(errno) << std::endl; + send_msg = false; + goto finished_sub_req; + } + //std::cout <<"++++++++++++++ EVENT TRIGGER ++++++++++++++++++++++++++++++++++" << std::endl; + //xer_fprint(stdout, &asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event); + //std::cout <<"++++++++++++++ EVENT TRIGGER ++++++++++++++++++++++++++++++++++" << std::endl; + + } + + // set up response object + he_resp.set_request(he.get_request_id(), he.get_req_seq()); + he_resp.set_function_id(he.get_function_id()); + i = 0; + + // ideally should move all actions to not admitted if failed + // but we ignore admitted list anyway when we set up the PDU + // for now, just copy to both lists :) ... + for(auto &e : *(he.get_list())){ + he_resp.add_action(e.get_id()); + he_resp.add_action(e.get_id(), 1, 2); + + i++; + } + mlen = RMR_BUFFER_SIZE; + + res = sub_resp.encode_e2ap_subscription_response(&message->payload[0], &mlen, he_resp, true); + if (!res){ + std::cerr << "Error encoding subscription response successful. Reason = " << sub_resp.get_error() << std::endl; + send_msg = false; + goto finished_sub_req; + } + message->mtype = RIC_SUB_RESP; + subscription_active = true; + + + finished_sub_req: + ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv); + ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event); + if(send_msg){ + message->len = mlen; + + // also set subscription id ? + std::cout <<"Sending Subscription Response with RMR type " << message->mtype << " and size = " << message->len << std::endl; + std::cout <<"======================================" << std::endl; + return true; + } + else{ + break; + } + + case RIC_SUB_DEL_REQ: + + e2ap_pdu_recv = 0; + retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len); + if(retval.code == RC_OK){ + he.clear(); + sub_del_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, he); + } + else{ + std::cerr <<"Error decoding E2AP Subscription Delete Request PDU. Reason = " << strerror(errno) << std::endl; + send_msg = false; + goto finished_sub_del; + } + + std::cout <<"==============================\nReceived Subscription Delete Request with ID = " << he.get_request_id() << std::endl; + xer_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv); + std::cout <<"==============================\nReceived Subscription Delete Request with ID = " << he.get_request_id() << std::endl; + + // FILE *pfile; + // pfile = fopen("subscription_delete.per", "wb"); + // fwrite(message->payload, 1, message->len, pfile); + // fclose(pfile); + + // set up response object + std::cout <<"Generating response ...." << std::endl; + he_resp.clear(); + he_resp.set_request(he.get_request_id(), he.get_req_seq()); + he_resp.set_function_id(he.get_function_id()); + mlen = RMR_BUFFER_SIZE; + res = sub_del_resp.encode_e2ap_subscription_delete_response(&message->payload[0], &mlen, he_resp, true); + if (!res){ + std::cerr << "Error encoding subscription delete response failure . Reason = " << sub_resp.get_error() << std::endl; + send_msg = false; + goto finished_sub_del; + } + + finished_sub_del: + ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv); + + if(send_msg){ + message->mtype = RIC_SUB_DEL_RESP; + message->len = mlen; + subscription_active = false; + return true; + } + else{ + break; + } + + case RIC_CONTROL_REQ: + num_controls ++; + e2ap_pdu_recv = 0; + retval = asn_decode(0,ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len); + if(retval.code != RC_OK){ + std::cerr <<"Error decoding RIC Control Request" << std::endl; + goto finished_ctrl; + } + + if (verbose_flag){ + std::cout <<"++++++++ RECEIVED CONTROL REQUEST +++++++++++++++++++++++++++++" << std::endl; + xer_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv); + } + + res = control_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, control_data); + if(!res){ + std::cout <<"Error getting data from E2AP control request" << std::endl; + break; + } + + // Decode the X2AP PDU : directly embedded in Control Msg IE + x2ap_pdu_recv = 0; + retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_X2N_X2AP_PDU, (void **)&x2ap_pdu_recv, control_data.control_msg, control_data.control_msg_size ); + if (retval.code != RC_OK){ + std::cerr <<"Error decoding X2AP PDU in control request message of size " << control_data.control_msg_size << std::endl; + num_errors ++; + goto finished_ctrl; + } + + if(verbose_flag){ + xer_fprint(stdout, &asn_DEF_X2N_X2AP_PDU, x2ap_pdu_recv); + std::cout <<"++++++++ RECEIVED CONTROL REQUEST +++++++++++++++++++++++++++++" << std::endl; + + } + + if(x2ap_pdu_recv->present == X2N_X2AP_PDU_PR_successfulOutcome && x2ap_pdu_recv->choice.successfulOutcome->procedureCode == X2N_ProcedureCode_id_sgNBAdditionPreparation && x2ap_pdu_recv->choice.successfulOutcome->value.present == X2N_SuccessfulOutcome__value_PR_SgNBAdditionRequestAcknowledge ){ + num_accepts ++; + } + else if ( x2ap_pdu_recv->present == X2N_X2AP_PDU_PR_unsuccessfulOutcome && x2ap_pdu_recv->choice.unsuccessfulOutcome->procedureCode == X2N_ProcedureCode_id_sgNBAdditionPreparation && x2ap_pdu_recv->choice.unsuccessfulOutcome->value.present == X2N_UnsuccessfulOutcome__value_PR_SgNBAdditionRequestReject ){ + num_rejects ++; + } + else{ + std::cerr <<"Unknown X2AP PDU : message type = " << x2ap_pdu_recv->present << std::endl; + } + + + // generate control ack ? + // control_data.control_status = 0; + // mlen = RMR_BUFFER_SIZE; + // res = control_resp.encode_e2ap_control_response(message->payload, &mlen, control_data, true); + + // if (!res){ + // std::cerr <<"Error encoding control response ack. Reason = " << control_resp.get_error() << std::endl; + // } + finished_ctrl: + ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv); + ASN_STRUCT_FREE(asn_DEF_X2N_X2AP_PDU, x2ap_pdu_recv); + + break; + + default: + std::cerr <<"Error ! Unknown RMR message of type " << message->mtype << " received" << std::endl; + break; + } + + return false; +}; + + + + +int main(int argc, char *argv[]){ + + char name[128] = "mock_subscription_mgr"; + char port[16] = "tcp:4591"; + double rate = 1; // default rate to send at + int verbose_flag = 0; + + // Parse command line options + static struct option long_options[] = + { + /* Thse options require arguments */ + {"name", required_argument, 0, 'n'}, + {"port", required_argument, 0, 'p'}, + {"rate", required_argument, 0, 'r'}, + {"verbose", no_argument, &verbose_flag, 1}, + + }; + + + while(1) { + + int option_index = 0; + char c = getopt_long(argc, argv, "n:p:a:r:", long_options, &option_index); + if(c == -1){ + break; + } + + switch(c) + { + + case 0: + /* An option flag was set. + Do nothing for now */ + break; + + case 'n': + strcpy(name, optarg); + break; + + case 'p': + strcpy(port, optarg); + break; + + + case 'r': + rate = atof(optarg); + if (rate < 0){ + std::cerr <<"Error : Transmit rate must be >= 0/sec" << std::endl; + exit(-1); + } + + if (rate > 1000){ + std::cerr <<"Error : maximum allowed rate = 1000/sec" << std::endl; + exit(-1); + } + break; + + case 'h': + usage(argv[0]); + exit(0); + + + default: + std::cout <<"Error ! " << std::endl; + usage(argv[0]); + exit(1); + } + }; + + int log_level = MDCLOG_WARN; + if (verbose_flag){ + log_level = MDCLOG_INFO; + } + init_logger(name, static_cast(log_level)); + + XaPP my_xapp = XaPP(name, port, 16384, 1); + my_xapp.Start(Message_Handler); + + + + e2sm_indication e2sm_indication_obj; + bool res; + FILE *pfile; + + + //==== e2sm indication header : just some + e2sm_header_helper indication_header; + // random fill for now + indication_header.egNB_id="hello"; + indication_header.plmn_id="there"; + indication_header.interface_direction = 1; + indication_header.egNB_id_type = 2; + unsigned char buf_header[32]; + size_t buf_header_size = 32; + + res = e2sm_indication_obj.encode_indication_header(&buf_header[0], &buf_header_size, indication_header); + if(!res){ + std::cout <<"Error encoding indication header. Reason = " << e2sm_indication_obj.get_error() << std::endl; + exit(-1); + } + + //====== x2ap sgnb addition request created by us + unsigned char x2ap_buf[1024]; + size_t x2ap_buf_size = 1024; + pfile = fopen(X2_SGNB_ADDITION_REQUEST, "r"); + if(pfile == NULL){ + std::cerr <<"Error ! Could not find test per file " << X2_SGNB_ADDITION_REQUEST << std::endl; + exit(-1); + } + + x2ap_buf_size = fread((char *)x2ap_buf, sizeof(char), 1024, pfile); + fclose(pfile); + + + //==== e2ap indication for generated x2ap pdus + ric_indication_helper dinput ; + dinput.action_id = 100; + dinput.func_id = 10; + dinput.indication_sn = 100; + dinput.req_id = 6; + dinput.req_seq_no = 11; + + + + /* encoding pdu put here */ + size_t data_size = 16384; + unsigned char data[data_size]; + + ric_indication indication_pdu; + + + // prepare packet to send. we send + // same packet every time for now + dinput.indication_header = buf_header; + dinput.indication_header_size = buf_header_size; + dinput.indication_msg = x2ap_buf; + dinput.indication_msg_size = x2ap_buf_size; + dinput.indication_type = 1; // for now always ask for control back + res = indication_pdu.encode_e2ap_indication(&data[0], &data_size, dinput); + if (!res){ + std::cout <<"Error encoding E2AP Indication PDU. Reason = " << indication_pdu.get_error().c_str() << std::endl; + exit(-1); + } + + + //Register signal handler to stop + signal(SIGINT, EndProgram); + signal(SIGTERM, EndProgram); + + unsigned long int interval = 0; + + if (rate > 0){ + interval = 1000.0/rate; + } + else{ + interval = 10; + } + + auto start_time = std::chrono::steady_clock::now(); + int count = 0; + + + while(RunProgram){ + + if ( subscription_active && rate > 0 ){ + my_xapp.Send(RIC_INDICATION, data_size, data); + num_indications ++; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(interval)); + count ++; + } + + + auto end_time = std::chrono::steady_clock::now(); + double duration = std::chrono::duration_cast(end_time - start_time).count(); + + std::cout <<"Number of SgNB Addition Request (in E2AP Indication) sent = " << num_indications << std::endl; + std::cout <<"Number of control responses received = " << num_controls << std::endl; + std::cout <<"Number of SgNB Addition Acknowledges = " << num_accepts << std::endl; + std::cout <<"NUmber of SgNB Addition Rejects = " << num_rejects << std::endl; + std::cout <<"Number of E2AP control requests we could not decode = " << num_errors << std::endl; + + std::cout <<"Duration = " << duration << " E2AP Indication Tx Rate = " << num_indications/duration << std::endl; + my_xapp.Stop(); + + std::cout <<"Stopped RMR thread .." << std::endl; + return 0; + + +}; + + + + + +