3224758b3ea4957654890bc68bfffa8b99bf3a93
[ric-app/admin.git] / test / mock_e2term_server.cc
1 /*==================================================================================
2
3         Copyright (c) 2018-2019 AT&T Intellectual Property.
4
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
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
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 ==================================================================================
17 */
18
19 /* Author : Ashwin Sridharan
20    Date   : Feb 2019
21 */
22
23
24 /* 
25
26    A mock e2term for testing 
27    -- accepts a subscription request 
28   -- accepts a delete subscription request
29   
30
31   -- when subscription is active,  sends out indication messages with X2AP SgNBAdditionRequest at specified rate
32      and monitors control request
33
34   -- when delete is requested, stops sending ...
35   
36
37 */
38
39
40 #include <string.h>
41 #include <stdio.h>
42 #include <iostream>
43 #include <fstream>
44 #include <csignal>
45 #include <chrono>
46 #include <fstream>
47 #include <xapp_utils.hpp>
48 #include <getopt.h>
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>
55
56 #include <e2sm.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>
62
63
64
65
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;
71
72 bool verbose_flag = false;
73 bool RunProgram = true;
74 bool subscription_active = false;
75 int action_type = E2N_RICindicationType::E2N_RICindicationType_report;
76
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"};
79
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;
87 }
88
89 void EndProgram(int signum){
90   std::cout <<"Signal received. Stopping program ....." << std::endl;
91   RunProgram = false;
92 }
93
94 bool  Message_Handler(rmr_mbuf_t *message){
95
96   bool res;
97   int i;
98   unsigned char meid[32];
99   unsigned char src[32];
100   
101   subscription_helper he;
102   subscription_response_helper he_resp;
103   
104   subscription_request sub_req;
105   subscription_response sub_resp;
106
107   subscription_delete sub_del_req;
108   subscription_delete_response sub_del_resp;
109   
110   ric_control_request control_req;
111   ric_control_response control_resp;
112   ric_control_helper  control_data;
113
114   e2sm_control e2sm_control_proc;
115   
116   asn_dec_rval_t retval;
117   size_t mlen;
118   
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;
123
124   bool send_msg = true;
125   
126   rmr_get_meid(message, meid);
127   rmr_get_src(message, src);
128   
129   switch(message->mtype){
130   case RIC_SUB_REQ:
131     
132     std::cout <<"*** Received message from src = " << src  << " for gNodeB = " << meid << " of size = " << message->len  << " and type = " << message->mtype << std::endl;
133     
134     e2ap_pdu_recv = 0;
135     retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len);
136
137     if(retval.code == RC_OK){
138       he.clear();
139       sub_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, he);
140     }
141     else{
142       std::cerr <<"Error decoding E2AP Subscription response PDU. Reason = " << strerror(errno) << std::endl;
143       send_msg = false;
144       goto finished_sub_req;
145
146     }
147
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);
150
151
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;
156     
157     // decode the event trigger ...
158     {
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;
164         send_msg = false;
165         goto finished_sub_req;
166       }
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;
170       
171     }
172     
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());
176     i = 0;
177
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);
184       
185       i++;
186     }
187     mlen = RMR_BUFFER_SIZE;
188
189     res = sub_resp.encode_e2ap_subscription_response(&message->payload[0], &mlen,  he_resp, true);
190     if (!res){
191       std::cerr << "Error encoding subscription response successful. Reason = " << sub_resp.get_error() << std::endl;
192       send_msg = false;
193       goto finished_sub_req;
194     }
195     message->mtype = RIC_SUB_RESP;
196     subscription_active = true;
197     
198     
199   finished_sub_req:
200     ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
201     ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event);
202     if(send_msg){
203       message->len = mlen;
204       
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;
208       return true;
209     }
210     else{
211       break;
212     }
213     
214   case RIC_SUB_DEL_REQ:
215
216     e2ap_pdu_recv = 0;
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){
219       he.clear();
220       sub_del_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, he);
221     }
222     else{
223       std::cerr <<"Error decoding E2AP Subscription Delete Request PDU. Reason = " << strerror(errno) << std::endl;
224       send_msg = false;
225       goto finished_sub_del;
226     }
227
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;
231
232     // FILE *pfile;
233     // pfile = fopen("subscription_delete.per", "wb");
234     // fwrite(message->payload, 1, message->len, pfile);
235     // fclose(pfile);
236     
237     // set up response object
238     std::cout <<"Generating response ...." << std::endl;
239     he_resp.clear();
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);
244     if (!res){
245       std::cerr << "Error encoding subscription delete  response failure . Reason = " << sub_resp.get_error() << std::endl;
246       send_msg = false;
247       goto finished_sub_del;
248     }
249
250   finished_sub_del:
251     ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
252     
253     if(send_msg){
254       message->mtype = RIC_SUB_DEL_RESP;
255       message->len = mlen;
256       subscription_active = false;
257       return true;
258     }
259     else{
260       break;
261     }
262     
263   case RIC_CONTROL_REQ:
264     num_controls ++;
265     e2ap_pdu_recv = 0;
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;
269       goto finished_ctrl;
270     }
271     
272     if (verbose_flag){
273       std::cout <<"++++++++ RECEIVED CONTROL REQUEST +++++++++++++++++++++++++++++" << std::endl;
274       xer_fprint(stdout,  &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
275     }
276     
277     res = control_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, control_data);
278     if(!res){
279       std::cout <<"Error getting data from E2AP control request" << std::endl;
280       break;
281     }
282
283     // Decode the X2AP PDU : directly embedded in Control Msg IE
284     x2ap_pdu_recv = 0;
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;
288       num_errors ++;
289       goto finished_ctrl;
290     }
291     
292     if(verbose_flag){
293       xer_fprint(stdout, &asn_DEF_X2N_X2AP_PDU, x2ap_pdu_recv);
294       std::cout <<"++++++++ RECEIVED CONTROL REQUEST +++++++++++++++++++++++++++++" << std::endl;
295       
296     }
297
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 ){
299       num_accepts ++;
300     }
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 ){
302       num_rejects ++;
303     }
304     else{
305       std::cerr <<"Unknown X2AP PDU : message type = " << x2ap_pdu_recv->present << std::endl;
306     }
307
308     
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);
313
314     // if (!res){
315     //   std::cerr <<"Error encoding control response ack. Reason = " << control_resp.get_error() << std::endl;
316     // }
317   finished_ctrl:
318     ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
319     ASN_STRUCT_FREE(asn_DEF_X2N_X2AP_PDU, x2ap_pdu_recv);
320     
321     break;
322
323   default:
324     std::cerr <<"Error ! Unknown RMR message of type " << message->mtype << " received" << std::endl;
325     break;
326   }
327   
328   return false;
329 };
330
331
332
333
334 int main(int argc, char *argv[]){
335
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;
340   
341   // Parse command line options
342   static struct option long_options[] =
343     {
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},
349
350     };
351
352
353    while(1) {
354
355         int option_index = 0;
356         char c = getopt_long(argc, argv, "n:p:a:r:", long_options, &option_index);
357         if(c == -1){
358             break;
359          }
360
361         switch(c)
362         {
363
364         case 0:
365           /* An option flag was set.
366              Do nothing for now */
367           break;
368           
369         case 'n':
370           strcpy(name, optarg);
371           break;
372           
373         case 'p':
374           strcpy(port, optarg);
375           break;
376           
377
378         case 'r':
379           rate = atof(optarg);
380           if (rate < 0){
381             std::cerr <<"Error : Transmit rate must be >= 0/sec" << std::endl;
382             exit(-1);
383           }
384           
385           if (rate > 1000){
386             std::cerr <<"Error : maximum allowed rate = 1000/sec" << std::endl;
387             exit(-1);
388           }
389           break;
390           
391         case 'h':
392           usage(argv[0]);
393           exit(0);
394
395           
396         default:
397           std::cout <<"Error ! " << std::endl;
398           usage(argv[0]);
399           exit(1);
400         }
401    };
402
403    int log_level = MDCLOG_WARN;
404    if (verbose_flag){
405      log_level = MDCLOG_INFO;
406    }
407    init_logger(name, static_cast<mdclog_severity_t>(log_level));
408
409    XaPP my_xapp = XaPP(name, port, 16384);
410    my_xapp.StartThread(Message_Handler);
411
412    
413    
414    e2sm_indication e2sm_indication_obj;
415    bool res;
416    FILE *pfile;
417    
418
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;
428    
429    res = e2sm_indication_obj.encode_indication_header(&buf_header[0], &buf_header_size, indication_header);
430    if(!res){
431      std::cout <<"Error encoding indication header. Reason = " << e2sm_indication_obj.get_error() << std::endl;
432      exit(-1);
433    }
434
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));
438
439    assert(x2ap_bufs != 0);
440    assert(x2ap_buf_sizes != 0);
441    
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);
448      
449      pfile = fopen(x2ap_files[i].c_str(), "r");
450      if(pfile == NULL){
451        std::cerr <<"Error ! Could not find test per file " << x2ap_files[i] << std::endl;
452        exit(-1);
453      }
454      
455      fread((char *)x2ap_bufs[i], sizeof(char), x2ap_buf_sizes[i], pfile);
456      fclose(pfile);
457    }
458    
459    //==== e2ap indication for generated x2ap pdus
460    ric_indication_helper dinput ;   
461    dinput.action_id = 100;
462    dinput.func_id = 10;
463    dinput.indication_sn = 100;
464    dinput.req_id = 6;
465    dinput.req_seq_no = 11;
466
467    
468
469    /* encoding pdu put here */
470    size_t data_size = 16384;
471    unsigned char data[data_size];
472    
473    ric_indication indication_pdu;
474    
475
476    dinput.indication_header = buf_header;
477    dinput.indication_header_size = buf_header_size;
478     
479
480    //Register signal handler to stop 
481    signal(SIGINT, EndProgram);
482    signal(SIGTERM, EndProgram);
483
484    unsigned long int interval = 0;
485
486    if (rate > 0){
487      interval = 1000.0/rate;
488    }
489    else{
490      interval = 10;
491    }
492    
493    auto start_time = std::chrono::steady_clock::now();
494    int count = 0;
495
496    int packet_index = 0;
497    while(RunProgram){
498
499      if ( subscription_active && rate > 0 ){
500        my_xapp.Send(RIC_INDICATION, data_size, data);
501        num_indications ++;
502      
503
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);
509        if (!res){
510          std::cout <<"Error encoding E2AP Indication PDU. Reason = " << indication_pdu.get_error().c_str() <<  std::endl;
511          exit(-1);
512        }
513        packet_index ++;
514        packet_index = packet_index % x2ap_files.size();
515      }
516      
517      std::this_thread::sleep_for(std::chrono::milliseconds(interval));
518      count ++;
519    }
520    
521    
522    auto end_time = std::chrono::steady_clock::now();
523    double  duration = std::chrono::duration_cast<std::chrono::seconds>(end_time - start_time).count();
524
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;
530    
531    std::cout <<"Duration = " << duration  << " E2AP Indication Tx Rate = " << num_indications/duration << std::endl;
532    my_xapp.Stop();
533
534    std::cout <<"Stopped RMR thread .." << std::endl;
535    return 0;
536       
537
538 };
539
540
541
542
543
544