Updating E2sim Code to support Multiple E2sim 56/6456/1
authorhimeshshukla <himesh.s@hcl.com>
Thu, 1 Jul 2021 14:13:01 +0000 (19:43 +0530)
committerhimeshshukla <himesh.s@hcl.com>
Thu, 1 Jul 2021 14:13:01 +0000 (19:43 +0530)
Issue-ID: RIC-743

Updating the E2simulator code to support multiple E2sim
instances

Signed-off-by: himeshshukla <himesh.s@hcl.com>
Change-Id: I299822fc8ce00d146068709a983238858c5e7892

16 files changed:
ric_benchmarking/README
ric_benchmarking/e2-interface/e2sim/docker/container-tag.yaml
ric_benchmarking/e2-interface/e2sim/e2sm_examples/kpm_e2sm/Dockerfile
ric_benchmarking/e2-interface/e2sim/e2sm_examples/kpm_e2sm/e2sim-dev_1.0.0_amd64.deb
ric_benchmarking/e2-interface/e2sim/e2sm_examples/kpm_e2sm/e2sim_1.0.0_amd64.deb
ric_benchmarking/e2-interface/e2sim/e2sm_examples/kpm_e2sm/helm/values.yaml
ric_benchmarking/e2-interface/e2sim/e2sm_examples/kpm_e2sm/src/kpm/encode_kpm.cpp
ric_benchmarking/e2-interface/e2sim/e2sm_examples/kpm_e2sm/src/kpm/kpm_callbacks.cpp
ric_benchmarking/e2-interface/e2sim/e2sm_examples/kpm_e2sm/src/kpm/kpm_callbacks.hpp
ric_benchmarking/e2-interface/e2sim/src/DEF/e2sim_defs.cpp
ric_benchmarking/e2-interface/e2sim/src/DEF/e2sim_defs.h
ric_benchmarking/e2-interface/e2sim/src/SCTP/e2sim_sctp.cpp
ric_benchmarking/e2-interface/e2sim/src/base/e2sim.cpp
ric_benchmarking/e2-interface/e2sim/src/base/e2sim.hpp
ric_benchmarking/e2-interface/e2sim/src/encoding/encode_e2apv1.cpp
ric_benchmarking/e2-interface/e2sim/src/encoding/encode_e2apv1.hpp

index ec33208..ce81bb6 100644 (file)
@@ -38,7 +38,9 @@ Testing:
 To test the bouncer xapp, E2simulator is required to be build and run.
 1. Take the E2simulator code under RIC-Benchmarking/E2-interface.
 2. Run/Restart the Near RT RIC Platform pods.
-3. Run E2sim Pod using helm chart( build e2sim using docker file available in e2-interface/e2sim/e2sm_examples/kpm_e2sm/Dockerfile)
+3. Run E2sim Pod using helm chart( build e2sim using docker file available in e2-interface/e2sim/e2sm_examples/kpm_e2sm/Dockerfile). For Multiple E2sim instances update the Dockerfile(e2-interface/e2sim/e2sm_examples/kpm_e2sm/Dockerfile) with the number of instances.
+  For example: ./kpm_sim 192.168.122.66 32222 10 
+  where 10 = no of instances of E2sim     
 4. Deploy bouncer xapp by following the xapp onboarding steps
 
 Login to the bouncer xapp and E2sim Pods using kubectl exec to see the benchmarking timestamp.
index b8c119c..59ed72b 100644 (file)
@@ -31,7 +31,7 @@
 
 # the builder has: git, wget, cmake, gcc/g++, make, python2/3. v7 dropped nng support
 #
-FROM nexus3.o-ran-sc.org:10004/o-ran-sc/bldr-ubuntu18-c-go:9-u18.04 as buildenv
+FROM nexus3.o-ran-sc.org:10002/o-ran-sc/bldr-ubuntu18-c-go:1.9.0 as buildenv
 
 # spaces to save things in the build image to copy to final image
 RUN mkdir -p /playpen/assets /playpen/src /playpen/bin
@@ -69,6 +69,8 @@ RUN apt-get update \
        vim \
        tcpdump \
        net-tools \
+        libncurses5-dev \
+        libncursesw5-dev \
        nmap \
   && apt-get clean
 
