Refactor SCTP association response handler

* this function is used by both CU-CP and CU-UP
* it behaves differently depending on the type of E1 instance:
  CU-CP: inform RRC of E1 connection loss with CU-UP
  CU-UP: trigger a new SCTP association request by sending an ITTI to the CU-UP task
* after receiving the E1AP register request, the CU-UP will send a new association request to
  SCTP until new E1 connection is achieved by sending a TIMER_HAS_EXPIRED message to the CU-UP
  task. The function e1apHandleTimer() is basically triggering a new E1 association request
  until new E1 connection is achieved
* print SCTP association state in e1ap.c whenever needed

Related to #878
This commit is contained in:
Guido Casati
2025-01-14 14:13:49 +01:00
parent b922fd2649
commit bcd1270237
6 changed files with 57 additions and 28 deletions
+17 -6
View File
@@ -36,11 +36,22 @@
#define SCTP_INIT_MSG_MULTI_CNF(mSGpTR) (mSGpTR)->ittiMsg.sctp_init_msg_multi_cnf #define SCTP_INIT_MSG_MULTI_CNF(mSGpTR) (mSGpTR)->ittiMsg.sctp_init_msg_multi_cnf
#define SCTP_CLOSE_ASSOCIATION(mSGpTR) (mSGpTR)->ittiMsg.sctp_close_association #define SCTP_CLOSE_ASSOCIATION(mSGpTR) (mSGpTR)->ittiMsg.sctp_close_association
enum sctp_state_e { #define SCTP_STATES \
SCTP_STATE_CLOSED, ITEM(SCTP_STATE_CLOSED) \
SCTP_STATE_SHUTDOWN, ITEM(SCTP_STATE_SHUTDOWN) \
SCTP_STATE_ESTABLISHED, ITEM(SCTP_STATE_ESTABLISHED) \
SCTP_STATE_UNREACHABLE ITEM(SCTP_STATE_UNREACHABLE)
typedef enum {
#define ITEM(state) state,
SCTP_STATES
#undef ITEM
} sctp_state_e;
static const char *sctp_state_s[] __attribute__((unused)) = {
#define ITEM(state) #state,
SCTP_STATES
#undef ITEM
}; };
typedef struct sctp_new_association_req_s { typedef struct sctp_new_association_req_s {
@@ -112,7 +123,7 @@ typedef struct sctp_new_association_resp_s {
uint16_t in_streams; uint16_t in_streams;
/* State of the association at SCTP level */ /* State of the association at SCTP level */
enum sctp_state_e sctp_state; sctp_state_e sctp_state;
} sctp_new_association_resp_t; } sctp_new_association_resp_t;
typedef struct sctp_data_ind_s { typedef struct sctp_data_ind_s {
+36 -18
View File
@@ -1281,6 +1281,13 @@ static void e1apCUUP_send_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_setup_req_t
e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__); e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__);
} }
/**
* @brief SCTP association response handler (CU-CP to/from CU-UP)
* it behaves differently depending on the type of E1 instance,
* CUCP: informs RRC of E1 connection loss with CU-UP
* CUUP: triggers a new SCTP association request by sending an ITTI to the CU-UP task
* @param type indicates whether the handler is for the CU-CP or CU-UP
*/
static void e1_task_handle_sctp_association_resp(E1_t type, static void e1_task_handle_sctp_association_resp(E1_t type,
instance_t instance, instance_t instance,
sctp_new_association_resp_t *sctp_new_association_resp) sctp_new_association_resp_t *sctp_new_association_resp)
@@ -1288,24 +1295,26 @@ static void e1_task_handle_sctp_association_resp(E1_t type,
DevAssert(sctp_new_association_resp != NULL); DevAssert(sctp_new_association_resp != NULL);
getCxtE1(instance)->sockState = sctp_new_association_resp->sctp_state; getCxtE1(instance)->sockState = sctp_new_association_resp->sctp_state;
if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN) { // Handle SCTP establishment failure
LOG_I(E1AP, "Received SCTP shutdown for assoc_id %d, removing CUCP endpoint\n", sctp_new_association_resp->assoc_id);
/* inform RRC that the CU-UP is gone */
MessageDef *message_p = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_LOST_CONNECTION);
message_p->ittiMsgHeader.originInstance = sctp_new_association_resp->assoc_id;
itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p);
return;
}
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
LOG_W(E1AP, if (type == CPtype) {
"Received unsuccessful result for SCTP association (%u), instance " // Inform RRC that the CU-UP is gone
"%ld, cnx_id %u\n", LOG_W(E1AP,
sctp_new_association_resp->sctp_state, "Lost connection (%s) with CU-UP (assoc_id %d)\n",
instance, sctp_state_s[sctp_new_association_resp->sctp_state],
sctp_new_association_resp->ulp_cnx_id); sctp_new_association_resp->assoc_id);
long timer_id; // if we want to cancel timer MessageDef *message_p = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_LOST_CONNECTION);
timer_setup(1, 0, TASK_CUUP_E1, 0, TIMER_ONE_SHOT, NULL, &timer_id); message_p->ittiMsgHeader.originInstance = sctp_new_association_resp->assoc_id;
itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p);
} else if (type == UPtype) {
// Trigger new E1 association when no CU-CP is connected
LOG_W(E1AP,
"Lost connection (%s) with CU-CP (assoc_id %d): trigger new E1 association\n",
sctp_state_s[sctp_new_association_resp->sctp_state],
sctp_new_association_resp->assoc_id);
long timer_id;
timer_setup(1, 0, TASK_CUUP_E1, 0, TIMER_ONE_SHOT, NULL, &timer_id);
}
return; return;
} }
@@ -1373,7 +1382,11 @@ void e1_task_handle_sctp_association_ind(E1_t type, instance_t instance, sctp_ne
inst->cuup.assoc_id = sctp_new_ind->assoc_id; inst->cuup.assoc_id = sctp_new_ind->assoc_id;
} }
void e1apHandleTimer(instance_t myInstance) /**
* @brief Handle the timer triggered by a connection loss with CU-CP
* it uses a stored network configuration and send a new SCTP association request
*/
static void e1apHandleTimer(instance_t myInstance)
{ {
LOG_W(E1AP, "Try to reconnect to CP\n"); LOG_W(E1AP, "Try to reconnect to CP\n");
if (getCxtE1(myInstance)->sockState != SCTP_STATE_ESTABLISHED) if (getCxtE1(myInstance)->sockState != SCTP_STATE_ESTABLISHED)
@@ -1483,6 +1496,8 @@ void *E1AP_CUUP_task(void *arg)
LOG_D(E1AP, "CUUP received %s for instance %ld\n", messages_info[msgType].name, myInstance); LOG_D(E1AP, "CUUP received %s for instance %ld\n", messages_info[msgType].name, myInstance);
switch (msgType) { switch (msgType) {
case E1AP_REGISTER_REQ: { case E1AP_REGISTER_REQ: {
/* E1AP Register Request triggered at startup
create a new E1 instance and send the first association request */
e1ap_register_req_t *reg_req = &E1AP_REGISTER_REQ(msg); e1ap_register_req_t *reg_req = &E1AP_REGISTER_REQ(msg);
createE1inst(UPtype, myInstance, reg_req->gnb_id, &reg_req->net_config, &reg_req->setup_req); createE1inst(UPtype, myInstance, reg_req->gnb_id, &reg_req->net_config, &reg_req->setup_req);
e1_task_send_sctp_association_req(TASK_CUUP_E1, myInstance, &reg_req->net_config); e1_task_send_sctp_association_req(TASK_CUUP_E1, myInstance, &reg_req->net_config);
@@ -1490,6 +1505,8 @@ void *E1AP_CUUP_task(void *arg)
case SCTP_NEW_ASSOCIATION_RESP: case SCTP_NEW_ASSOCIATION_RESP:
e1_task_handle_sctp_association_resp(UPtype, myInstance, &msg->ittiMsg.sctp_new_association_resp); e1_task_handle_sctp_association_resp(UPtype, myInstance, &msg->ittiMsg.sctp_new_association_resp);
if (getCxtE1(myInstance)->sockState == SCTP_STATE_ESTABLISHED)
LOG_A(E1AP, "E1 connection established (%s)\n", sctp_state_s[getCxtE1(myInstance)->sockState]);
break; break;
case SCTP_DATA_IND: case SCTP_DATA_IND:
@@ -1497,6 +1514,7 @@ void *E1AP_CUUP_task(void *arg)
break; break;
case TIMER_HAS_EXPIRED: case TIMER_HAS_EXPIRED:
// Timer triggered by a connection loss with CU-CP
e1apHandleTimer(myInstance); e1apHandleTimer(myInstance);
break; break;
+1 -1
View File
@@ -31,7 +31,7 @@ typedef struct e1ap_upcp_inst_s {
instance_t instance; instance_t instance;
uint32_t gnb_id; // associated gNB's ID, unused in E1 but necessary for e.g. E2 agent uint32_t gnb_id; // associated gNB's ID, unused in E1 but necessary for e.g. E2 agent
E1_t type; E1_t type;
enum sctp_state_e sockState; sctp_state_e sockState;
struct { struct {
sctp_assoc_t assoc_id; sctp_assoc_t assoc_id;
e1ap_setup_req_t setupReq; e1ap_setup_req_t setupReq;
+1 -1
View File
@@ -65,7 +65,7 @@ static void cu_task_handle_sctp_association_ind(instance_t instance,
static void cu_task_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) { static void cu_task_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) {
DevAssert(sctp_new_association_resp != NULL); DevAssert(sctp_new_association_resp != NULL);
enum sctp_state_e state = sctp_new_association_resp->sctp_state; sctp_state_e state = sctp_new_association_resp->sctp_state;
if (state != SCTP_STATE_ESTABLISHED) { if (state != SCTP_STATE_ESTABLISHED) {
f1ap_cudu_inst_t *f1ap_cu_data = getCxt(instance); f1ap_cudu_inst_t *f1ap_cu_data = getCxt(instance);
AssertFatal(f1ap_cu_data != NULL, "illegal state: SCTP shutdown for non-existing F1AP endpoint\n"); AssertFatal(f1ap_cu_data != NULL, "illegal state: SCTP shutdown for non-existing F1AP endpoint\n");
+1 -1
View File
@@ -68,7 +68,7 @@ int sctp_itti_send_association_resp(task_id_t task_id,
instance_t instance, instance_t instance,
sctp_assoc_t assoc_id, sctp_assoc_t assoc_id,
uint16_t cnx_id, uint16_t cnx_id,
enum sctp_state_e state, sctp_state_e state,
uint16_t out_streams, uint16_t out_streams,
uint16_t in_streams) uint16_t in_streams)
{ {
+1 -1
View File
@@ -35,7 +35,7 @@ int sctp_itti_send_association_resp(task_id_t task_id,
instance_t instance, instance_t instance,
sctp_assoc_t assoc_id, sctp_assoc_t assoc_id,
uint16_t cnx_id, uint16_t cnx_id,
enum sctp_state_e state, sctp_state_e state,
uint16_t out_streams, uint16_t out_streams,
uint16_t in_streams); uint16_t in_streams);