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:
co-authored by
Robert Schmidt
parent
f3eb713084
commit
1ab8a58a2f
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user