Commit 8d289546 authored by Guido Casati's avatar Guido Casati

Paging UE (SDAP): reattach TUN after idle reset

UE paging can recreate the AS-side SDAP entity while NAS still keeps the
PDU session established. Per TS 38.304 clause 7.1 and TS 24.501 clauses
5.6.2.2.1,5.6.1.2 paging/service request restores user-plane resources
for an established PDU session, it does not imply deleting the UE IP/TUN
interface.

Deleting the UE TUN with SDAP entity teardown breaks user-plane continuity
after re-attach. We need SDAP entity lifetime and UE TUN lifetime to be
decoupled. This commit keeps a UE/PDU-session TUN registry outside the
SDAP entity lifetime. When a UE SDAP entity is recreated, reattach it
to the preserved TUN socket and restart the reader thread. On first PDU
session setup, NAS registers the TUN before attaching the reader.

The sequence is the following: (1) NAS register the iface
(2) sdap entity attaches to the iface (3) UE goes IDLE, SDAP
entity is destroyed, iface is deatched and brought down (4)
UE Service Request, SDAP entity is created (5) iface reattaches
to the SDAP entity and is brought up

UE reattach assumes the PDU session TUN interface was registered
before the SDAP entity is recreated.

DL/UL data is intentionally dropped when SDAP is not yet attached
or QFI is unavailable, rather than queued in this layer.

Changes:
- `nr_sdap.c`: keep a UE/PDU-session TUN registry, duplicate the stored
  socket into each SDAP entity, and add attach/detach/destroy helpers.
- `nr_sdap_entity.c`: detach SDAP entities from their TUN reader on
  deletion, preserve UE TUN interfaces across idle cleanup, and destroy
  gNB TUN interfaces when the gNB entity is removed. Drop downlink SDUs
  if the UE SDAP entity is not attached to a TUN socket yet.
- `openair3/NAS/NR_UE/nr_nas_msg.c`: set QFI before UE TUN creation so
  first attach can pick up cached QFI.
- `common/utils/tuntap_if.c`: add `tuntap_set_up`/`tuntap_set_down` helpers
  for UE interface state reflection and initialize `flags` in `tuntap_destroy`
  to avoid maybe-uninitialized build failures.
