[ORAN] FlexRIC Sevice Model (3): RIC 對應程式的修改
在完成 Service Model 的定義之後,
我們需要透過程式對所定義的 Service Model 進行操作,
考慮到 FlexRIC 的實作架構, 我們在修改 xApp 和 E2 Agent 的程式前,
要先修改 FlexRIC 相關的程式, 以提供 xApp 和 E2 Agent 串接的支援,
在此實作中, 我們以 Indication 作為開發的應用,
此應用中, xApp 負責送出訂閱 Indication 的需求,
E2 Agent 則將數值填入 Indication Message 中, 並定期發送.
在 FlexRIC 官方網站中, 提供教學的連結如下:
在 FlexRIC 中, 整體的資料交換流程如下:
- E2 Agent 透過 E2 Setup 向 FlexRIC 註冊 (ID, 以及所支援的服務)
- xApp 向 FlexRIC 進行註冊 (為自定義的 E42 介面)
- xApp 向 E2 Agent 註冊 Indication 服務 (Subscription Request)
- E2 Agent 根據訂閱的資訊以及時間間隔, 進行資料回報
- xApp 收到資料將數值存入 SQLite (不是標準的 O-RAN 流程, 在此先略去)
- xApp 向 E2 Agent 刪除 Indication 服務 (Subscription Delete Request)
在 FlexRIC 對應的 c-code 程式中, 為了加入一個新的 Service Model,
我們也要進行相對應的修改, 包含三個部分: xApp, RIC, 和 E2 Agent,
對應的資料夾位置為: ~/flexric/src/xApp/, ~/flexric/src/ric/iApps/, ~/flexric/examples/,
我們從 xApp 端要進行的修改開始, 這邊所指的 xApp 並非收值的 xApp,
而主要的修改在於 xApp 和 RIC 之間溝通的部分, 包含 FlexRIC 定義的 E42 介面:
(紅字為修改的部分, 藍字為註解)
- ~/flexric/src/xApp/e42_xapp.c
// 讓 RIC 平台可以看懂新建立的 Service Model
// 需要匯入 header 檔, 並修正判斷項次
#include "../sm/new_sm/new_sm_id.h"
...
static
bool valid_ran_func_id(uint16_t ran_func_id)
if(ran_func_id == SM_SLICE_ID
..
|| ran_func_id == SM_NEW_ID
)
return true;
return false;
} - ~/flexric/src/xApp/e42_xapp_api.c
// 把 Service Model 的 ID 加入判斷式, 按照之前設定, 此數值為 148
static inline
bool valid_sm_id(global_e2_node_id_t* id, uint32_t sm_id)
{
assert(id != NULL);
// Only for testing purposes
assert(sm_id == 142 || sm_id == 143 || sm_id == 144 || sm_id == 145 || sm_id == 147 || sm_id == 148);
return true;
} - ~/flexric/src/xApp/msg_handler_xapp.c
// 考慮到對應 Indication 的功能
// 將 Indication type 中對應的型態加入新的 Service Model
#include "../sm/new_sm/new_sm_id.h"
// E2 -> RIC
e2ap_msg_t e2ap_handle_indication_xapp(e42_xapp_t* xapp, const e2ap_msg_t* msg){
...
assert(msg_disp.rd.type == MAC_STATS_V0
...
|| msg_disp.rd.type == NEW_STATS_V0
);
}
接下來, 我們要修改 RIC 平台中的 iApp,
在 FlexRIC 中, iApp 可以想像成 RIC 平台的管理介面,
負責將運作過程中的 log 與資料記錄下來或顯示 (我們之後會解釋),
提供 RIC 平台管理, 或是 xApp 除錯的對應功能.
- ~/flexric/src/ric/iApps/influx.c
#include "ric/iApps/../../sm/new_sm/ie/new_data_ie.h" // for new_ind_msg_t
void notify_influx_listener(sm_ag_if_rd_t const* data){
assert(data->type == MAC_STATS_V0 ... || data->type == NEW_STATS_V0);
if(data->type == MAC_STATS_V0){
...
} else if (data->type == NEW_STATS_V0){
new_ind_msg_t const* new = &data->new_stats.msg;
char stats[1024] = {0};
to_string_new_ngut(&new->ngut, new->tstamp, stats, 1024);
int const rc = sendto(sockfd, stats, strlen(stats), MSG_CONFIRM, (const struct sockaddr *)
&servaddr, sizeof(servaddr));
assert(rc != -1);
} else {
assert(0 != 0 || "invalid data type ");
}
} - ~/flexric/src/ric/iApps/redis.c
void notify_redis_listener(sm_ag_if_rd_t const* data){
assert(data->type == MAC_STATS_V0 ... || data->type == NEW_STATS_V0);
} - ~/flexric/src/ric/iApps/stdout.c
// 當收到新的 Service Model 時, 將數值印出來
// 注意: 資料型態為自定義格式 (new_ng_u_tunnel_stats_t)
#include "ric/iApps/../../sm/new_sm/ie/new_data_ie.h"
static
void print_new_stats(new_ng_u_tunnel_stats_t const* new)
{
assert(new != NULL);
if(fp == NULL)
init_fp(&fp, file_path);
char stats[1024] = {0};
to_string_new_ngut(&new->ngut, new->tstamp , stats , 1024);
int const rc = fputs(stats , fp);
assert(rc > -1);
}
void notify_stdout_listener(sm_ag_if_r d_t const* data)
{
assert(data != NULL);
if(data->type == MAC_STATS_V0)
...
else if (data->type == NEW_STATS_V0)
print_new_stats(&data->new_stats.msg);
else
assert(0!= 0);
} - ~/flexric/src/ric/iApps/string_parser.c
// 把 Service Model 的數值轉換成 String 的格式,
// 這邊請參照之前 Indication Message 定義的格式填入
// 注意: 資料型態為自定義格式 (new_ng_u_tunnel_stats_t)
#include "ric/iApps/../../sm/new_sm/ie/new_data_ie.h"
void to_string_new_ngut(new_ng_u_tunnel_stats_t* ngut, int64_t tstamp , char* out, size_t out_len)
{
assert(new != NULL);
assert(out != NULL);
const size_t max = 1024;
assert(out_len >= max);
int const rc = snprintf(out, max,
"new_stats: tstamp=%ld,"
"data1=%ld,"
"data2=%ld,"
"data3=%ld,"
"data4=%ld"
"\n"
, tstamp
, new->data1
, new->data2
, new->data3
, new->data4
);
assert(rc < (int)max && "Not enough space in the char array to write all the data");
} - ~/flexric/src/ric/iApps/string_parser.h
#include "../../sm/new_sm/ie/new_data_ie.h"
void to_string_new_ngut(new_ng_u_tunnel_stats_t* ngut, int64_t tstamp, char* out, size_t out_len); - ~/flexric/src/ric/msg_handler_ric.c
e2ap_msg_t e2ap_handle_indication_ric(near_ric_t* ric, const e2ap_msg_t* msg){
...
assert(d.type == MAC_STATS_V0
...
|| d.type == NEW_STATS_V0);
}
在修改完上述部分的程式後, FlexRIC 才算真的能夠了解新定義的 Service Model,
幸好, 多數的程式定義都和 Service Model 的內容格式無關,
因此, 建立 Sevice Model 的程式修改主要是出現在第一次建立的時候,
之後, 若是修改或是擴充自定義的 Service Model, 只需修改 stdout 的 iApp 就好,
在確定好 FlexRIC 對定義的 Service Model 支援後,
我們修改測試的 E2 Agent 程式, 引入定義的 Service Model 資訊:
- ~/flexric/examples/xApp/c/monitor/CMakeLists.txt
// 編譯路徑的修改
add_executable(xapp_new_moni
xapp_new_moni.c
//... 如果有其他相關的 SM
../../../../src/sm/new_sm/ie/new_data_ie.c
)
target_link_libraries(xapp_new_moni
PUBLIC
e42_xapp
-pthread
-lsctp
-ldl
) - ~/flexric/examples/emulator/agent/test_agent.c
// 將填值對應程式放入 read_RAN 的程式中,
// 真實填值的程式位於: ~/flexric/test/sm/common/fill_ind_data.c
// 我們將在之後說明此部分程式
static
void read_RAN(sm_ag_if_rd_t* data)
{
assert(data->type == MAC_STATS_V0 ...
data->type == NEW_STATS_V0);
if(data->type == MAC_STATS_V0 ){
...
} else if(data->type == NEW_STATS_V0){
fill_new_ind_data(&data->new_stats);
} else {
assert("Invalid data type");
}
} - ~/flexric/examples/ric/near_ric.c
// 加入 Service Model 的 ID
const uint16_t NEW_ran_func_id = 148; //
以上大致完成 FlexRIC 架構中, 加入一個新的 Service Model 所需的修改,
接下來我們會繼續介紹 E2 Agent 和 xApp 所要做的對應修正.
留言
張貼留言