Skip to main content

C SDK Signatures

xApp configuration

Support .conf file for xApp configuration with the following information.

General configuration

  • Mandatory setting of xApp
# Set your SM directory path
SM_DIR = "/usr/local/lib/flexric/"

Name = "xApp"
NearRT_RIC_IP = "127.0.0.1"
E42_Port = 36422
  • Setting of database
xApp_DB = {
enable = "OFF"
}

Note: assume we disable writing to database by default

Customized SMs' configuration

  • Supported options:
    • name : MAC, RLC, PDCP, GTP, SLICE
    • time : 1_ms, 2_ms, 5_ms, 10_ms, 100_ms, 1000_ms
  • Example:
Sub_CUST_SM_List = (
{ name = "MAC", time = "10_ms" },
{ name = "RLC", time = "100_ms" },
{ name = "PDCP", time = "1000_ms" }
)

O-RAN SMs' configuration

  • Supported options:
    • name : KPM, RC
    • time (ms): 1, 2, 5, 10, 100, 1000
      • Note: no need timer for RC Report Service , set as 0
    • format for action definition:
      • name = "KPM": 1, 4
      • name = "RC": 1
    • ran_type: ngran_gNB, ngran_gNB_CU, ngran_gNB_DU
  • Example:
# FOR EXAMPLE 
Sub_ORAN_SM_List = (
{ name = "RC", time = 0,
format = 1,
ran_type = "ngran_gNB",
actions = ( # 8.2.2 RAN Parameters for Report Service Style 2
{ id = 1 }, # Current UE ID
{ id = 6 }, # Cell Global ID
{ id = 21528 } # List of Neighbor cells
)
},
{ name = "KPM", time = 1000,
format = 4,
ran_type = "ngran_gNB_CU",
actions = (
{ name = "DRB.PdcpSduVolumeDL" }
)
}
)

Overview

Introducing C SDK signature functions that oversee the entire lifecycle of an xApp. The table below provides a brief description with the following item:

SignatureDescription
init_fr_args()Initialize the xApp configuration
init_xapp_api()Initializes the xApp and sends an E42-Setup-Request to NearRT-RIC based on the given configurations
e2_nodes_xapp_api()Get connected E2-Nodes' information (e.g., NodeB ID, RAN type and supported RAN functions, etc)
report_sm_xapp_api()Sends a RIC-Subscription-Request to subscribe the RAN function on the specific E2-Node via the service model
sm_cb_{SM-NAME}()A callback function of service model(s) for handling indication messages received by the xApp
control_sm_xapp_api()Sends a RIC-Conctrol-Request to the RAN function at the specific E2-Node via the service model
rm_report_sm_xapp_api()Sends a RIC-Delete-Subscription-Request to unsubscribes the subscribed RAN functions
try_stop_xapp_api()Terminate the xApp

Note: {SM-NAME} serves as a placeholder for the name of a specific service model, for example: if {SM-NAME} = kpm which stands for Key Performance Measurement service model, the function names will be sm_cb_kpm(). The supported {SM-NAME}s in C SDK include:

  • Customized service models: mac, rlc, pdcp, gtp, slice
  • O-RAN standardized service models: kpm, rc

Sequence Diagram

The following figures illustrates the sequence diagram of lifecycle in a Python xApp, including:

  1. Init: initialize xApp (from step 2 to 6)
  2. Report Service: subscribe RAN function via service model (from step 7 to 13)
  3. xApp Logic: store or process receiving data from RAN functions (from step 14 to 15)
  4. Control Service: control RAN function via service model (from step 16 to 20)
  5. Exit: terminate xApp (from step 21 to 26)

Detail of Signatures


Init - Step 2 to 6


init_fr_args()

  • Example:

    // Read xApp configuration file 
    fr_args_t args = init_fr_args(argc, argv);
    defer({ free_fr_args(&args); });
  • Input:

    ParameterType in CComment
    argcintThe count of command-line arguments
    argvchar* argv[]An array of strings holding the command-line arguments
  • Output:

    ParameterType in CComment
    argsfr_args_tArgument custom structure containing configuration properties

