Refactor TUN Interface Management and Move to SDAP Layer

This commit refactors the TUN interface management by moving its creation
and configuration from the PDCP layer to the SDAP layer for UE.

Key changes include:

- Introduced `tun_generate_ue_ifname` and `tun_destroy` functions for better
  TUN interface lifecycle management.
- Added support for creating and destroying UE-specific TUN interfaces in SDAP.
- Refactored `nr_pdcp_module_init` to remove TUN-related logic and moved it
  to SDAP.
- Updated NAS and SDAP layers to handle PDU session-specific TUN interface
  creation and configuration.
- Enhanced SDAP entity management to include TUN socket handling and thread
  lifecycle.
- Updated NAS message handling to initialize default PDU session TUN
  interfaces in NOS1 mode.
- Use a single SDAP thread function for gNB and UE
- Allow noS1 mode also in SA on gNB

These changes improve modularity by isolating TUN interface management within
the SDAP layer, aligning with the 3GPP architecture, and simplifying the PDCP
layer.

Co-Authored-By: Robert Schmidt <robert.schmidt@openairinterface.org>
This commit is contained in:
Bartosz Podrygajlo
2025-04-16 15:03:18 +02:00
co-authored by Robert Schmidt
parent f3eb713084
commit 1ab8a58a2f
17 changed files with 238 additions and 272 deletions
+23 -5
View File
@@ -38,7 +38,7 @@
int nas_sock_fd[MAX_MOBILES_PER_ENB * 2]; // Allocated for both LTE UE and NR UE.
int nas_sock_mbms_fd;
static int tun_alloc(const char *dev)
int tun_alloc(const char *dev)
{
struct ifreq ifr;
int fd, err;
@@ -157,13 +157,14 @@ static bool setInterfaceParameter(int sock_fd, const char *ifn, int af, const ch
return success;
}
/*
* \brief bring interface up (up != 0) or down (up == 0)
*/
typedef enum { INTERFACE_DOWN, INTERFACE_UP } if_action_t;
/*
* \brief bring interface up (up != 0) or down (up == 0)
*/
static bool change_interface_state(int sock_fd, const char *ifn, if_action_t if_action)
{
const char* action = if_action == INTERFACE_DOWN ? "DOWN" : "UP";
const char *action = if_action == INTERFACE_DOWN ? "DOWN" : "UP";
struct ifreq ifr = {0};
strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name));
@@ -189,6 +190,7 @@ fail_interface_state:
return false;
}
bool tun_config(const char* ifname, const char *ipv4, const char *ipv6)
{
AssertFatal(ipv4 != NULL || ipv6 != NULL, "need to have IP address, but none given\n");
@@ -262,3 +264,19 @@ int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id)
{
return snprintf(ifname, IFNAMSIZ, "%s%d", ifprefix, instance_id + 1);
}
int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id)
{
char pdu_session_string[10];
snprintf(pdu_session_string, sizeof(pdu_session_string), "p%d", pdu_session_id);
return snprintf(ifname, IFNAMSIZ, "%s%d%s", "oaitun_ue", instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string);
}
void tun_destroy(const char *dev, int fd) {
if (change_interface_state(fd, dev, INTERFACE_DOWN) == 0) {
LOG_I(UTIL, "Interface %s is now down.\n", dev);
} else {
LOG_E(UTIL, "Could not bring interface %s down.\n", dev);
}
close(fd);
}
+15
View File
@@ -34,6 +34,7 @@
* \param[in] instance_id unique instance number
*/
int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id);
int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id);
/*!
* \brief This function initializes the TUN interface
@@ -73,4 +74,18 @@ bool tun_config(const char* ifname, const char *ipv4, const char *ipv6);
*/
void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4);
/*!
* \brief This function allocates a TUN interface
* \param[in] dev name of the interface
* \return file descriptor of the allocated interface
*/
int tun_alloc(const char *dev);
/*!
* \brief This function destroys the TUN interface
* \param[in] dev name of the interface
* \param[in] fd file descriptor of the allocated interface
*/
void tun_destroy(const char *dev, int fd);
#endif /*TUN_IF_H_*/
+1 -1
View File
@@ -329,7 +329,7 @@ To manage UE connections, `nr_pdcp_add_srbs()` is employed for adding UE SRBs in
## PDCP Tx flow
On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` and `nr_pdcp_data_req_srb()` are called by the upper layer. The upper layer could be GTP or a PDCP internal thread like `enb_tun_read_thread()`, which reads directly from the Linux socket if the 3GPP core implementation is skipped. The PDCP internals for `nr_pdcp_data_req_srb()` and `nr_pdcp_data_req_drb()` are thread-safe. Within these functions, the PDCP manager protects access to the SDU receiving function of PDCP (`recv_sdu()` callback, corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs) using mutex. When necessary, the PDCP layer pushes this data to RLC by calling `rlc_data_req()`.
On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` and `nr_pdcp_data_req_srb()` are called by the upper layer. The upper layer could be GTP or a PDCP internal thread like `gnb_tun_read_thread()`, which reads directly from the Linux socket if the 3GPP core implementation is skipped. The PDCP internals for `nr_pdcp_data_req_srb()` and `nr_pdcp_data_req_drb()` are thread-safe. Within these functions, the PDCP manager protects access to the SDU receiving function of PDCP (`recv_sdu()` callback, corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs) using mutex. When necessary, the PDCP layer pushes this data to RLC by calling `rlc_data_req()`.
## PDCP Rx flow
+1 -3
View File
@@ -85,6 +85,7 @@ unsigned short config_frames[4] = {2,9,11,13};
#include "utils.h"
#include "x2ap_eNB.h"
#include "openair1/SCHED_NR/sched_nr.h"
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
pthread_cond_t nfapi_sync_cond;
pthread_mutex_t nfapi_sync_mutex;
@@ -497,11 +498,8 @@ static void wait_nfapi_init(char *thread_name)
}
void init_pdcp(void) {
uint32_t pdcp_initmask = IS_SOFTMODEM_NOS1 ? ENB_NAS_USE_TUN_BIT : LINK_ENB_PDCP_TO_GTPV1U_BIT;
if (!NODE_IS_DU(get_node_type())) {
nr_pdcp_layer_init();
nr_pdcp_module_init(pdcp_initmask, 0);
}
}
+5 -20
View File
@@ -301,25 +301,10 @@ void init_openair0()
static void init_pdcp(int ue_id)
{
uint32_t pdcp_initmask = (!IS_SOFTMODEM_NOS1) ? LINK_ENB_PDCP_TO_GTPV1U_BIT : LINK_ENB_PDCP_TO_GTPV1U_BIT;
/*if (IS_SOFTMODEM_RFSIM || (nfapi_getmode()==NFAPI_UE_STUB_PNF)) {
pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT;
}*/
// previous code was:
// if (IS_SOFTMODEM_NOKRNMOD)
// pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT;
// The kernel module (KRNMOD) has been removed from the project, so the 'if'
// was removed but the flag 'pdcp_initmask' was kept, as "no kernel module"
// was always set. further refactoring could take it out
pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT;
if (get_softmodem_params()->nsa && nr_rlc_module_init(0) != 0) {
LOG_I(RLC, "Problem at RLC initiation \n");
}
nr_pdcp_layer_init();
nr_pdcp_module_init(pdcp_initmask, ue_id);
}
// Stupid function addition because UE itti messages queues definition is common with eNB
@@ -449,6 +434,11 @@ int main(int argc, char **argv)
}
}
if (create_tasks_nrue(1) < 0) {
printf("cannot create ITTI tasks\n");
exit(-1); // need a softer mode
}
int mode_offset = get_softmodem_params()->nsa ? NUMBER_OF_UE_MAX : 1;
uint16_t node_number = get_softmodem_params()->node_number;
ue_id_g = (node_number == 0) ? 0 : node_number - 2;
@@ -557,11 +547,6 @@ int main(int argc, char **argv)
// wait for end of program
printf("TYPE <CTRL-C> TO TERMINATE\n");
if (create_tasks_nrue(1) < 0) {
printf("cannot create ITTI tasks\n");
exit(-1); // need a softer mode
}
// Sleep a while before checking all parameters have been used
// Some are used directly in external threads, asynchronously
sleep(2);
+4
View File
@@ -144,6 +144,7 @@ extern "C"
#define EMULATE_L1 softmodem_params.emulate_l1
#define CONTINUOUS_TX softmodem_params.continuous_tx
#define SYNC_REF softmodem_params.sync_ref
#define DEFAULT_PDU_ID softmodem_params.default_pdu_session_id
#define DEFAULT_RFCONFIG_FILE "/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat";
@@ -188,6 +189,7 @@ extern int usrp_tx_thread;
{"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \
{"imscope" , CONFIG_HLP_IMSCOPE, PARAMFLAG_BOOL, .uptr=&enable_imscope, .defintval=0, TYPE_UINT, 0}, \
{"imscope-record" , CONFIG_HLP_IMSCOPE_RECORD,PARAMFLAG_BOOL, .uptr=&enable_imscope_record, .defintval=0, TYPE_UINT, 0}, \
{"default_pdu_id", NULL, 0, .iptr=&DEFAULT_PDU_ID, .defintval=10, TYPE_INT, 0}, \
}
// clang-format on
@@ -234,6 +236,7 @@ extern int usrp_tx_thread;
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
}
// clang-format on
@@ -343,6 +346,7 @@ typedef struct {
uint32_t sync_ref;
int no_itti;
int threequarter_fs;
int default_pdu_session_id;
} softmodem_params_t;
#define IS_SA_MODE(sM_params) (!(sM_params)->phy_test && !(sM_params)->do_ra && !(sM_params)->nsa)
+4
View File
@@ -469,6 +469,10 @@ typedef ul_info_transfer_cnf_t dl_info_transfer_cnf_t;
*/
typedef ul_info_transfer_ind_t dl_info_transfer_ind_t;
typedef struct nas_nos1_msg_s {
int dummy; // This dummy element is to avoid CLANG warning: empty struct has size 0 in C, size 1 in C++
} nas_nos1_msg_t;
typedef struct nas_pdu_session_req_s {
int pdusession_id;
int pdusession_type;
+1
View File
@@ -79,6 +79,7 @@ MESSAGE_DEF(NR_NAS_CONN_ESTABLISH_IND, MESSAGE_PRIORITY_MED, nas_establish_ind_t
MESSAGE_DEF(NR_NAS_CONN_RELEASE_IND, MESSAGE_PRIORITY_MED, NRNasConnReleaseInd, nr_nas_conn_release_ind)
MESSAGE_DEF(NAS_UPLINK_DATA_CNF, MESSAGE_PRIORITY_MED, ul_info_transfer_cnf_t, nas_ul_data_cnf)
MESSAGE_DEF(NAS_DOWNLINK_DATA_IND, MESSAGE_PRIORITY_MED, dl_info_transfer_ind_t, nas_dl_data_ind)
MESSAGE_DEF(NAS_INIT_NOS1_IF, MESSAGE_PRIORITY_MED, nas_nos1_msg_t, nas_init_nos1_if)
// xNB: realtime -> RRC messages
MESSAGE_DEF(RRC_SUBFRAME_PROCESS, MESSAGE_PRIORITY_MED, RrcSubframeProcess, rrc_subframe_process)
+1 -210
View File
@@ -390,168 +390,6 @@ bool nr_pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP,
/* pdcp_data_ind thread - end */
/****************************************************************************/
/****************************************************************************/
/* hacks to be cleaned up at some point - begin */
/****************************************************************************/
#include "LAYER2/MAC/mac_extern.h"
static void reblock_tun_socket(void)
{
extern int nas_sock_fd[];
int f;
f = fcntl(nas_sock_fd[0], F_GETFL, 0);
f &= ~(O_NONBLOCK);
if (fcntl(nas_sock_fd[0], F_SETFL, f) == -1) {
LOG_E(PDCP, "fcntl(F_SETFL) failed on fd %d: errno %d, %s\n", nas_sock_fd[0], errno, strerror(errno));
}
}
static void *enb_tun_read_thread(void *_)
{
extern int nas_sock_fd[];
char rx_buf[NL_MAX_PAYLOAD];
int len;
protocol_ctxt_t ctxt;
ue_id_t UEid;
int rb_id = 1;
pthread_setname_np( pthread_self(),"enb_tun_read");
while (1) {
len = read(nas_sock_fd[0], &rx_buf, NL_MAX_PAYLOAD);
if (len == -1) {
LOG_E(PDCP, "could not read(): errno %d %s\n", errno, strerror(errno));
return NULL;
}
LOG_D(PDCP, "%s(): nas_sock_fd read returns len %d\n", __func__, len);
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
const bool has_ue = nr_pdcp_get_first_ue_id(nr_pdcp_ue_manager, &UEid);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
if (!has_ue) continue;
ctxt.module_id = 0;
ctxt.enb_flag = 1;
ctxt.instance = 0;
ctxt.frame = 0;
ctxt.subframe = 0;
ctxt.eNB_index = 0;
ctxt.brOption = 0;
ctxt.rntiMaybeUEid = UEid;
uint8_t qfi = 7;
bool rqi = 0;
int pdusession_id = 10;
sdap_data_req(&ctxt,
UEid,
SRB_FLAG_NO,
rb_id,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
len,
(unsigned char *)rx_buf,
PDCP_TRANSMISSION_MODE_DATA,
NULL,
NULL,
qfi,
rqi,
pdusession_id);
}
return NULL;
}
static void *ue_tun_read_thread(void *_)
{
extern int nas_sock_fd[];
char rx_buf[NL_MAX_PAYLOAD];
int len;
protocol_ctxt_t ctxt;
ue_id_t UEid;
int has_ue;
int rb_id = 1;
pthread_setname_np( pthread_self(),"ue_tun_read");
while (1) {
len = read(nas_sock_fd[0], &rx_buf, NL_MAX_PAYLOAD);
if (len == -1) {
LOG_E(PDCP, "error: cannot read() from fd %d: errno %d, %s\n", nas_sock_fd[0], errno, strerror(errno));
return NULL; /* exit thread */
}
LOG_D(PDCP, "%s(): nas_sock_fd read returns len %d\n", __func__, len);
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
has_ue = nr_pdcp_get_first_ue_id(nr_pdcp_ue_manager, &UEid);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
if (!has_ue) continue;
ctxt.module_id = 0;
ctxt.enb_flag = 0;
ctxt.instance = 0;
ctxt.frame = 0;
ctxt.subframe = 0;
ctxt.eNB_index = 0;
ctxt.brOption = 0;
ctxt.rntiMaybeUEid = UEid;
bool dc = SDAP_HDR_UL_DATA_PDU;
extern uint8_t nas_qfi;
extern uint8_t nas_pduid;
sdap_data_req(&ctxt,
UEid,
SRB_FLAG_NO,
rb_id,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
len,
(unsigned char *)rx_buf,
PDCP_TRANSMISSION_MODE_DATA,
NULL,
NULL,
nas_qfi,
dc,
nas_pduid);
}
return NULL;
}
static void start_pdcp_tun_enb(void)
{
pthread_t t;
reblock_tun_socket();
if (pthread_create(&t, NULL, enb_tun_read_thread, NULL) != 0) {
LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
exit(1);
}
}
static void start_pdcp_tun_ue(void)
{
pthread_t t;
reblock_tun_socket();
if (pthread_create(&t, NULL, ue_tun_read_thread, NULL) != 0) {
LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
exit(1);
}
}
/****************************************************************************/
/* hacks to be cleaned up at some point - end */
/****************************************************************************/
int pdcp_fifo_flush_sdus(const protocol_ctxt_t *const ctxt_pP)
{
return 0;
@@ -592,54 +430,7 @@ void nr_pdcp_layer_init(void)
#include "nfapi/oai_integration/vendor_ext.h"
#include "executables/lte-softmodem.h"
#include "common/utils/tun_if.h"
uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id)
{
/* hack: be sure to initialize only once */
static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
static int initialized = 0;
if (pthread_mutex_lock(&m) != 0) abort();
if (initialized) {
abort();
}
initialized = 1;
if (pthread_mutex_unlock(&m) != 0) abort();
pdcp_optmask = pdcp_optmask | _pdcp_optmask ;
if (UE_NAS_USE_TUN) {
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_nrue" : "oaitun_ue";
int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 || NFAPI_MODE == NFAPI_MODE_STANDALONE_PNF)
? MAX_MOBILES_PER_ENB
: 1;
int begx = (id == 0) ? 0 : id - 1;
int endx = (id == 0) ? num_if : id;
for (int i = begx; i < endx; i++) {
char ifname[IFNAMSIZ];
tun_generate_ifname(ifname, ifprefix, i);
tun_init(ifname, i);
}
if (IS_SOFTMODEM_NOS1) {
const char *ip = !get_softmodem_params()->nsa ? "10.0.1.2" : "10.0.1.3";
char ifname[IFNAMSIZ];
tun_generate_ifname(ifname, ifprefix, id);
tun_config(ifname, ip, NULL);
set_qfi_pduid(7, 10);
}
LOG_I(PDCP, "UE pdcp will use tun interface\n");
start_pdcp_tun_ue();
} else if (ENB_NAS_USE_TUN) {
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb";
char ifname[IFNAMSIZ];
tun_generate_ifname(ifname, ifprefix, id);
tun_init(ifname, id);
tun_config(ifname, "10.0.1.1", NULL);
LOG_I(PDCP, "ENB pdcp will use tun interface\n");
start_pdcp_tun_enb();
}
return pdcp_optmask ;
}
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
char *buf, int size,
@@ -35,7 +35,6 @@ struct NR_DRB_ToAddMod;
struct NR_SRB_ToAddMod;
void nr_pdcp_layer_init(void);
uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id);
void du_rlc_data_req(const protocol_ctxt_t *const ctxt_pP,
const srb_flag_t srb_flagP,
+2
View File
@@ -62,6 +62,8 @@ void init_nsa_message(NR_UE_RRC_INST_t *rrc, char* reconfig_file, char* rbconfig
msg_len = fread(buffer, 1, 1024, fd);
fclose(fd);
process_nsa_message(rrc, nr_RadioBearerConfigX_r15, buffer,msg_len);
MessageDef* ittiMsg = itti_alloc_new_message(TASK_RRC_NRUE, rrc->ue_id, NAS_INIT_NOS1_IF);
itti_send_msg_to_task(TASK_NAS_NRUE, rrc->ue_id, ittiMsg);
}
else
LOG_D(NR_RRC, "In NSA mode \n");
+124 -6
View File
@@ -20,13 +20,29 @@
*/
#include "nr_sdap.h"
#include "assertions.h"
#include "utils.h"
#include <inttypes.h>
#include <pthread.h>
#include <stddef.h>
#include "nr_sdap_entity.h"
#include "common/utils/LOG/log.h"
#include "errno.h"
#include "rlc.h"
#include "tun_if.h"
#include "system.h"
static void reblock_tun_socket(int fd)
{
int f;
f = fcntl(fd, F_GETFL, 0);
f &= ~(O_NONBLOCK);
if (fcntl(fd, F_SETFL, f) == -1) {
LOG_E(PDCP, "fcntl(F_SETFL) failed on fd %d: errno %d, %s\n", fd, errno, strerror(errno));
}
}
uint8_t nas_qfi;
uint8_t nas_pduid;
bool sdap_data_req(protocol_ctxt_t *ctxt_p,
const ue_id_t ue_id,
@@ -91,8 +107,110 @@ void sdap_data_ind(rb_id_t pdcp_entity,
size);
}
void set_qfi_pduid(uint8_t qfi, uint8_t pduid){
nas_qfi = qfi;
nas_pduid = pduid;
return;
struct thread_args {
nr_sdap_entity_t *entity;
bool is_gnb;
};
static void *sdap_tun_read_thread(void *arg)
{
DevAssert(arg != NULL);
struct thread_args *ta = arg;
nr_sdap_entity_t *entity = ta->entity;
bool is_gnb = ta->is_gnb;
free(ta);
char rx_buf[NL_MAX_PAYLOAD];
int len;
reblock_tun_socket(entity->pdusession_sock);
int rb_id = 1;
while (!entity->stop_thread) {
len = read(entity->pdusession_sock, &rx_buf, NL_MAX_PAYLOAD);
if (len == -1) {
LOG_E(PDCP, "could not read(): errno %d %s\n", errno, strerror(errno));
return NULL;
}
LOG_D(SDAP, "read data of size %d\n", len);
protocol_ctxt_t ctxt = {.enb_flag = is_gnb, .rntiMaybeUEid = entity->ue_id};
bool dc = is_gnb ? false : SDAP_HDR_UL_DATA_PDU;
DevAssert(entity != NULL);
entity->tx_entity(entity,
&ctxt,
SRB_FLAG_NO,
rb_id,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
len,
(unsigned char *)rx_buf,
PDCP_TRANSMISSION_MODE_DATA,
NULL,
NULL,
entity->qfi,
dc);
}
return NULL;
}
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id)
{
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, get_softmodem_params()->default_pdu_session_id);
DevAssert(entity != NULL);
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb";
char ifname[IFNAMSIZ];
tun_generate_ifname(ifname, ifprefix, ue_id - 1);
entity->pdusession_sock = tun_alloc(ifname);
tun_config(ifname, "10.0.1.1", NULL);
struct thread_args *ta = calloc_or_fail(1, sizeof(*ta));
ta->entity = entity;
ta->is_gnb = true;
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, "gnb_tun_read_thread", -1, OAI_PRIORITY_RT_LOW);
}
void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock)
{
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
DevAssert(entity != NULL);
entity->pdusession_sock = sock;
entity->stop_thread = false;
char thread_name[64];
snprintf(thread_name, sizeof(thread_name), "ue_tun_read_%ld_p%d", ue_id, pdu_session_id);
struct thread_args *ta = calloc_or_fail(1, sizeof(*ta));
ta->entity = entity;
ta->is_gnb = false;
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, thread_name, -1, OAI_PRIORITY_RT_LOW);
}
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id)
{
int default_pdu = get_softmodem_params()->default_pdu_session_id;
char ifname[IFNAMSIZ];
tun_generate_ue_ifname(ifname, ue_id, pdu_session_id != default_pdu ? pdu_session_id : -1);
const int sock = tun_alloc(ifname);
tun_config(ifname, ipv4, ipv6);
if (ipv4) {
setup_ue_ipv4_route(ifname, ue_id, ipv4);
}
start_sdap_tun_ue(ue_id, pdu_session_id, sock); // interface name suffix is ue_id+1
}
void remove_ue_ip_if(nr_sdap_entity_t *entity)
{
DevAssert(entity != NULL);
// Stop the read thread
entity->stop_thread = true;
int ret = pthread_join(entity->pdusession_thread, NULL);
AssertFatal(ret == 0, "pthread_join() failed, errno: %d, %s\n", errno, strerror(errno));
// Bring down the IP interface
int default_pdu = get_softmodem_params()->default_pdu_session_id;
char ifname[IFNAMSIZ];
tun_generate_ue_ifname(ifname, entity->ue_id, entity->pdusession_id != default_pdu ? entity->pdusession_id : -1);
tun_destroy(ifname, entity->pdusession_sock);
}
+3 -1
View File
@@ -61,6 +61,8 @@ void sdap_data_ind(rb_id_t pdcp_entity,
char *buf,
int size);
void set_qfi_pduid(uint8_t qfi, uint8_t pduid);
void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock);
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id);
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id);
#endif
+23 -3
View File
@@ -31,6 +31,8 @@
#include "gtpv1_u_messages_types.h"
#include "intertask_interface.h"
#include "rlc.h"
#include "tun_if.h"
#include "nr_sdap.h"
typedef struct {
nr_sdap_entity_t *sdap_entity_llist;
@@ -103,7 +105,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
/* The offset of the SDAP header, it might be 0 if has_sdap_tx is not true in the pdcp entity. */
int offset=0;
bool ret = false;
/*Hardcode DRB ID given from upper layer (ue/enb_tun_read_thread rb_id), it will change if we have SDAP*/
/*Hardcode DRB ID given from upper layer (ue/gnb_tun_read_thread rb_id), it will change if we have SDAP*/
rb_id_t sdap_drb_id = rb_id;
int pdcp_ent_has_sdap = 0;
@@ -321,8 +323,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
* 5.2.2 Downlink
* deliver the retrieved SDAP SDU to the upper layer.
*/
extern int nas_sock_fd[];
int len = write(nas_sock_fd[0], &buf[offset], size-offset);
int len = write(entity->pdusession_sock, &buf[offset], size - offset);
LOG_D(SDAP, "RX Entity len : %d\n", len);
LOG_D(SDAP, "RX Entity size : %d\n", size);
LOG_D(SDAP, "RX Entity offset : %d\n", offset);
@@ -513,6 +514,8 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb,
sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del;
sdap_entity->qfi2drb_map = nr_sdap_qfi2drb_map;
sdap_entity->pdusession_sock = -1;
if(is_defaultDRB) {
sdap_entity->default_drb = drb_identity;
LOG_I(SDAP, "Default DRB for the created SDAP entity: %ld \n", sdap_entity->default_drb);
@@ -523,6 +526,12 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb,
sdap_entity->next_entity = sdap_info.sdap_entity_llist;
sdap_info.sdap_entity_llist = sdap_entity;
if (IS_SOFTMODEM_NOS1 && is_gnb) {
// In NOS1 mode, terminate SDAP for the first UE on the gNB. This allows injecting/receiving
// PDCP SDUs to/from the TUN interface.
start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id);
}
return sdap_entity;
}
@@ -591,6 +600,9 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) {
entityPrev->next_entity = entityPtr->next_entity;
if (entityPrev->pdusession_sock != -1) {
remove_ue_ip_if(entityPrev);
}
free(entityPtr);
LOG_D(SDAP, "Successfully deleted Entity.\n");
ret = true;
@@ -674,3 +686,11 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in
}
}
}
void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id)
{
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pduid);
DevAssert(entity != NULL);
entity->qfi = qfi;
return;
}
+7
View File
@@ -81,6 +81,11 @@ typedef struct nr_sdap_entity_s {
ue_id_t ue_id;
rb_id_t default_drb;
int pdusession_id;
int pdusession_sock;
pthread_t pdusession_thread;
bool stop_thread;
int qfi;
qfi2drb_t qfi2drb_table[SDAP_MAX_QFI];
void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx);
@@ -212,4 +217,6 @@ bool is_sdap_tx(bool is_gnb, NR_SDAP_Config_t *sdap_config);
*/
void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, int pdusession_id, int drb_id);
void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id);
void remove_ue_ip_if(nr_sdap_entity_t *entity);
#endif
+23 -22
View File
@@ -64,6 +64,7 @@
#include "secu_defs.h"
#include "utils.h"
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
#include "openair2/SDAP/nr_sdap/nr_sdap_entity.h"
#include "fgs_nas_utils.h"
#include "fgmm_service_accept.h"
#include "fgmm_service_reject.h"
@@ -1059,7 +1060,7 @@ static int capture_ipv6_addr(const uint8_t *addr, char *ip, size_t len)
* @brief Process PDU Session Address in PDU Session Establishment Accept message
* and configure the tun interface
*/
static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg)
static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg, int instance_id, int pdu_session_id)
{
uint8_t *addr = msg->pdu_addr_ie.pdu_addr_oct;
@@ -1067,18 +1068,13 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg
case PDU_SESSION_TYPE_IPV4: {
char ip[20];
capture_ipv4_addr(&addr[0], ip, sizeof(ip));
char ifname[IFNAMSIZ];
tun_generate_ifname(ifname, "oaitun_ue", 0);
tun_config(ifname, ip, NULL);
setup_ue_ipv4_route(ifname, 0, ip);
create_ue_ip_if(ip, NULL, instance_id, pdu_session_id);
} break;
case PDU_SESSION_TYPE_IPV6: {
char ipv6[40];
capture_ipv6_addr(addr, ipv6, sizeof(ipv6));
char ifname[IFNAMSIZ];
tun_generate_ifname(ifname, "oaitun_ue", 0);
tun_config(ifname, NULL, ipv6);
create_ue_ip_if(NULL, ipv6, instance_id, pdu_session_id);
} break;
case PDU_SESSION_TYPE_IPV4V6: {
@@ -1086,10 +1082,7 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg
capture_ipv6_addr(addr, ipv6, sizeof(ipv6));
char ipv4[20];
capture_ipv4_addr(&addr[IPv6_INTERFACE_ID_LENGTH], ipv4, sizeof(ipv4));
char ifname[IFNAMSIZ];
tun_generate_ifname(ifname, "oaitun_ue", 0);
tun_config(ifname, ipv4, ipv6);
setup_ue_ipv4_route(ifname, 0, ipv4);
create_ue_ip_if(ipv4, ipv6, instance_id, pdu_session_id);
} break;
default:
@@ -1101,7 +1094,7 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg
/**
* @brief Handle PDU Session Establishment Accept and process decoded message
*/
static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length)
static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length, int instance)
{
pdu_session_establishment_accept_msg_t msg = {0};
int size = 0;
@@ -1143,24 +1136,23 @@ static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length)
LOG_E(NAS, "decode_pdu_session_establishment_accept_msg failure\n");
// process PDU Session
if (msg.pdu_addr_ie.pdu_length)
process_pdu_session_addr(&msg);
process_pdu_session_addr(&msg, instance, sm_header.pdu_session_id);
else
LOG_W(NAS, "Optional PDU Address IE was not provided\n");
set_qfi_pduid(msg.qos_rules.rule->qfi, sm_header.pdu_session_id);
set_qfi(msg.qos_rules.rule->qfi, sm_header.pdu_session_id, instance);
}
/**
* @brief Handle DL NAS Transport and process piggybacked 5GSM messages
*/
static void handleDownlinkNASTransport(uint8_t *pdu_buffer, uint32_t msg_length)
void handleDownlinkNASTransport(uint8_t * pdu_buffer, int pdu_length, int instance)
{
uint8_t msg_type = *(pdu_buffer + 16);
if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
LOG_A(NAS, "Received PDU Session Establishment Accept in DL NAS Transport\n");
handle_pdu_session_accept(pdu_buffer, msg_length);
handle_pdu_session_accept(pdu_buffer, pdu_length, instance);
} else {
LOG_E(NAS, "Received unexpected message in DLinformationTransfer %d\n", msg_type);
}
@@ -1403,7 +1395,7 @@ static void send_nas_5gmm_ind(instance_t instance, const Guti5GSMobileIdentity_t
static void request_default_pdusession(nr_ue_nas_t *nas)
{
MessageDef *message_p = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_PDU_SESSION_REQ);
NAS_PDU_SESSION_REQ(message_p).pdusession_id = 10; /* first or default pdu session */
NAS_PDU_SESSION_REQ(message_p).pdusession_id = get_softmodem_params()->default_pdu_session_id;
NAS_PDU_SESSION_REQ(message_p).pdusession_type = 0x91; // 0x91 = IPv4, 0x92 = IPv6, 0x93 = IPv4v6
NAS_PDU_SESSION_REQ(message_p).sst = nas->uicc->nssai_sst;
NAS_PDU_SESSION_REQ(message_p).sd = nas->uicc->nssai_sd;
@@ -1634,7 +1626,7 @@ void *nas_nrue(void *args_p)
if (msg_type == FGS_REGISTRATION_ACCEPT) {
handle_registration_accept(nas, pdu_buffer, pdu_length);
} else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
handle_pdu_session_accept(pdu_buffer, pdu_length);
handle_pdu_session_accept(pdu_buffer, pdu_length, nas->UE_id);
}
// Free NAS buffer memory after use (coming from RRC)
@@ -1724,7 +1716,7 @@ void *nas_nrue(void *args_p)
handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length);
break;
case FGS_DOWNLINK_NAS_TRANSPORT:
handleDownlinkNASTransport(pdu_buffer, pdu_length);
handleDownlinkNASTransport(pdu_buffer, pdu_length, nas->UE_id);
break;
case FGS_REGISTRATION_ACCEPT:
handle_registration_accept(nas, pdu_buffer, pdu_length);
@@ -1735,7 +1727,7 @@ void *nas_nrue(void *args_p)
nas->fiveGMM_state = FGS_DEREGISTERED;
break;
case FGS_PDU_SESSION_ESTABLISHMENT_ACC:
handle_pdu_session_accept(pdu_buffer, pdu_length);
handle_pdu_session_accept(pdu_buffer, pdu_length, nas->UE_id);
break;
case FGS_PDU_SESSION_ESTABLISHMENT_REJ:
LOG_E(NAS, "Received PDU Session Establishment reject\n");
@@ -1767,6 +1759,15 @@ void *nas_nrue(void *args_p)
send_nas_uplink_data_req(nas, &initialNasMsg);
} break;
case NAS_INIT_NOS1_IF: {
const int pdu_session_id = get_softmodem_params()->default_pdu_session_id;
const char *ip = !get_softmodem_params()->nsa ? "10.0.1.2" : "10.0.1.3";
const int qfi = 7;
create_ue_ip_if(ip, NULL, nas->UE_id, pdu_session_id);
set_qfi(qfi, pdu_session_id, nas->UE_id);
break;
}
default:
LOG_E(NAS, "[UE %ld] Received unexpected message %s\n", nas->UE_id, ITTI_MSG_NAME(msg_p));
break;
+1
View File
@@ -110,5 +110,6 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas);
void *nas_nrue_task(void *args_p);
void *nas_nrue(void *args_p);
void nas_init_nrue(int num_ues);
void nr_ue_create_ip_if(const char *ifnameprefix, const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id);
#endif /* __NR_NAS_MSG_SIM_H__*/