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 ...
46 #include <xapp_utils.hpp>
48 #include <rmr/RIC_message_types.h>
49 #include <xapp_utils.hpp>
50 #include <subscription_request.hpp>
51 #include <subscription_response.hpp>
52 #include <subscription_delete_request.hpp>
53 #include <subscription_delete_response.hpp>
56 #include <e2ap_indication.hpp>
57 #include <e2ap_control.hpp>
58 #include <e2ap_control_response.hpp>
59 #include <sgnb_addition_request.hpp>
60 #include <sgnb_addition_response.hpp>
62 #define X2_SGNB_ADDITION_REQUEST "test-data/X2AP-PDU-SgNBAdditionRequest.per"
65 unsigned long int num_indications = 0;
66 unsigned long int num_controls = 0;
67 unsigned long int num_accepts = 0;
68 unsigned long int num_rejects = 0;
69 unsigned long int num_errors = 0;
71 bool verbose_flag = false;
72 bool RunProgram = true;
73 bool subscription_active = false;
74 int action_type = E2N_RICindicationType::E2N_RICindicationType_report;
78 void usage(char *command){
79 std::cout <<"Usage : " << command << " ";
80 std::cout <<" --name[-n] xapp_instance_name ";
81 std::cout <<" --port[-p] port to listen on e.g tcp:4591 ";
82 std::cout << "--verbose ";
83 std::cout <<" --rate[-r] rate to send indication messages";
84 std::cout << std::endl;
87 void EndProgram(int signum){
88 std::cout <<"Signal received. Stopping program ....." << std::endl;
92 bool Message_Handler(rmr_mbuf_t *message){
96 unsigned char meid[32];
97 unsigned char src[32];
99 subscription_helper he;
100 subscription_response_helper he_resp;
102 subscription_request sub_req;
103 subscription_response sub_resp;
105 subscription_delete sub_del_req;
106 subscription_delete_response sub_del_resp;
108 ric_control_request control_req;
109 ric_control_response control_resp;
110 ric_control_helper control_data;
112 e2sm_control e2sm_control_proc;
114 asn_dec_rval_t retval;
117 E2N_E2AP_PDU_t *e2ap_pdu_recv = 0;
118 X2N_X2AP_PDU_t *x2ap_pdu_recv = 0;
119 E2N_E2SM_gNB_X2_eventTriggerDefinition_t *event = 0;
120 std::vector<Action> * actions;
122 bool send_msg = true;
124 rmr_get_meid(message, meid);
125 rmr_get_src(message, src);
127 switch(message->mtype){
130 std::cout <<"*** Received message from src = " << src << " for gNodeB = " << meid << " of size = " << message->len << " and type = " << message->mtype << std::endl;
133 retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len);
135 if(retval.code == RC_OK){
137 sub_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, he);
140 std::cerr <<"Error decoding E2AP Subscription response PDU. Reason = " << strerror(errno) << std::endl;
142 goto finished_sub_req;
146 std::cout <<"==============================\nReceived Subscription Request with ID = " << he.get_request_id() << std::endl;
147 //xer_fprint(stdout, &asn_DEF_E2AP_PDU, e2ap_pdu_recv);
150 // get action type (we support only one action in subscription request currently ....
151 actions = he.get_list();
152 action_type = (*actions)[0].get_type();
153 std::cout << "Action type in subscription request ID = "<< he.get_request_id() << " set to " << action_type << std::endl;
155 // decode the event trigger ...
157 e2sm_event_trigger_helper event_trigger_data;
158 event = 0; // used for decoding
159 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());
160 if (retval.code != RC_OK){
161 std::cerr <<"Error decoding event trigger in subscription request. Reason = " << strerror(errno) << std::endl;
163 goto finished_sub_req;
165 //std::cout <<"++++++++++++++ EVENT TRIGGER ++++++++++++++++++++++++++++++++++" << std::endl;
166 //xer_fprint(stdout, &asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event);
167 //std::cout <<"++++++++++++++ EVENT TRIGGER ++++++++++++++++++++++++++++++++++" << std::endl;
171 // set up response object
172 he_resp.set_request(he.get_request_id(), he.get_req_seq());
173 he_resp.set_function_id(he.get_function_id());
176 // ideally should move all actions to not admitted if failed
177 // but we ignore admitted list anyway when we set up the PDU
178 // for now, just copy to both lists :) ...
179 for(auto &e : *(he.get_list())){
180 he_resp.add_action(e.get_id());
181 he_resp.add_action(e.get_id(), 1, 2);
185 mlen = RMR_BUFFER_SIZE;
187 res = sub_resp.encode_e2ap_subscription_response(&message->payload[0], &mlen, he_resp, true);
189 std::cerr << "Error encoding subscription response successful. Reason = " << sub_resp.get_error() << std::endl;
191 goto finished_sub_req;
193 message->mtype = RIC_SUB_RESP;
194 subscription_active = true;
198 ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
199 ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event);
203 // also set subscription id ?
204 std::cout <<"Sending Subscription Response with RMR type " << message->mtype << " and size = " << message->len << std::endl;
205 std::cout <<"======================================" << std::endl;
212 case RIC_SUB_DEL_REQ:
215 retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len);
216 if(retval.code == RC_OK){
218 sub_del_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, he);
221 std::cerr <<"Error decoding E2AP Subscription Delete Request PDU. Reason = " << strerror(errno) << std::endl;
223 goto finished_sub_del;
226 std::cout <<"==============================\nReceived Subscription Delete Request with ID = " << he.get_request_id() << std::endl;
227 xer_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
228 std::cout <<"==============================\nReceived Subscription Delete Request with ID = " << he.get_request_id() << std::endl;
231 // pfile = fopen("subscription_delete.per", "wb");
232 // fwrite(message->payload, 1, message->len, pfile);
235 // set up response object
236 std::cout <<"Generating response ...." << std::endl;
238 he_resp.set_request(he.get_request_id(), he.get_req_seq());
239 he_resp.set_function_id(he.get_function_id());
240 mlen = RMR_BUFFER_SIZE;
241 res = sub_del_resp.encode_e2ap_subscription_delete_response(&message->payload[0], &mlen, he_resp, true);
243 std::cerr << "Error encoding subscription delete response failure . Reason = " << sub_resp.get_error() << std::endl;
245 goto finished_sub_del;
249 ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
252 message->mtype = RIC_SUB_DEL_RESP;
254 subscription_active = false;
261 case RIC_CONTROL_REQ:
264 retval = asn_decode(0,ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len);
265 if(retval.code != RC_OK){
266 std::cerr <<"Error decoding RIC Control Request" << std::endl;
271 std::cout <<"++++++++ RECEIVED CONTROL REQUEST +++++++++++++++++++++++++++++" << std::endl;
272 xer_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
275 res = control_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, control_data);
277 std::cout <<"Error getting data from E2AP control request" << std::endl;
281 // Decode the X2AP PDU : directly embedded in Control Msg IE
283 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 );
284 if (retval.code != RC_OK){
285 std::cerr <<"Error decoding X2AP PDU in control request message of size " << control_data.control_msg_size << std::endl;
291 xer_fprint(stdout, &asn_DEF_X2N_X2AP_PDU, x2ap_pdu_recv);
292 std::cout <<"++++++++ RECEIVED CONTROL REQUEST +++++++++++++++++++++++++++++" << std::endl;
296 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 ){
299 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 ){
303 std::cerr <<"Unknown X2AP PDU : message type = " << x2ap_pdu_recv->present << std::endl;
307 // generate control ack ?
308 // control_data.control_status = 0;
309 // mlen = RMR_BUFFER_SIZE;
310 // res = control_resp.encode_e2ap_control_response(message->payload, &mlen, control_data, true);
313 // std::cerr <<"Error encoding control response ack. Reason = " << control_resp.get_error() << std::endl;
316 ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
317 ASN_STRUCT_FREE(asn_DEF_X2N_X2AP_PDU, x2ap_pdu_recv);
322 std::cerr <<"Error ! Unknown RMR message of type " << message->mtype << " received" << std::endl;
332 int main(int argc, char *argv[]){
334 char name[128] = "mock_subscription_mgr";
335 char port[16] = "tcp:4591";
336 double rate = 1; // default rate to send at
337 int verbose_flag = 0;
339 // Parse command line options
340 static struct option long_options[] =
342 /* Thse options require arguments */
343 {"name", required_argument, 0, 'n'},
344 {"port", required_argument, 0, 'p'},
345 {"rate", required_argument, 0, 'r'},
346 {"verbose", no_argument, &verbose_flag, 1},
353 int option_index = 0;
354 char c = getopt_long(argc, argv, "n:p:a:r:", long_options, &option_index);
363 /* An option flag was set.
364 Do nothing for now */
368 strcpy(name, optarg);
372 strcpy(port, optarg);
379 std::cerr <<"Error : Transmit rate must be >= 0/sec" << std::endl;
384 std::cerr <<"Error : maximum allowed rate = 1000/sec" << std::endl;
395 std::cout <<"Error ! " << std::endl;
401 int log_level = MDCLOG_WARN;
403 log_level = MDCLOG_INFO;
405 init_logger(name, static_cast<mdclog_severity_t>(log_level));
407 XaPP my_xapp = XaPP(name, port, 16384, 1);
408 my_xapp.Start(Message_Handler);
412 e2sm_indication e2sm_indication_obj;
417 //==== e2sm indication header : just some
418 e2sm_header_helper indication_header;
419 // random fill for now
420 indication_header.egNB_id="hello";
421 indication_header.plmn_id="there";
422 indication_header.interface_direction = 1;
423 indication_header.egNB_id_type = 2;
424 unsigned char buf_header[32];
425 size_t buf_header_size = 32;
427 res = e2sm_indication_obj.encode_indication_header(&buf_header[0], &buf_header_size, indication_header);
429 std::cout <<"Error encoding indication header. Reason = " << e2sm_indication_obj.get_error() << std::endl;
433 //====== x2ap sgnb addition request created by us
434 unsigned char x2ap_buf[1024];
435 size_t x2ap_buf_size = 1024;
436 pfile = fopen(X2_SGNB_ADDITION_REQUEST, "r");
438 std::cerr <<"Error ! Could not find test per file " << X2_SGNB_ADDITION_REQUEST << std::endl;
442 x2ap_buf_size = fread((char *)x2ap_buf, sizeof(char), 1024, pfile);
446 //==== e2ap indication for generated x2ap pdus
447 ric_indication_helper dinput ;
448 dinput.action_id = 100;
450 dinput.indication_sn = 100;
452 dinput.req_seq_no = 11;
456 /* encoding pdu put here */
457 size_t data_size = 16384;
458 unsigned char data[data_size];
460 ric_indication indication_pdu;
463 // prepare packet to send. we send
464 // same packet every time for now
465 dinput.indication_header = buf_header;
466 dinput.indication_header_size = buf_header_size;
467 dinput.indication_msg = x2ap_buf;
468 dinput.indication_msg_size = x2ap_buf_size;
469 dinput.indication_type = 1; // for now always ask for control back
470 res = indication_pdu.encode_e2ap_indication(&data[0], &data_size, dinput);
472 std::cout <<"Error encoding E2AP Indication PDU. Reason = " << indication_pdu.get_error().c_str() << std::endl;
477 //Register signal handler to stop
478 signal(SIGINT, EndProgram);
479 signal(SIGTERM, EndProgram);
481 unsigned long int interval = 0;
484 interval = 1000.0/rate;
490 auto start_time = std::chrono::steady_clock::now();
496 if ( subscription_active && rate > 0 ){
497 my_xapp.Send(RIC_INDICATION, data_size, data);
501 std::this_thread::sleep_for(std::chrono::milliseconds(interval));
506 auto end_time = std::chrono::steady_clock::now();
507 double duration = std::chrono::duration_cast<std::chrono::seconds>(end_time - start_time).count();
509 std::cout <<"Number of SgNB Addition Request (in E2AP Indication) sent = " << num_indications << std::endl;
510 std::cout <<"Number of control responses received = " << num_controls << std::endl;
511 std::cout <<"Number of SgNB Addition Acknowledges = " << num_accepts << std::endl;
512 std::cout <<"NUmber of SgNB Addition Rejects = " << num_rejects << std::endl;
513 std::cout <<"Number of E2AP control requests we could not decode = " << num_errors << std::endl;
515 std::cout <<"Duration = " << duration << " E2AP Indication Tx Rate = " << num_indications/duration << std::endl;
518 std::cout <<"Stopped RMR thread .." << std::endl;