@@ -101,4 +103,4 @@ RUN cd /playpen/src && \
        make install
 
 
-CMD kpm_sim 192.168.122.66 32222
+CMD kpm_sim 192.168.122.66 32222 
index 9d7464b..bba627e 100644 (file)
Binary files a/ric_benchmarking/e2-interface/e2sim/e2sm_examples/kpm_e2sm/e2sim-dev_1.0.0_amd64.deb and b/ric_benchmarking/e2-interface/e2sim/e2sm_examples/kpm_e2sm/e2sim-dev_1.0.0_amd64.deb differ
index 151b708..3c2a21e 100644 (file)
Binary files a/ric_benchmarking/e2-interface/e2sim/e2sm_examples/kpm_e2sm/e2sim_1.0.0_amd64.deb and b/ric_benchmarking/e2-interface/e2sim/e2sm_examples/kpm_e2sm/e2sim_1.0.0_amd64.deb differ
index 751cda5..428d7e0 100644 (file)
@@ -25,9 +25,9 @@ e2sim:
     app: e2simulator
     imagepullpolicy: IfNotPresent
     image:
-      name: oran-ric/e2simul
-      tag: 1.2.2     
-      registry: "oran.nexus:8082"
+      name: oran-ric/e2simulator
+      tag: 2.0.0   
+      registry: "nexus3.o-ran-sc.org:10002"
     port: 36422
 
     privilegedmode: false