init_xapp_api()

  • Example:

    // Initialize xApp using the settings from configuration file
    init_xapp_api(&args);
  • Input:

    ParameterType in CComment
    &argsfr_args_t const*A consta struct containing parameters sourced from xapp.conf
  • Output: N/A



e2_nodes_xapp_api()

  • Example:

    // Get connected E2-Nodes
    e2_node_arr_t nodes = e2_nodes_xapp_api();
    defer({ free_e2_node_arr(&nodes); });

    // Case 1: if no E-Node connected, do no excuting xApp anymore
    assert(nodes.len > 0);

    # Case 2: if the number of connected E2-Nodes is greater than 0
    printf("Connected E2 nodes = %d\n", nodes.len);
  • Input: N/A

  • Output:

    ParameterType in CComment
    nodese2_node_arr_tA struct contains a array of E2-Nodes' information

Report service - Step 7 to 13


report_sm_xapp_api()

  • Example - Customized SMs

    // Define a handler as pointer to store the RIC Request ID
    sm_ans_xapp_t* cust_sm_handle = NULL;

    // Note: we assume the number of handler will be the same as the number of connected E2-Node,
    // therefore, we allocate the memory to the handler based on nodes.len
    cust_sm_handle = calloc(nodes.len, sizeof(sm_ans_xapp_t) );
    assert(cust_sm_handle != NULL);

    // Subscribe to all the connected E2-Nodes
    for (int i = 0; i < nodes.len; i++) {
    // Get the current E2-Node
    e2_node_connected_t* n = &nodes.n[i];

    // Get the supported RAN function's ID from the current E2-Node
    for (size_t j = 0; j < n->len_rf; j++) {
    printf("Registered node %d ran func id = %d \n ", i, n->ack_rf[j].id);

    // Get the current RAN functions's ID
    uint32_t rf_id = n->ack_rf[j].id;

    // Send subscription request to n by giving:
    // global E2-Node ID, service model's ID, transmission time intervale of indicaiton message, and defined callback function
    cust_sm_handle[i] = report_sm_xapp_api(n->id, sm_id, (void*)args.sub_cust_sm[j].time, sm_cb_{SM-NAME});
    assert(cust_sm_handle[i].success == true);
    }
    }
  • Input:

    ParameterType in CComment
    n->idglobal_e2_node_id_t*Stands for Global E2-Node ID
    rf_iduint32_tRAN function's ID
    (void*)args.sub_cust_sm[j].timevoid*Time duration of each RIC Indication read from xapp.conf
    sm_cb_{SM-NAME}sm_cbDefined callback function in xApp, e.g., sm_cb_mac
  • Output:

    ParameterType in CComment
    cust_sm_handle[i]intRIC Request ID
  • Example - O-RAN Standarized SM

    // Define a handler as pointer to store the RIC Request ID
    sm_ans_xapp_t* oran_sm_handle = NULL;

    // Note: we assume the number of handler will be the same as the number of connected E2-Node,
    // therefore, we allocate the memory to the handler based on nodes.len
    oran_sm_handle = calloc(nodes.len, sizeof(sm_ans_xapp_t) );
    assert(oran_sm_handle != NULL);

    // Subscribe to all the connected E2-Nodes
    for (int i = 0; i < nodes.len; i++) {
    // Get the current E2-Node
    e2_node_connected_t* n = &nodes.n[i];

    // Get the supported RAN function's ID from the current E2-Node
    for (size_t j = 0; j < n->len_rf; j++) {
    printf("Registered node %d ran func id = %d \n ", i, n->ack_rf[j].id);

    // Get the current RAN functions's ID
    uint32_t rf_id = n->ack_rf[j].id;

    // Generate subscription data based on the union type in sm_ag_if_wr_subs_t
    // Note: generate event trigger definition and action definition for KPM SM
    kpm_sub_data_t kpm_sub = {0}
    kpm_sub.ev_trg_def = gen_kpm_ev_trig()
    kpm_sub.sz_ad = 1;
    kpm_sub.ad = calloc(1, sizeof(kpm_act_def_t));
    kpm_sub.ad = gen_kpm_act()

    // Send subscription request to n by giving:
    // global E2-Node ID, service model's ID, subscription data, and defined callback function
    oran_sm_handle[i] = report_sm_xapp_api(n->id, sm_id, &kpm_sub, sm_cb_{SM-NAME});
    assert(oran_sm_handle[i].success == true);
    }
    }
  • Input:

    ParameterType in CComment
    n->idglobal_e2_node_id_t*Stands for Global E2-Node ID
    rf_iduint32_tRAN function's ID
    &kpm_subvoid*Subscription data including event trigger definition and action definition
    sm_cb_{SM-NAME}sm_cbDefined callback function in xApp, e.g., sm_cb_kpm
  • Output:

    ParameterType in CComment
    oran_sm_handle[i]intRIC Request ID