Signed-off-by: default avatarGuido Casati <guido.casati@openairinterface.org>
parent 74f661f3
...@@ -184,6 +184,18 @@ static bool set_if_flags(int sock_fd, const char *ifn, short flags) ...@@ -184,6 +184,18 @@ static bool set_if_flags(int sock_fd, const char *ifn, short flags)
return true; return true;
} }
short tuntap_set_up(const char *ifname, int sock_fd)
{
short flags = 0;
if (!get_if_flags(sock_fd, ifname, &flags))
return -1;
flags |= IFF_UP;
if (!set_if_flags(sock_fd, ifname, flags))
return -1;
return flags;
}
bool tun_config(const char* ifname, const char *ipv4, const char *ipv6) bool tun_config(const char* ifname, const char *ipv4, const char *ipv6)
{ {
...@@ -215,10 +227,10 @@ bool tun_config(const char* ifname, const char *ipv4, const char *ipv6) ...@@ -215,10 +227,10 @@ bool tun_config(const char* ifname, const char *ipv4, const char *ipv6)
close(sock_fd); close(sock_fd);
} }
// if successfully set IP addresses: set iterface up, disable ARP, no if (success) {
// multicast, point-to-point const short flags = tuntap_set_up(ifname, sock_fd);
if (success) success = flags >= 0 && set_if_flags(sock_fd, ifname, (flags | IFF_NOARP | IFF_POINTOPOINT) & ~IFF_MULTICAST);
success = set_if_flags(sock_fd, ifname, (IFF_UP | IFF_NOARP | IFF_POINTOPOINT) & ~IFF_MULTICAST); }
if (success) if (success)
LOG_A(OIP, "TUN Interface %s successfully configured, IPv4 %s, IPv6 %s\n", ifname, ipv4, ipv6); LOG_A(OIP, "TUN Interface %s successfully configured, IPv4 %s, IPv6 %s\n", ifname, ipv4, ipv6);
...@@ -233,11 +245,11 @@ bool tap_config(const char* ifname) ...@@ -233,11 +245,11 @@ bool tap_config(const char* ifname)
{ {
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd < 0) { if (sock_fd < 0) {
LOG_E(UTIL, "Failed creating socket for interface management: %d, %s\n", errno, strerror(errno)); LOG_E(UTIL, "tap_config: failed creating socket %d, %s\n", errno, strerror(errno));
return false; return false;
} }
bool success = set_if_flags(sock_fd, ifname, IFF_UP); const bool success = tuntap_set_up(ifname, sock_fd) >= 0;
if (success) if (success)
LOG_A(OIP, "TAP interface %s successfully configured\n", ifname); LOG_A(OIP, "TAP interface %s successfully configured\n", ifname);
...@@ -282,6 +294,7 @@ int tuntap_generate_ue_ifname(char *ifname, int flag, int instance_id, int pdu_s ...@@ -282,6 +294,7 @@ int tuntap_generate_ue_ifname(char *ifname, int flag, int instance_id, int pdu_s
char pdu_session_string[10]; char pdu_session_string[10];
snprintf(pdu_session_string, sizeof(pdu_session_string), "p%d", pdu_session_id); snprintf(pdu_session_string, sizeof(pdu_session_string), "p%d", pdu_session_id);
const char *basename = flag == IFF_TUN ? "oaitun_ue" : "oaitap_ue"; const char *basename = flag == IFF_TUN ? "oaitun_ue" : "oaitap_ue";
// ifname: oaitun_ue<ue_id+1>[p<pdu_session_id>] when not default
return snprintf(ifname, IFNAMSIZ, "%s%d%s", basename, instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string); return snprintf(ifname, IFNAMSIZ, "%s%d%s", basename, instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string);
} }
...@@ -295,7 +308,7 @@ void tuntap_destroy(const char *dev) ...@@ -295,7 +308,7 @@ void tuntap_destroy(const char *dev)
} }
// interface not up => down // interface not up => down
short flags; short flags = 0;
bool success = get_if_flags(fd, dev, &flags); bool success = get_if_flags(fd, dev, &flags);
success = success && set_if_flags(fd, dev, flags & ~IFF_UP); success = success && set_if_flags(fd, dev, flags & ~IFF_UP);
if (success) { if (success) {
......
...@@ -90,4 +90,12 @@ int tuntap_alloc(int flag, const char *dev); ...@@ -90,4 +90,12 @@ int tuntap_alloc(int flag, const char *dev);
*/ */
void tuntap_destroy(const char *dev); void tuntap_destroy(const char *dev);
/*!
* \brief Bring a TUN/TAP interface administratively up (IOCTL SIOCSIFFLAGS, set IFF_UP).
* \param[in] ifname name of the interface
* \param[in] sock_fd IPv4 SOCK_DGRAM fd for ioctl (opened by the caller)
* \return interface flags with IFF_UP set, or -1 on failure
*/
short tuntap_set_up(const char *ifname, int sock_fd);
#endif /*TUN_IF_H_*/ #endif /*TUN_IF_H_*/
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "SIMULATION/TOOLS/sim.h" // for taus #include "SIMULATION/TOOLS/sim.h" // for taus
#include "nr_nas_msg.h" #include "nr_nas_msg.h"
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
#include "openair2/SDAP/nr_sdap/nr_sdap_entity.h" #include "openair2/SDAP/nr_sdap/nr_sdap_entity.h"
static NR_UE_RRC_INST_t *NR_UE_rrc_inst[MAX_NUM_NR_UE_INST] = {0}; static NR_UE_RRC_INST_t *NR_UE_rrc_inst[MAX_NUM_NR_UE_INST] = {0};
......
...@@ -5,16 +5,30 @@ ...@@ -5,16 +5,30 @@
#include "nr_sdap.h" #include "nr_sdap.h"
#include "assertions.h" #include "assertions.h"
#include "utils.h" #include "utils.h"
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <pthread.h> #include <pthread.h>
#include <stddef.h> #include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "nr_sdap_entity.h" #include "nr_sdap_entity.h"
#include "common/utils/LOG/log.h" #include "common/utils/LOG/log.h"
#include "errno.h"
#include "rlc.h" #include "rlc.h"
#include "tuntap_if.h" #include "tuntap_if.h"
#include "system.h" #include "system.h"
typedef struct sdap_tun_iface_s {
ue_id_t ue_id;
int pdusession_id;
int sock;
char *ifname;
int qfi;
struct sdap_tun_iface_s *next;
} sdap_tun_iface_t;
static sdap_tun_iface_t *sdap_tun_iface_list = NULL;
static void reblock_tun_socket(int fd) static void reblock_tun_socket(int fd)
{ {
int f; int f;
...@@ -26,6 +40,88 @@ static void reblock_tun_socket(int fd) ...@@ -26,6 +40,88 @@ static void reblock_tun_socket(int fd)
} }
} }
static void *sdap_tun_read_thread(void *arg);
static sdap_tun_iface_t *sdap_tun_iface_lookup(ue_id_t ue_id, int pdusession_id)
{
for (sdap_tun_iface_t *it = sdap_tun_iface_list; it != NULL; it = it->next) {
if (it->ue_id == ue_id && it->pdusession_id == pdusession_id)
return it;
}
return NULL;
}
void nr_sdap_tun_store_qfi(ue_id_t ue_id, int pdusession_id, uint8_t qfi)
{
DevAssert(qfi < SDAP_MAX_QFI);
sdap_tun_iface_t *iface = sdap_tun_iface_lookup(ue_id, pdusession_id);
if (iface == NULL)
return;
iface->qfi = qfi;
}
void nr_sdap_tun_attach(nr_sdap_entity_t *entity)
{
DevAssert(entity);
if (entity->pdusession_sock >= 0)
return;
sdap_tun_iface_t *iface = sdap_tun_iface_lookup(entity->ue_id, entity->pdusession_id);
if (iface == NULL)
return;
if (!entity->is_gnb && iface->qfi >= 0 && iface->qfi < SDAP_MAX_QFI) {
entity->qfi = iface->qfi;
LOG_I(SDAP, "UE %ld PDU session %d: cached QFI %d\n", entity->ue_id, entity->pdusession_id, entity->qfi);
}
/* For UE, reflect UP suspend/resume to the OS by toggling IFF_UP. */
if (!entity->is_gnb) {
LOG_I(SDAP, "UE %ld PDU session %d: bringing TUN %s up\n", entity->ue_id, entity->pdusession_id, iface->ifname);
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd >= 0) {
tuntap_set_up(iface->ifname, fd);
close(fd);
}
}
int d = dup(iface->sock);
AssertFatal(d >= 0, "dup(tun sock) failed: errno %d %s\n", errno, strerror(errno));
reblock_tun_socket(d);
entity->pdusession_sock = d;
entity->stop_thread = false;
char thread_name[64];
if (entity->is_gnb) {
snprintf(thread_name, sizeof(thread_name), "gnb_tun_read_thread");
} else {
snprintf(thread_name,
sizeof(thread_name),
"ue_tun_read_%ld_p%d",
entity->ue_id,
entity->pdusession_id);
}
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, thread_name, -1, OAI_PRIORITY_RT_LOW);
}
static sdap_tun_iface_t *sdap_tun_iface_register(ue_id_t ue_id, int pdusession_id, int sock, const char *ifname)
{
DevAssert(sdap_tun_iface_lookup(ue_id, pdusession_id) == NULL);
sdap_tun_iface_t *iface = calloc_or_fail(1, sizeof(*iface));
iface->ue_id = ue_id;
iface->pdusession_id = pdusession_id;
iface->sock = sock;
iface->qfi = -1;
iface->ifname = strdup(ifname);
AssertFatal(iface->ifname != NULL, "strdup(ifname) failed\n");
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdusession_id);
if (entity != NULL && !entity->is_gnb && entity->qfi >= 0 && entity->qfi < SDAP_MAX_QFI)
iface->qfi = entity->qfi;
iface->next = sdap_tun_iface_list;
sdap_tun_iface_list = iface;
return iface;
}
bool sdap_data_req(protocol_ctxt_t *ctxt_p, bool sdap_data_req(protocol_ctxt_t *ctxt_p,
const ue_id_t ue_id, const ue_id_t ue_id,
...@@ -88,6 +184,7 @@ static void *sdap_tun_read_thread(void *arg) ...@@ -88,6 +184,7 @@ static void *sdap_tun_read_thread(void *arg)
char rx_buf[NL_MAX_PAYLOAD]; char rx_buf[NL_MAX_PAYLOAD];
int len; int len;
DevAssert(entity->pdusession_sock >= 0);
reblock_tun_socket(entity->pdusession_sock); reblock_tun_socket(entity->pdusession_sock);
while (!entity->stop_thread) { while (!entity->stop_thread) {
...@@ -112,11 +209,18 @@ static void *sdap_tun_read_thread(void *arg) ...@@ -112,11 +209,18 @@ static void *sdap_tun_read_thread(void *arg)
LOG_D(SDAP, "read data of size %d\n", len); LOG_D(SDAP, "read data of size %d\n", len);
if (!entity->is_gnb && entity->enable_sdap && (entity->qfi < 0 || entity->qfi >= SDAP_MAX_QFI)) {
LOG_W(SDAP,
"Dropping UL SDU for UE %ld PDU session %d: no QoS rule QFI available for SDAP header\n",
entity->ue_id,
entity->pdusession_id);
continue;
}
protocol_ctxt_t ctxt = {.enb_flag = entity->is_gnb, .rntiMaybeUEid = entity->ue_id}; protocol_ctxt_t ctxt = {.enb_flag = entity->is_gnb, .rntiMaybeUEid = entity->ue_id};
bool dc = entity->is_gnb ? false : SDAP_HDR_UL_DATA_PDU; bool dc = entity->is_gnb ? false : SDAP_HDR_UL_DATA_PDU;
DevAssert(entity != NULL);
entity->tx_entity(entity, entity->tx_entity(entity,
&ctxt, &ctxt,
SRB_FLAG_NO, SRB_FLAG_NO,
...@@ -134,6 +238,56 @@ static void *sdap_tun_read_thread(void *arg) ...@@ -134,6 +238,56 @@ static void *sdap_tun_read_thread(void *arg)
return NULL; return NULL;
} }
void nr_sdap_tun_detach(nr_sdap_entity_t *entity)
{
DevAssert(entity != NULL);
sdap_tun_iface_t *iface = NULL;
if (!entity->is_gnb) {
iface = sdap_tun_iface_lookup(entity->ue_id, entity->pdusession_id);
if (iface != NULL && entity->qfi >= 0 && entity->qfi < SDAP_MAX_QFI)
iface->qfi = entity->qfi; // store the QFI for the next attach
}
if (entity->pdusession_sock < 0)
return;
entity->stop_thread = true;
close(entity->pdusession_sock);
entity->pdusession_sock = -1;
/* For UE, bring interface down so the OS reflects UP suspension. */
if (!entity->is_gnb && iface != NULL) {
LOG_I(SDAP, "UE %ld PDU session %d: bringing TUN %s down\n", entity->ue_id, entity->pdusession_id, iface->ifname);
tuntap_destroy(iface->ifname);
}
int cancel_ret = pthread_cancel(entity->pdusession_thread);
AssertFatal(cancel_ret == 0, "pthread_cancel() failed: %d (%s)\n", cancel_ret, strerror(cancel_ret));
int ret = pthread_join(entity->pdusession_thread, NULL);
AssertFatal(ret == 0, "pthread_join() failed: %d (%s)\n", ret, strerror(ret));
}
void nr_sdap_tun_destroy(ue_id_t ue_id, int pdusession_id)
{
sdap_tun_iface_t *iface = NULL;
for (sdap_tun_iface_t **pp = &sdap_tun_iface_list; *pp != NULL; pp = &(*pp)->next) {
if ((*pp)->ue_id == ue_id && (*pp)->pdusession_id == pdusession_id) {
iface = *pp;
*pp = iface->next;
iface->next = NULL;
break;
}
}
if (iface == NULL) {
LOG_D(SDAP, "nr_sdap_tun_destroy: no iface (ue=%ld, pdu=%d)\n", ue_id, pdusession_id);
return;
}
close(iface->sock);
tuntap_destroy(iface->ifname);
LOG_I(SDAP, "Destroyed TUN dataplane for UE %ld PDU session %d (%s)\n", iface->ue_id, iface->pdusession_id, iface->ifname);
free(iface->ifname);
free(iface);
}
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_session_id) void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_session_id)
{ {
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id); nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
...@@ -142,10 +296,10 @@ void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_sess ...@@ -142,10 +296,10 @@ void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_sess
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb"; char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb";
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
tun_generate_ifname(ifname, ifprefix, ue_id - 1); tun_generate_ifname(ifname, ifprefix, ue_id - 1);
entity->pdusession_sock = tuntap_alloc(IFF_TUN, ifname); const int sock = tuntap_alloc(IFF_TUN, ifname);
entity->pdusession_if_name = strdup(ifname);
tun_config(ifname, "10.0.1.1", NULL); tun_config(ifname, "10.0.1.1", NULL);
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, "gnb_tun_read_thread", -1, OAI_PRIORITY_RT_LOW); sdap_tun_iface_register(entity->ue_id, entity->pdusession_id, sock, ifname);
nr_sdap_tun_attach(entity);
} }
static void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock, const char *ifname) static void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock, const char *ifname)
...@@ -153,51 +307,44 @@ static void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock, const ...@@ -153,51 +307,44 @@ static void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock, const
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id); nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
DevAssert(entity != NULL); DevAssert(entity != NULL);
DevAssert(!entity->is_gnb); DevAssert(!entity->is_gnb);
entity->pdusession_sock = sock; // First PDU session setup: register UE TUN and attach the reader thread
entity->pdusession_if_name = strdup(ifname); sdap_tun_iface_register(ue_id, pdu_session_id, sock, ifname);
entity->stop_thread = false; nr_sdap_tun_attach(entity);
char thread_name[64];
snprintf(thread_name, sizeof(thread_name), "ue_tun_read_%ld_p%d", ue_id, pdu_session_id);
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, 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, bool is_default) void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id, bool is_default)
{ {
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
tuntap_generate_ue_ifname(ifname, IFF_TUN, ue_id, is_default ? -1 : pdu_session_id); tuntap_generate_ue_ifname(ifname, IFF_TUN, ue_id, is_default ? -1 : pdu_session_id);
if (sdap_tun_iface_lookup(ue_id, pdu_session_id) == NULL) {
const int sock = tuntap_alloc(IFF_TUN, ifname); const int sock = tuntap_alloc(IFF_TUN, ifname);
start_sdap_tun_ue(ue_id, pdu_session_id, sock, ifname);
} else {
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
if (entity != NULL)
nr_sdap_tun_attach(entity);
}
tun_config(ifname, ipv4, ipv6); tun_config(ifname, ipv4, ipv6);
if (ipv4) { if (ipv4) {
setup_ue_ipv4_route(ifname, ue_id, ipv4); setup_ue_ipv4_route(ifname, ue_id, ipv4);
} }
start_sdap_tun_ue(ue_id, pdu_session_id, sock, ifname); // interface name suffix is ue_id+1
} }
void create_ue_eth_if(int ue_id, int pdu_session_id, bool is_default) void create_ue_eth_if(int ue_id, int pdu_session_id, bool is_default)
{ {
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
tuntap_generate_ue_ifname(ifname, IFF_TAP, ue_id, is_default ? -1 : pdu_session_id); tuntap_generate_ue_ifname(ifname, IFF_TAP, ue_id, is_default ? -1 : pdu_session_id);
if (sdap_tun_iface_lookup(ue_id, pdu_session_id) == NULL) {
const int sock = tuntap_alloc(IFF_TAP, ifname); const int sock = tuntap_alloc(IFF_TAP, ifname);
tap_config(ifname); // brings the interface up
start_sdap_tun_ue(ue_id, pdu_session_id, sock, ifname); start_sdap_tun_ue(ue_id, pdu_session_id, sock, ifname);
} } else {
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
void remove_ip_if(nr_sdap_entity_t *entity) if (entity != NULL)
{ nr_sdap_tun_attach(entity);
DevAssert(entity != NULL); }
DevAssert(entity->pdusession_if_name != NULL);
// Stop the read thread
entity->stop_thread = true;
// Close the socket: read() will get EBADF and exit
close(entity->pdusession_sock);
int ret = pthread_join(entity->pdusession_thread, NULL); tap_config(ifname);
AssertFatal(ret == 0, "pthread_join() failed, errno: %d, %s\n", errno, strerror(errno));
// Bring down the IP interface
tuntap_destroy(entity->pdusession_if_name);
free(entity->pdusession_if_name);
entity->pdusession_if_name = NULL;
} }
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <stdint.h> #include <stdint.h>
#include "common/platform_types.h" #include "common/platform_types.h"
struct nr_sdap_entity_s;
/* /*
* TS 37.324 4.4 Functions * TS 37.324 4.4 Functions
* Transfer of user plane data * Transfer of user plane data
...@@ -40,5 +42,9 @@ void sdap_data_ind(int pdcp_entity, int is_gnb, int pdusession_id, ue_id_t ue_id ...@@ -40,5 +42,9 @@ void sdap_data_ind(int pdcp_entity, int is_gnb, int pdusession_id, ue_id_t ue_id
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_session_id); void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_session_id);
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id, bool is_default); void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id, bool is_default);
void create_ue_eth_if(int ue_id, int pdu_session_id, bool is_default); void create_ue_eth_if(int ue_id, int pdu_session_id, bool is_default);
void nr_sdap_tun_attach(struct nr_sdap_entity_s *entity);
void nr_sdap_tun_detach(struct nr_sdap_entity_s *entity);
void nr_sdap_tun_destroy(ue_id_t ue_id, int pdusession_id);
void nr_sdap_tun_store_qfi(ue_id_t ue_id, int pdusession_id, uint8_t qfi);
#endif #endif
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <openair3/ocp-gtpu/gtp_itf.h> #include <openair3/ocp-gtpu/gtp_itf.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <unistd.h> #include <unistd.h>
#include "T.h" #include "T.h"
#include "assertions.h" #include "assertions.h"
...@@ -14,7 +15,6 @@ ...@@ -14,7 +15,6 @@
#include "gtpv1_u_messages_types.h" #include "gtpv1_u_messages_types.h"
#include "intertask_interface.h" #include "intertask_interface.h"
#include "rlc.h" #include "rlc.h"
#include "tuntap_if.h"
#include "nr_sdap.h" #include "nr_sdap.h"
#define NO_SDAP_HEADER 0 #define NO_SDAP_HEADER 0
...@@ -27,6 +27,15 @@ static nr_sdap_entity_info sdap_info; ...@@ -27,6 +27,15 @@ static nr_sdap_entity_info sdap_info;
instance_t *N3GTPUInst = NULL; instance_t *N3GTPUInst = NULL;
static void remove_ip_if(nr_sdap_entity_t *entity)
{
DevAssert(entity != NULL);
nr_sdap_tun_detach(entity);
if (!entity->is_gnb)
return;
nr_sdap_tun_destroy(entity->ue_id, entity->pdusession_id);
}
/** @brief Returns a bitmap indicating the SDAP entity role, /** @brief Returns a bitmap indicating the SDAP entity role,
* i.e. for UL transmission, header for UL data is present in RX/TX * i.e. for UL transmission, header for UL data is present in RX/TX
* for DL transmission, header for DL data is present in RX/TX */ * for DL transmission, header for DL data is present in RX/TX */
...@@ -338,6 +347,10 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, ...@@ -338,6 +347,10 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
* 5.2.2 Downlink * 5.2.2 Downlink
* deliver the retrieved SDAP SDU to the upper layer. * deliver the retrieved SDAP SDU to the upper layer.
*/ */
if (entity->pdusession_sock < 0) {
LOG_D(SDAP, "[UE %ld] PDU session %d: TUN not attached, drop DL SDU (%d B)\n", ue_id, pdusession_id, size - offset);
return;
}
int len = write(entity->pdusession_sock, &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 len : %d\n", len);
LOG_D(SDAP, "RX Entity size : %d\n", size); LOG_D(SDAP, "RX Entity size : %d\n", size);
...@@ -568,6 +581,13 @@ static void nr_sdap_add_entity(const int is_gnb, const ue_id_t ue_id, const sdap ...@@ -568,6 +581,13 @@ static void nr_sdap_add_entity(const int is_gnb, const ue_id_t ue_id, const sdap
// PDCP SDUs to/from the TUN interface. // PDCP SDUs to/from the TUN interface.
start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id, sdap_entity->pdusession_id); start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id, sdap_entity->pdusession_id);
} }
if (!is_gnb) {
/* No-op on first setup until NAS registers the TUN. After paging/service request,
* re-attach the preserved UE TUN for the established PDU session (TS 38.304 clause 7.1,
* TS 24.501 clauses 5.6.2.2.1/5.6.1.1 restore UP resources for an established PDU session). */
nr_sdap_tun_attach(sdap_entity);
}
} }
/** @brief Add or modify an SDAP entity if it already exists */ /** @brief Add or modify an SDAP entity if it already exists */
...@@ -692,7 +712,6 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id) ...@@ -692,7 +712,6 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) { if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) {
sdap_info.sdap_entity_llist = sdap_info.sdap_entity_llist->next_entity; sdap_info.sdap_entity_llist = sdap_info.sdap_entity_llist->next_entity;
if (entityPtr->pdusession_sock != -1)
remove_ip_if(entityPtr); remove_ip_if(entityPtr);
free(entityPtr); free(entityPtr);
LOG_D(SDAP, "Successfully deleted SDAP entity for UE %lx and PDU Session id %d\n", ue_id, pdusession_id); LOG_D(SDAP, "Successfully deleted SDAP entity for UE %lx and PDU Session id %d\n", ue_id, pdusession_id);
...@@ -707,9 +726,7 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id) ...@@ -707,9 +726,7 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) { if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) {
entityPrev->next_entity = entityPtr->next_entity; entityPrev->next_entity = entityPtr->next_entity;
if (entityPtr->pdusession_sock != -1) {
remove_ip_if(entityPtr); remove_ip_if(entityPtr);
}
free(entityPtr); free(entityPtr);
LOG_D(SDAP, "Successfully deleted Entity for UE %lx and PDU Session id %d\n", ue_id, pdusession_id); LOG_D(SDAP, "Successfully deleted Entity for UE %lx and PDU Session id %d\n", ue_id, pdusession_id);
return true; return true;
...@@ -734,7 +751,6 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id) ...@@ -734,7 +751,6 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id)
/* Handle scenario where ue_id matches the head of the list */ /* Handle scenario where ue_id matches the head of the list */
while (entityPtr != NULL && entityPtr->ue_id == ue_id && upperBound < MAX_DRBS_PER_UE) { while (entityPtr != NULL && entityPtr->ue_id == ue_id && upperBound < MAX_DRBS_PER_UE) {
sdap_info.sdap_entity_llist = entityPtr->next_entity; sdap_info.sdap_entity_llist = entityPtr->next_entity;
if (entityPtr->pdusession_sock != -1)
remove_ip_if(entityPtr); remove_ip_if(entityPtr);
free(entityPtr); free(entityPtr);
entityPtr = sdap_info.sdap_entity_llist; entityPtr = sdap_info.sdap_entity_llist;
...@@ -747,7 +763,6 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id) ...@@ -747,7 +763,6 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id)
entityPtr = entityPtr->next_entity; entityPtr = entityPtr->next_entity;
} else { } else {
entityPrev->next_entity = entityPtr->next_entity; entityPrev->next_entity = entityPtr->next_entity;
if (entityPtr->pdusession_sock != -1)
remove_ip_if(entityPtr); remove_ip_if(entityPtr);
free(entityPtr); free(entityPtr);
entityPtr = entityPrev->next_entity; entityPtr = entityPrev->next_entity;
...@@ -815,8 +830,9 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in ...@@ -815,8 +830,9 @@ 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) void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id)
{ {
DevAssert(qfi < SDAP_MAX_QFI);
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pduid); nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pduid);
DevAssert(entity != NULL); DevAssert(entity != NULL);
entity->qfi = qfi; entity->qfi = qfi;
return; nr_sdap_tun_store_qfi(ue_id, pduid, qfi);
} }
...@@ -85,7 +85,6 @@ typedef struct nr_sdap_entity_s { ...@@ -85,7 +85,6 @@ typedef struct nr_sdap_entity_s {
bool enable_sdap; bool enable_sdap;
int pdusession_id; int pdusession_id;
int pdusession_sock; int pdusession_sock;
char *pdusession_if_name;
pthread_t pdusession_thread; pthread_t pdusession_thread;
bool stop_thread; bool stop_thread;
int qfi; int qfi;
...@@ -186,5 +185,4 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in ...@@ -186,5 +185,4 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in
void nr_sdap_entity_update_qos_flows(ue_id_t ue_id, int pdusession_id, int drb_id, const uint8_t *qfis, int n_qfis); void nr_sdap_entity_update_qos_flows(ue_id_t ue_id, int pdusession_id, int drb_id, const uint8_t *qfis, int n_qfis);
void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id); void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id);
void remove_ip_if(nr_sdap_entity_t *entity);
#endif #endif
...@@ -2428,8 +2428,8 @@ void *nas_nrue(void *args_p) ...@@ -2428,8 +2428,8 @@ void *nas_nrue(void *args_p)
const char *ip = "10.0.1.2"; const char *ip = "10.0.1.2";
const int qfi = 7; const int qfi = 7;
const bool is_default = true; const bool is_default = true;
create_ue_ip_if(ip, NULL, nas->UE_id, pdu_session_id, is_default);
set_qfi(qfi, pdu_session_id, nas->UE_id); set_qfi(qfi, pdu_session_id, nas->UE_id);
create_ue_ip_if(ip, NULL, nas->UE_id, pdu_session_id, is_default);
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment