1 /*==================================================================================
3 Copyright (c) 2018-2019 AT&T Intellectual Property.
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
9 http://www.apache.org/licenses/LICENSE-2.0
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 ==================================================================================
19 /* Author : Ashwin Sridharan
26 A mock e2term for testing
27 -- accepts a subscription request
28 -- accepts a delete subscription request
31 -- when subscription is active, sends out indication messages with X2AP SgNBAdditionRequest at specified rate
32 and monitors control request
34 -- when delete is requested, stops sending ...
47 #include <xapp_utils.hpp>
49 #include <rmr/RIC_message_types.h>
50 #include <xapp_utils.hpp>
51 #include <subscription_request.hpp>
52 #include <subscription_response.hpp>
53 #include <subscription_delete_request.hpp>
54 #include <subscription_delete_response.hpp>
57 #include <e2ap_indication.hpp>
58 #include <e2ap_control.hpp>
59 #include <e2ap_control_response.hpp>
60 #include <sgnb_addition_request.hpp>
61 #include <sgnb_addition_response.hpp>
66 unsigned long int num_indications = 0;
67 unsigned long int num_controls = 0;
68 unsigned long int num_accepts = 0;
69 unsigned long int num_rejects = 0;
70 unsigned long int num_errors = 0;
72 bool verbose_flag = false;
73 bool RunProgram = true;
74 bool subscription_active = false;
75 int action_type = E2N_RICindicationType::E2N_RICindicationType_report;
77 // PRE-ENCODED X2AP SGNB ADDITION REQUESTS
78 static const std::vector<std::string> x2ap_files = {"test-data/X2AP-PDU-SgNBAdditionRequest_SubId_10.per", "test-data/X2AP-PDU-SgNBAdditionRequest_SubId_23.per", "test-data/X2AP-PDU-SgNBAdditionRequest_SubId_29.per", "test-data/X2AP-PDU-SgNBAdditionRequest_SubId_180.per", "test-data/X2AP-PDU-SgNBAdditionRequest_SubId_210.per"};
80 void usage(char *command){
81 std::cout <<"Usage : " << command << " ";
82 std::cout <<" --name[-n] xapp_instance_name ";
83 std::cout <<" --port[-p] port to listen on e.g tcp:4591 ";
84 std::cout << "--verbose ";
85 std::cout <<" --rate[-r] rate to send indication messages";
86 std::cout << std::endl;
89 void EndProgram(int signum){
90 std::cout <<"Signal received. Stopping program ....." << std::endl;
94 bool Message_Handler(rmr_mbuf_t *message){
98 unsigned char meid[32];
99 unsigned char src[32];
101 subscription_helper he;
102 subscription_response_helper he_resp;
104 subscription_request sub_req;
105 subscription_response sub_resp;
107 subscription_delete sub_del_req;
108 subscription_delete_response sub_del_resp;
110 ric_control_request control_req;
111 ric_control_response control_resp;
112 ric_control_helper control_data;
114 e2sm_control e2sm_control_proc;
116 asn_dec_rval_t retval;
119 E2N_E2AP_PDU_t *e2ap_pdu_recv = 0;
120 X2N_X2AP_PDU_t *x2ap_pdu_recv = 0;
121 E2N_E2SM_gNB_X2_eventTriggerDefinition_t *event = 0;
122 std::vector<Action> * actions;
124 bool send_msg = true;
126 rmr_get_meid(message, meid);
127 rmr_get_src(message, src);
129 switch(message->mtype){
132 std::cout <<"*** Received message from src = " << src << " for gNodeB = " << meid << " of size = " << message->len << " and type = " << message->mtype << std::endl;
135 retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len);
137 if(retval.code == RC_OK){
139 sub_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, he);
142 std::cerr <<"Error decoding E2AP Subscription response PDU. Reason = " << strerror(errno) << std::endl;
144 goto finished_sub_req;
148 std::cout <<"==============================\nReceived Subscription Request with ID = " << he.get_request_id() << std::endl;
149 //xer_fprint(stdout, &asn_DEF_E2AP_PDU, e2ap_pdu_recv);
152 // get action type (we support only one action in subscription request currently ....
153 actions = he.get_list();
154 action_type = (*actions)[0].get_type();
155 std::cout << "Action type in subscription request ID = "<< he.get_request_id() << " set to " << action_type << std::endl;
157 // decode the event trigger ...
159 e2sm_event_trigger_helper event_trigger_data;
160 event = 0; // used for decoding
161 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());
162 if (retval.code != RC_OK){
163 std::cerr <<"Error decoding event trigger in subscription request. Reason = " << strerror(errno) << std::endl;
165 goto finished_sub_req;
167 //std::cout <<"++++++++++++++ EVENT TRIGGER ++++++++++++++++++++++++++++++++++" << std::endl;
168 //xer_fprint(stdout, &asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event);
169 //std::cout <<"++++++++++++++ EVENT TRIGGER ++++++++++++++++++++++++++++++++++" << std::endl;
173 // set up response object
174 he_resp.set_request(he.get_request_id(), he.get_req_seq());
175 he_resp.set_function_id(he.get_function_id());
178 // ideally should move all actions to not admitted if failed
179 // but we ignore admitted list anyway when we set up the PDU
180 // for now, just copy to both lists :) ...
181 for(auto &e : *(he.get_list())){
182 he_resp.add_action(e.get_id());
183 he_resp.add_action(e.get_id(), 1, 2);
187 mlen = RMR_BUFFER_SIZE;
189 res = sub_resp.encode_e2ap_subscription_response(&message->payload[0], &mlen, he_resp, true);
191 std::cerr << "Error encoding subscription response successful. Reason = " << sub_resp.get_error() << std::endl;
193 goto finished_sub_req;
195 message->mtype = RIC_SUB_RESP;
196 subscription_active = true;
200 ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
201 ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event);
205 // also set subscription id ?
206 std::cout <<"Sending Subscription Response with RMR type " << message->mtype << " and size = " << message->len << std::endl;
207 std::cout <<"======================================" << std::endl;
214 case RIC_SUB_DEL_REQ:
217 retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len);
218 if(retval.code == RC_OK){
220 sub_del_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, he);
223 std::cerr <<"Error decoding E2AP Subscription Delete Request PDU. Reason = " << strerror(errno) << std::endl;
225 goto finished_sub_del;
228 std::cout <<"==============================\nReceived Subscription Delete Request with ID = " << he.get_request_id() << std::endl;
229 xer_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
230 std::cout <<"==============================\nReceived Subscription Delete Request with ID = " << he.get_request_id() << std::endl;
233 // pfile = fopen("subscription_delete.per", "wb");
234 // fwrite(message->payload, 1, message->len, pfile);
237 // set up response object
238 std::cout <<"Generating response ...." << std::endl;
240 he_resp.set_request(he.get_request_id(), he.get_req_seq());
241 he_resp.set_function_id(he.get_function_id());
242 mlen = RMR_BUFFER_SIZE;
243 res = sub_del_resp.encode_e2ap_subscription_delete_response(&message->payload[0], &mlen, he_resp, true);
245 std::cerr << "Error encoding subscription delete response failure . Reason = " << sub_resp.get_error() << std::endl;
247 goto finished_sub_del;
251 ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
254 message->mtype = RIC_SUB_DEL_RESP;
256 subscription_active = false;
263 case RIC_CONTROL_REQ:
266 retval = asn_decode(0,ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len);
267 if(retval.code != RC_OK){
268 std::cerr <<"Error decoding RIC Control Request" << std::endl;
273 std::cout <<"++++++++ RECEIVED CONTROL REQUEST +++++++++++++++++++++++++++++" << std::endl;
274 xer_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
277 res = control_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, control_data);
279 std::cout <<"Error getting data from E2AP control request" << std::endl;
283 // Decode the X2AP PDU : directly embedded in Control Msg IE
285 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 );
286 if (retval.code != RC_OK){
287 std::cerr <<"Error decoding X2AP PDU in control request message of size " << control_data.control_msg_size << std::endl;
293 xer_fprint(stdout, &asn_DEF_X2N_X2AP_PDU, x2ap_pdu_recv);
294 std::cout <<"++++++++ RECEIVED CONTROL REQUEST +++++++++++++++++++++++++++++" << std::endl;
298 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 ){
301 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 ){
305 std::cerr <<"Unknown X2AP PDU : message type = " << x2ap_pdu_recv->present << std::endl;
309 // generate control ack ?
310 // control_data.control_status = 0;
311 // mlen = RMR_BUFFER_SIZE;
312 // res = control_resp.encode_e2ap_control_response(message->payload, &mlen, control_data, true);
315 // std::cerr <<"Error encoding control response ack. Reason = " << control_resp.get_error() << std::endl;
318 ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
319 ASN_STRUCT_FREE(asn_DEF_X2N_X2AP_PDU, x2ap_pdu_recv);
324 std::cerr <<"Error ! Unknown RMR message of type " << message->mtype << " received" << std::endl;
334 int main(int argc, char *argv[]){
336 char name[128] = "mock_subscription_mgr";
337 char port[16] = "tcp:4591";
338 double rate = 1; // default rate to send at
339 int verbose_flag = 0;
341 // Parse command line options
342 static struct option long_options[] =
344 /* Thse options require arguments */
345 {"name", required_argument, 0, 'n'},
346 {"port", required_argument, 0, 'p'},
347 {"rate", required_argument, 0, 'r'},
348 {"verbose", no_argument, &verbose_flag, 1},
355 int option_index = 0;
356 char c = getopt_long(argc, argv, "n:p:a:r:", long_options, &option_index);
365 /* An option flag was set.
366 Do nothing for now */
370 strcpy(name, optarg);
374 strcpy(port, optarg);
381 std::cerr <<"Error : Transmit rate must be >= 0/sec" << std::endl;
386 std::cerr <<"Error : maximum allowed rate = 1000/sec" << std::endl;
397 std::cout <<"Error ! " << std::endl;
403 int log_level = MDCLOG_WARN;
405 log_level = MDCLOG_INFO;
407 init_logger(name, static_cast<mdclog_severity_t>(log_level));
409 XaPP my_xapp = XaPP(name, port, 16384);
410 my_xapp.StartThread(Message_Handler);
414 e2sm_indication e2sm_indication_obj;
419 //==== e2sm indication header : just some
420 e2sm_header_helper indication_header;
421 // random fill for now
422 indication_header.egNB_id="hello";
423 indication_header.plmn_id="there";
424 indication_header.interface_direction = 1;
425 indication_header.egNB_id_type = 2;
426 unsigned char buf_header[32];
427 size_t buf_header_size = 32;
429 res = e2sm_indication_obj.encode_indication_header(&buf_header[0], &buf_header_size, indication_header);
431 std::cout <<"Error encoding indication header. Reason = " << e2sm_indication_obj.get_error() << std::endl;
435 //====== load the various x2ap requests
436 unsigned char ** x2ap_bufs = (unsigned char **)calloc(x2ap_files.size(), sizeof(unsigned char *));
437 size_t * x2ap_buf_sizes = (size_t *)calloc(x2ap_files.size(), sizeof(size_t));
439 assert(x2ap_bufs != 0);
440 assert(x2ap_buf_sizes != 0);
442 for(int i = 0; i < x2ap_files.size(); i++){
443 std::ifstream in(x2ap_files[i], std::ifstream::ate | std::ifstream::binary);
444 x2ap_buf_sizes[i] = in.tellg();
445 std::cout <<"Assigned " << x2ap_buf_sizes[i] << " bytes of memory for file " << x2ap_files[i] << std::endl;
446 x2ap_bufs[i] = (unsigned char *)calloc(x2ap_buf_sizes[i], sizeof(unsigned char));
447 assert(x2ap_bufs[i] != 0);
449 pfile = fopen(x2ap_files[i].c_str(), "r");
451 std::cerr <<"Error ! Could not find test per file " << x2ap_files[i] << std::endl;
455 fread((char *)x2ap_bufs[i], sizeof(char), x2ap_buf_sizes[i], pfile);
459 //==== e2ap indication for generated x2ap pdus
460 ric_indication_helper dinput ;
461 dinput.action_id = 100;
463 dinput.indication_sn = 100;
465 dinput.req_seq_no = 11;
469 /* encoding pdu put here */
470 size_t data_size = 16384;
471 unsigned char data[data_size];
473 ric_indication indication_pdu;
476 dinput.indication_header = buf_header;
477 dinput.indication_header_size = buf_header_size;
480 //Register signal handler to stop
481 signal(SIGINT, EndProgram);
482 signal(SIGTERM, EndProgram);
484 unsigned long int interval = 0;
487 interval = 1000.0/rate;
493 auto start_time = std::chrono::steady_clock::now();
496 int packet_index = 0;
499 if ( subscription_active && rate > 0 ){
500 my_xapp.Send(RIC_INDICATION, data_size, data);
504 // choose packet to encode
505 dinput.indication_msg = x2ap_bufs[packet_index];
506 dinput.indication_msg_size = x2ap_buf_sizes[packet_index];
507 dinput.indication_type = 1; // for now always ask for control back
508 res = indication_pdu.encode_e2ap_indication(&data[0], &data_size, dinput);
510 std::cout <<"Error encoding E2AP Indication PDU. Reason = " << indication_pdu.get_error().c_str() << std::endl;
514 packet_index = packet_index % x2ap_files.size();
517 std::this_thread::sleep_for(std::chrono::milliseconds(interval));
522 auto end_time = std::chrono::steady_clock::now();
523 double duration = std::chrono::duration_cast<std::chrono::seconds>(end_time - start_time).count();
525 std::cout <<"Number of SgNB Addition Request (in E2AP Indication) sent = " << num_indications << std::endl;
526 std::cout <<"Number of control responses received = " << num_controls << std::endl;
527 std::cout <<"Number of SgNB Addition Acknowledges = " << num_accepts << std::endl;
528 std::cout <<"NUmber of SgNB Addition Rejects = " << num_rejects << std::endl;
529 std::cout <<"Number of E2AP control requests we could not decode = " << num_errors << std::endl;
531 std::cout <<"Duration = " << duration << " E2AP Indication Tx Rate = " << num_indications/duration << std::endl;
534 std::cout <<"Stopped RMR thread .." << std::endl;