xApp Logic - Step 14 to 15


sm_cb_{SM-NAME}()

  • Example - Customized SM: {SM-NAME} = gtp

    // Define a callback function for GTP SM
    static void sm_cb_gtp(sm_ag_if_rd_t const* rd, global_e2_node_id_t const* e2_node)
    {
    // Use assert function to check the coming indication message is not NULL and its type is correct
    assert(rd != NULL);
    assert(rd->type == INDICATION_MSG_AGENT_IF_ANS_V0);
    assert(rd->ind.type == GTP_STATS_V0);

    // Get tstamp value stored in gtp_ind_data_t to calculate the one way latency of indication message
    int64_t now = time_now_us();
    printf("GTP ind_msg latency = %ld from E2-node type %d ID %d\n",
    now - rd->ind.gtp.msg.tstamp, e2_node->type, e2_node->nb_id.nb_id);
    }
  • Input:

    ParameterType in CComment
    rdsm_ag_if_rd_t const*A constant pointer to an received indication message
    e2_nodeglobal_e2_node_id_t const*A constant pointer to the global E2-Node ID, indicating the source E2-Node
  • Output: N/A

Note: Once the RIC Subscription Request is received by the E2-Node, the xApp will continue to receive RIC Indications forwarded from the C SDK. For further development (i.e., ML or AI usage), developers can process the received RIC Indications to analyze/optimize network performance.


Control Service - Step 16 to 20


control_sm_xapp_api()

  • Example - Customized SM: slice
  // Create slice control message by following the structure sm_ag_if_wr_t
sm_ag_if_wr_t ctrl_msg = fill_slice_sm_ctrl_req();

// Get the slice SM's ID
uint32_t rf_id = SM_SLICE_ID;

// Send control request to nodes.n[i] by giving:
// global E2-Node ID, SM's ID, and predefined contorl message
control_sm_xapp_api(&nodes.n[i].id, sm_id, &ctrl_msg_del);

// Deallocate the contorl message
free_slice_ctrl_msg(&ctrl_msg.ctrl.slice_req_ctrl.msg);
  • Input:

    ParameterType in CComment
    &nodes.n[i].idglobal_e2_node_id_t*Stands for Global E2-Node ID
    rf_iduint32_tRAN function's ID
    &ctrl_msgvoid*Control message written by xApp
  • Output: N/A


Exit - Step 21 to 26


rm_report_sm_xapp_api()

  • Example
  // Loop handler to send subcription delete request to each recorded RIC Request ID
// Note: we assume that we allocate the memory to sm_handle based on the length of connected E2-Node
for (int i = 0; i < nodes.len; ++i)
rm_report_sm_xapp_api(sm_handle[i].u.handle);

// Deallocate the handler
if (nodes.len > 0)
free(sm_handle);
  • Input:

    ParameterType in CComment
    sm_handle[i].u.handleintRIC Request ID
  • Output: N/A


try_stop_xapp_api()

  • Example:
  // Call the stop function every one second until it recevies a true value
bool ans = try_stop_xapp_api()
while(ans == false) {
usleep(1000);
ans = try_stop_xapp_api()
}
  • Input: N/A

  • Output: N/A

    ParameterType in CComment
    ansboolThe status of terminating an xApp: "TRUE" means the xApp has terminated completely, including freeing the memory; "FALSE" indicates the opposite.