index 6981454..9604fa2 100644 (file)
@@ -28,7 +28,7 @@ using namespace std;
 
 void encode_kpm_function_description(E2SM_KPM_RANfunction_Description_t* ranfunc_desc) {
 
-  printf("kpm0\n");
// printf("kpm0\n");
 
   uint8_t *buf = (uint8_t*)"ORAN-E2SM-KPM";
   uint8_t *buf2 = (uint8_t*)"KPM monitor";
@@ -51,14 +51,14 @@ void encode_kpm_function_description(E2SM_KPM_RANfunction_Description_t* ranfunc
   ranfunc_desc->ranFunction_Name.ranFunction_Description.size = strlen((char*)buf2);
   ranfunc_desc->ranFunction_Name.ranFunction_Instance = &inst;
 
-  printf("kpm0.9\n");
+  //printf("kpm0.9\n");
 
   //  ranfunc_desc->ranFunction_Name.ranFunction_E2SM_OID = (OCTET_STRING_t*)calloc(1, sizeof(OCTET_STRING_t));
   ranfunc_desc->ranFunction_Name.ranFunction_E2SM_OID.buf = (uint8_t*)calloc(1,strlen((char*)buf3));
   memcpy(ranfunc_desc->ranFunction_Name.ranFunction_E2SM_OID.buf, buf3, strlen((char*)buf3));
   ranfunc_desc->ranFunction_Name.ranFunction_E2SM_OID.size = strlen((char*)buf3);
 
-  printf("kpm2\n");
// printf("kpm2\n");
   
 
   RIC_EventTriggerStyle_List_t *trigger_style =
@@ -71,20 +71,20 @@ void encode_kpm_function_description(E2SM_KPM_RANfunction_Description_t* ranfunc
   trigger_style->ric_EventTriggerStyle_Name.size = strlen((char*)buf4);
   trigger_style->ric_EventTriggerFormat_Type = 5;
 
-  printf("kpm3\n");
+  //printf("kpm3\n");
 
   ranfunc_desc->e2SM_KPM_RANfunction_Item.ric_EventTriggerStyle_List =
     (E2SM_KPM_RANfunction_Description::E2SM_KPM_RANfunction_Description__e2SM_KPM_RANfunction_Item::E2SM_KPM_RANfunction_Description__e2SM_KPM_RANfunction_Item__ric_EventTriggerStyle_List*)calloc(1,sizeof(E2SM_KPM_RANfunction_Description::E2SM_KPM_RANfunction_Description__e2SM_KPM_RANfunction_Item::E2SM_KPM_RANfunction_Description__e2SM_KPM_RANfunction_Item__ric_EventTriggerStyle_List));
 
   int ret = ASN_SEQUENCE_ADD(&ranfunc_desc->e2SM_KPM_RANfunction_Item.ric_EventTriggerStyle_List->list , trigger_style);
-  printf("ret is %d\n", ret);
+  //printf("ret is %d\n", ret);
 
   RIC_ReportStyle_List_t *report_style1 = (RIC_ReportStyle_List_t*)calloc(1, sizeof(RIC_ReportStyle_List_t));
   report_style1->ric_ReportStyle_Type = 1;
 
   uint8_t *buf5 = (uint8_t*)"O-DU Measurement Container for the 5GC connected deployment";
 
-  printf("kpm4\n");  
// printf("kpm4\n");  
   
   //  report_style1->ric_ReportStyle_Name = (OCTET_STRING_t*)calloc(1, sizeof(OCTET_STRING_t));
   report_style1->ric_ReportStyle_Name.buf = (uint8_t*)calloc(1,strlen((char*)buf5));
@@ -93,7 +93,7 @@ void encode_kpm_function_description(E2SM_KPM_RANfunction_Description_t* ranfunc
   report_style1->ric_IndicationHeaderFormat_Type = 1;
   report_style1->ric_IndicationMessageFormat_Type = 1;
   
-  printf("kpm5\n");  
// printf("kpm5\n");  
 
   RIC_ReportStyle_List_t *report_style2 = (RIC_ReportStyle_List_t*)calloc(1, sizeof(RIC_ReportStyle_List_t));
   report_style2->ric_ReportStyle_Type = 2;
@@ -109,7 +109,7 @@ void encode_kpm_function_description(E2SM_KPM_RANfunction_Description_t* ranfunc
   report_style2->ric_IndicationHeaderFormat_Type = 1;
   report_style2->ric_IndicationMessageFormat_Type = 1;
 
-  printf("kpm6\n");  
// printf("kpm6\n");  
 
   RIC_ReportStyle_List_t *report_style3 = (RIC_ReportStyle_List_t*)calloc(1, sizeof(RIC_ReportStyle_List_t));
   report_style3->ric_ReportStyle_Type = 3;
@@ -171,7 +171,7 @@ void encode_kpm_function_description(E2SM_KPM_RANfunction_Description_t* ranfunc
   ASN_SEQUENCE_ADD(&ranfunc_desc->e2SM_KPM_RANfunction_Item.ric_ReportStyle_List->list, report_style5);
   ASN_SEQUENCE_ADD(&ranfunc_desc->e2SM_KPM_RANfunction_Item.ric_ReportStyle_List->list, report_style6);
 
-  xer_fprint(stderr, &asn_DEF_E2SM_KPM_RANfunction_Description, ranfunc_desc);
+  //xer_fprint(stderr, &asn_DEF_E2SM_KPM_RANfunction_Description, ranfunc_desc);
 }
 
 void encode_kpm_ocuup_user_level(RAN_Container_t *ranco) {
index c0d94b1..ed59ffa 100644 (file)
@@ -22,7 +22,7 @@
 #include <fstream>
 #include <vector>
 #include <unistd.h>
-
+#include <curses.h> 
 
 extern "C" {
   #include "OCUCP-PF-Container.h"
@@ -50,7 +50,7 @@ extern "C" {
 
 #include <nlohmann/json.hpp>
 #include <thread>
-
+#include <pthread.h>
 
 using json = nlohmann::json;
 
@@ -60,9 +60,28 @@ class E2Sim;
 
 E2Sim e2sim;
 
-int main(int argc, char* argv[]) {
+struct args {
+
+    int args1;
+    //char **args2;
+    char** args2;
+    int plmnId;
+
+};
+
+
+//int main(int argc, char* argv[]) {
+
+void *initparam(void *input){  
+  fprintf(stderr, "Starting KPM processor sim\n");
+
+  //struct args *value1 = (struct args *)malloc(sizeof(struct args));
+  //fprintf(stderr,"ip address at initparam :%s port:%s\n",(char *)input->args2[1],(char *)input->args2[2]);
+  //struct args *value1 = (struct args *)input;
+ // value1 = (struct args *)input;
+  struct args *value1 = ( args *) input;
+  //fprintf(stderr,"ip address at initparam :%s port:%s\n",value1->args2[1],value1->args2[2]);
 
-  fprintf(stderr, "Starting KPM processor sim");
 
   asn_codec_ctx_t *opt_cod;
 
@@ -94,7 +113,7 @@ int main(int argc, char* argv[]) {
   memcpy(ranfunc_ostr->buf,e2smbuffer,er.encoded);
 
   printf("!!!lenth of ranfuncdesc is %d\n", strlen((char*)ranfuncdesc));
-  printf("value of this index is %d\n", ranfuncdesc[0]);
+/*  printf("value of this index is %d\n", ranfuncdesc[0]);
   printf("value of this index is %d\n", ranfuncdesc[1]);
   printf("value of this index is %d\n", ranfuncdesc[2]);
   printf("value of this index is %d\n", ranfuncdesc[3]);
@@ -105,12 +124,78 @@ int main(int argc, char* argv[]) {
   printf("value of this index is %d\n", ranfuncdesc[15]);
   printf("value of this index is %d\n", ranfuncdesc[100]);
   printf("value of this index is %d\n", ranfuncdesc[101]);
-  
+  */
   e2sim.register_e2sm(0,ranfunc_ostr);
   e2sim.register_subscription_callback(0,&callback_kpm_subscription_request);
+  
+  fprintf(stderr,"ip address at run loop call:%s port:%s\n",value1->args2[1],value1->args2[2]);
+  e2sim.run_loop(value1->args1,value1->args2,value1->plmnId);//(argc, argv);
+
+}
 
-  e2sim.run_loop(argc, argv);
 
+int main(int argc, char  **argv) {
+       
+        struct args *value = (struct args *)malloc(sizeof(struct args));
+        value->args1  = argc;
+       value->args2  = argv;
+//     printf("Enter number of e2sim\n");
+//     int num_of_e2sim = getch();
+        value->plmnId = 1;
+       //int plmnid = 1;
+
+       int num_of_e2sim;
+       if (value->args2[3] != NULL)
+       {
+               num_of_e2sim = atoi(value->args2[3]);//500;
+               fprintf(stderr,"number of e2sim : %d\n", num_of_e2sim);
+       } 
+
+       else
+       {
+               num_of_e2sim = 1;
+       }
+       //int num_of_e2sim = atoi(value->args2[3]);//500;
+
+       //options_t read_input_options(int argc, char* argv[]);
+
+       fprintf(stderr,"value of thread id is %d\n", num_of_e2sim);
+
+       fprintf(stderr,"argc : %d ,ip address:%s, port:%s\n", value->args1,value->args2[1], value->args2[2]); 
+
+       pthread_t threads[10000];
+       int retvalue;
+       int i;
+        for( i = 0; i < num_of_e2sim; i++ ) {
+             
+            //struct args *value = (struct args *)malloc(sizeof(struct args)); 
+            
+             
+             //struct args *value = (struct args *)malloc(sizeof(struct args));
+             //value->args1  = argc;
+             //value->args2  = argv;
+            //value->plmnId = plmnid;
+
+               
+            fprintf(stderr,"\n****************************************************************************************************\n");        
+            //fprintf(stderr,"argc: %d, argv ip address is:%s,argv  port:%s\n",argc, argv[1],argv[2]);
+
+            fprintf(stderr,"value of thread id is %d\n", i);
+            fprintf(stderr,"value of plmn   id is %d\n", value->plmnId);
+            fprintf(stderr,"ip address is:%s, port:%s\n", value->args2[1],value->args2[2]);
+             retvalue = pthread_create(&threads[i], NULL, initparam, (void *)value);
+            sleep(2);
+            value->plmnId++;
+         //   plmnid++;
+      
+             if (retvalue) {
+                 
+                fprintf(stderr,"Error:unable to create  thread, %d\n", retvalue);
+                 exit(-1);
+             }
+            
+       }
+   pthread_exit(NULL);
 }
 
 /*
@@ -128,7 +213,7 @@ void run_report_loop(long requestorId, long instanceId, long ranFunctionId, long
 
   long seqNum = 1;
 
-  int  maxInd = 1000; //1000 no of indication to  send
+  int  maxInd = 1;//500; //1000 no of indication to  send
   
   simfile.open("simulation.txt", ios::in);
 
index 13b12d3..cecdf92 100644 (file)
@@ -16,9 +16,9 @@
 #                                                                            *
 ******************************************************************************/
 
-
 #include "e2sim.hpp"
 
 void callback_kpm_subscription_request(E2AP_PDU_t *pdu);
 
 void run_report_loop(long requestorId, long instanceId, long ranFunctionId, long actionId);
+
index f1730d3..42bc471 100644 (file)
@@ -95,11 +95,26 @@ options_t read_input_options(int argc, char *argv[])
 
   options.server_ip         = (char*)DEFAULT_SCTP_IP;
   options.server_port       = X2AP_SCTP_PORT;
+  options.num_of_e2sim      = 1;
 
-  if(argc == 3) //user provided IP and PORT
+  if(argc == 4) //user provided IP, PORT and number of e2sim
+  {
+    options.server_ip    = argv[1];
+    options.server_port  = atoi(argv[2]);
+    options.num_of_e2sim = atoi(argv[3]);
+    printf("options.server_ip:%s\n", options.server_ip);
+    if(options.server_port < 1 || options.server_port > 65535) {
+      LOG_E("Invalid port number (%d). Valid values are between 1 and 65535.\n",
+                                  options.server_port);
+      exit(1);
+    }
+  }
+  else if(argc == 3) //user provided IP and PORT
   {
     options.server_ip = argv[1];
     options.server_port = atoi(argv[2]);
+    printf("options.server_ip:%s\n", options.server_ip);
+    
     if(options.server_port < 1 || options.server_port > 65535) {
       LOG_E("Invalid port number (%d). Valid values are between 1 and 65535.\n",
                                   options.server_port);
index cf4a0d6..1c6cea5 100644 (file)
@@ -55,6 +55,7 @@ typedef struct {
 typedef struct {
   char* server_ip;
   int   server_port;
+  int   num_of_e2sim; //sriram
   //... extend as needed
 } options_t;
 
index 51bb8a7..6cf32ad 100644 (file)
@@ -112,7 +112,7 @@ int sctp_start_server(const char *server_ip_str, const int server_port)
   return server_fd;
 }
 
-int sctp_start_client(const char *server_ip_str, const int server_port)
+/*int sctp_start_client(const char *server_ip_str, const int server_port)
 {
   int client_fd, af;
 
@@ -195,6 +195,68 @@ int sctp_start_client(const char *server_ip_str, const int server_port)
 
   return client_fd;
 }
+*/
+int sctp_start_client(const char *server_ip_str, const int server_port)
+{
+  int client_fd, af;
+
+  struct sockaddr* server_addr;
+  size_t addr_len;
+
+  struct sockaddr_in  server4_addr;
+  memset(&server4_addr, 0, sizeof(struct sockaddr_in));
+
+  struct sockaddr_in6 server6_addr;
+  memset(&server6_addr, 0, sizeof(struct sockaddr_in6));
+
+  inet_pton(AF_INET, server_ip_str, &server4_addr.sin_addr); 
+    server4_addr.sin_family = AF_INET;
+    server4_addr.sin_port   = htons(server_port);
+    server_addr = (struct sockaddr*)&server4_addr;
+    addr_len    = sizeof(server4_addr);
+
+  if((client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) == -1)
+  {
+     perror("socket");
+     exit(1);
+  }
+
+  // int sendbuff = 10000;
+  // socklen_t optlen = sizeof(sendbuff);
+  // if(getsockopt(client_fd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen) == -1) {
+  //   perror("getsockopt send");
+  //   exit(1);
+  // }
+  // else
+  //   LOG_D("[SCTP] send buffer size = %d\n", sendbuff);
+
+  //--------------------------------
+  //Bind before connect
+  auto optval = 1;
+  if( setsockopt(client_fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof optval) != 0 ){
+    perror("setsockopt port");
+    exit(1);
+  }
+
+  if( setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) != 0 ){
+    perror("setsockopt addr");
+    exit(1);
+  }
+
+  // end binding ---------------------
+
+  LOG_I("[SCTP] Connecting to server at %s:%d ...", server_ip_str, server_port);
+  if(connect(client_fd, server_addr, addr_len) == -1) {
+    perror("connect");
+    exit(1);
+  }
+  assert(client_fd != 0);
+
+  LOG_I("[SCTP] Connection established");
+
+  return client_fd;
+}
+
 
 int sctp_accept_connection(const char *server_ip_str, const int server_fd)
 {
index 5aa0aeb..3186f02 100644 (file)
@@ -153,9 +153,9 @@ void E2Sim::generate_e2apv1_indication_request_parameterized(E2AP_PDU *e2ap_pdu,
 
 }
 
-int E2Sim::run_loop(int argc, char* argv[]){
+int E2Sim::run_loop(int argc, char* argv[], int plmnId){
 
-  printf("Start E2 Agent (E2 Simulator\n");
+  printf("Start E2 Agent (E2 Simulator)\n");
 
   ifstream simfile;
   string line;
@@ -174,6 +174,8 @@ int E2Sim::run_loop(int argc, char* argv[]){
 
   bool xmlenc = false;
 
+  printf("ip address is:%s\n",argv[1]);
+
   options_t ops = read_input_options(argc, argv);
 
   printf("After reading input options\n");
@@ -202,10 +204,15 @@ int E2Sim::run_loop(int argc, char* argv[]){
   }
     
   printf("about to call setup request encode\n");
-  
-  generate_e2apv1_setup_request_parameterized(pdu_setup, all_funcs);
 
-  printf("After generating e2setup req\n");
+  //int plmnid = plmnId; 
+  fprintf(stderr, "plmn id is : %d\n",plmnId);
+
+  generate_e2apv1_setup_request_parameterized(pdu_setup, all_funcs,plmnId);
+  //generate_e2apv1_setup_request_parameterized(pdu_setup, all_funcs);
+
+  fprintf(stderr,"After generating e2setup req\n");
 
   xer_fprint(stderr, &asn_DEF_E2AP_PDU, pdu_setup);
 
index eace5a8..0bb1acd 100644 (file)
@@ -55,7 +55,9 @@ public:
   
   void encode_and_send_sctp_data(E2AP_PDU_t* pdu);
 
-  int run_loop(int argc, char* argv[]);
+  //int run_loop(int argc, char* argv[]);
+  int run_loop(int argc, char* argv[], int plmnId);
+
 
 };
 
index 5529e72..a2e3cc3 100644 (file)
@@ -156,7 +156,7 @@ void encoding::generate_e2apv1_service_update(E2AP_PDU_t *e2ap_pdu, std::vector<
   e2ap_pdu->choice.initiatingMessage = initiatingMessage;
 }
 
-void encoding::generate_e2apv1_setup_request_parameterized(E2AP_PDU_t *e2ap_pdu, std::vector<ran_func_info> all_funcs) {
+void encoding::generate_e2apv1_setup_request_parameterized(E2AP_PDU_t *e2ap_pdu, std::vector<ran_func_info> all_funcs, int plmnId) {
   //                                            long ranFunctionId, uint8_t *ranFuncDescEncoded, int ranFuncLength) {
 
   //  uint8_t *buf = (uint8_t *)"gnb1"
@@ -171,7 +171,15 @@ void encoding::generate_e2apv1_setup_request_parameterized(E2AP_PDU_t *e2ap_pdu,
 
   gnb_bstring->bits_unused = 3;
 
-  uint8_t *buf2 = (uint8_t *)"747";
+  //uint8_t *buf2 = (uint8_t *)"747";
+  
+  char buff[16];
+  sprintf(buff,"%d",plmnId);
+  const char* plmnvalue=buff;
+
+  uint8_t *buf2 = (uint8_t *)plmnvalue;//"747";
+
+
   OCTET_STRING_t *plmn = (OCTET_STRING_t*)calloc(1, sizeof(OCTET_STRING_t));
   plmn->buf = (uint8_t*)calloc(1,3);
   memcpy(plmn->buf, buf2, 3);
index 6bbbe56..a054adf 100644 (file)
@@ -43,7 +43,7 @@ namespace encoding {
   
   void buildSubsReq(E2AP_PDU_t *pdu);
   
-  void generate_e2apv1_setup_request_parameterized(E2AP_PDU_t *setup_req_pdu, std::vector<ran_func_info> all_funcs);
+  void generate_e2apv1_setup_request_parameterized(E2AP_PDU_t *setup_req_pdu, std::vector<ran_func_info> all_funcs, int plmnId);
   
   void generate_e2apv1_setup_response(E2AP_PDU_t *setup_resp_pdu);