Commit c90d7f7f authored by Aswanth KC's avatar Aswanth KC Committed by Robert Schmidt

fix: issue 911 - OAI gNB hangs when AMF connection goes down

- Extended fix to support multiple UEs instead of single UE
- Actions now trigger upon AMF reconnection

Per 3GPP TS 123 502 V16.7.0 (2021-01) Section 4.2.6 (AN Release):
When NG-AP signalling connection is lost due to (R)AN or AMF failure,
AN release is performed locally by AMF or (R)AN without relying on
signalling between (R)AN and AMF. This deactivates all UP connections.
parent 46b76706
......@@ -73,6 +73,7 @@ MESSAGE_DEF(NGAP_HANDOVER_NOTIFY, MESSAGE_PRIORITY_MED, ngap_handover_notify_t,
MESSAGE_DEF(NGAP_HANDOVER_CANCEL, MESSAGE_PRIORITY_MED, ngap_handover_cancel_t, ngap_handover_cancel)
MESSAGE_DEF(NGAP_UL_RAN_STATUS_TRANSFER, MESSAGE_PRIORITY_MED, ngap_ran_status_transfer_t, ngap_ul_ran_status_transfer)
MESSAGE_DEF(NGAP_DL_RAN_STATUS_TRANSFER, MESSAGE_PRIORITY_MED, ngap_ran_status_transfer_t, ngap_dl_ran_status_transfer)
MESSAGE_DEF(NGAP_RECONNECT_TIMER, MESSAGE_PRIORITY_MED, IttiMsgText, ngap_gNB_amf_data)
/* NGAP -> RRC messages */
MESSAGE_DEF(NGAP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, ngap_downlink_nas_t , ngap_downlink_nas )
......
......@@ -93,6 +93,38 @@ uint32_t ngap_generate_gNB_id(void)
return gNB_id;
}
static void ngap_gNB_redial_amf(ngap_gNB_amf_data_t *amf_desc_p)
{
NGAP_INFO("AMF cnx_id = %u\n", amf_desc_p->cnx_id);
NGAP_INFO("AMF state = %d\n", amf_desc_p->state);
/*reconnect with the amf */
MessageDef *message_p = itti_alloc_new_message(TASK_NGAP, 0, SCTP_NEW_ASSOCIATION_REQ);
sctp_new_association_req_t *req = &message_p->ittiMsg.sctp_new_association_req;
/*amf descriptor */
req->port = NGAP_PORT_NUMBER;
req->ppid = NGAP_SCTP_PPID;
req->in_streams = amf_desc_p->in_streams;
req->out_streams = amf_desc_p->out_streams;
req->ulp_cnx_id = amf_desc_p->cnx_id;
ngap_gNB_instance_t *inst = amf_desc_p->ngap_gNB_instance;
memcpy(&req->remote_address, &amf_desc_p->amf_s1_ip, sizeof(req->remote_address));
memcpy(&req->local_address, &inst->gNB_ng_ip, sizeof(req->local_address));
NGAP_INFO("[gNB %ld] Re-dial AMF cnx_id=%u (streams in=%u out=%u)\n",
inst->instance,
amf_desc_p->cnx_id,
req->in_streams,
req->out_streams);
inst->ngap_amf_nb++;
inst->ngap_amf_pending_nb++;
itti_send_msg_to_task(TASK_SCTP, inst->instance, message_p);
}
static void ngap_gNB_register_amf(ngap_gNB_instance_t *instance_p,
net_ip_address_t *amf_ip_address,
net_ip_address_t *local_ip_addr,
......@@ -550,6 +582,15 @@ void *ngap_gNB_process_itti_msg(void *notUsed) {
ngap_gNB_handle_sctp_association_resp(instance, &received_msg->ittiMsg.sctp_new_association_resp);
break;
case TIMER_HAS_EXPIRED: {
timer_has_expired_t *th = &received_msg->ittiMsg.timer_has_expired;
ngap_gNB_amf_data_t *amf_desc_p = (ngap_gNB_amf_data_t *)th->arg;
if (amf_desc_p) {
ngap_gNB_redial_amf(amf_desc_p);
}
break;
}
case SCTP_DATA_IND:
ngap_gNB_handle_sctp_data_ind(&received_msg->ittiMsg.sctp_data_ind);
break;
......
......@@ -161,6 +161,8 @@ struct ngap_gNB_instance_s;
/* This structure describes association of a gNB to a AMF */
typedef struct ngap_gNB_amf_data_s {
long t_reconnect; // ITTI timer id (or equivalent)
/* AMF descriptors tree, ordered by sctp assoc id */
RB_ENTRY(ngap_gNB_amf_data_s) entry;
......
......@@ -77,6 +77,8 @@ void ngap_handle_ng_setup_message(ngap_gNB_amf_data_t *amf_desc_p, int sctp_shut
/* Decrease associated AMF number */
amf_desc_p->ngap_gNB_instance->ngap_amf_associated_nb --;
}
/* Release UE context and start reconnection process*/
ngap_release_ues_for_amf(amf_desc_p);
/* If there are no more associated AMF, inform gNB app */
if (amf_desc_p->ngap_gNB_instance->ngap_amf_associated_nb == 0) {
......
......@@ -59,7 +59,7 @@
#include "s1ap_messages_types.h"
#include "xer_encoder.h"
#include "ds/byte_array.h"
#include "intertask_interface.h"
/** @brief Selects the AMF instance for a given UE based on identity information.
* It attempts to select an AMF using the following prioritized criteria:
* 1. GUAMI, if provided and valid (via Region ID, Set ID, Pointer).
......
......@@ -34,6 +34,8 @@
#include "common/utils/T/T.h"
#include "ngap_common.h"
#include "tree.h"
#include "intertask_interface.h"
#define SCTP_LOOKUP_TIMER_TIMEOUT_SEC 30
/* Tree of UE ordered by gNB_ue_ngap_id's
* NO INSTANCE, the 32 bits id is large enough to handle all UEs, regardless the cell, gNB, ...
......@@ -92,3 +94,31 @@ struct ngap_gNB_ue_context_s *ngap_detach_ue_context(uint32_t gNB_ue_ngap_id)
RB_REMOVE(ngap_ue_map, &ngap_ue_head, tmp);
return tmp;
}
void ngap_release_ues_for_amf(ngap_gNB_amf_data_t *amf_desc_p)
{
/* Release all UE contexts for this AMF */
ngap_gNB_ue_context_t *ue = NULL;
ngap_gNB_ue_context_t *next = NULL;
RB_FOREACH_SAFE(ue, ngap_ue_map, &ngap_ue_head, next) {
if (ue->amf_ref == amf_desc_p) {
LOG_I(NGAP, "Releasing UE context: gNB UE NGAP ID: %u | AMF UE NGAP ID: %lu\n", ue->gNB_ue_ngap_id, ue->amf_ue_ngap_id);
MessageDef *msg_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_UE_CONTEXT_RELEASE_COMMAND);
NGAP_UE_CONTEXT_RELEASE_COMMAND(msg_p).gNB_ue_ngap_id = ue->gNB_ue_ngap_id;
itti_send_msg_to_task(TASK_RRC_GNB, amf_desc_p->ngap_gNB_instance->instance, msg_p);
}
}
/* Reset AMF connection and set reconnect timer */
/* SCTP lookup timer */
long tid;
int rc = timer_setup(SCTP_LOOKUP_TIMER_TIMEOUT_SEC,
0,
TASK_NGAP,
amf_desc_p->ngap_gNB_instance->instance,
TIMER_ONE_SHOT,
amf_desc_p,
&tid);
if (rc == 0) {
amf_desc_p->t_reconnect = tid;
}
}
......@@ -74,6 +74,7 @@ typedef struct ngap_gNB_ue_context_s {
} ngap_gNB_ue_context_t;
void ngap_store_ue_context(const ngap_gNB_ue_context_t *ue_desc_p);
void ngap_release_ues_for_amf(ngap_gNB_amf_data_t *amf_desc_p);
ngap_gNB_ue_context_t *ngap_get_ue_context(uint32_t gNB_ue_ngap_id);
ngap_gNB_ue_context_t *ngap_get_ue_context_from_amf_ue_ngap_id(uint32_t amf_ue_ngap_id);
......
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