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:
@@ -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
@@ -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, ®_req->net_config, ®_req->setup_req);
|
createE1inst(UPtype, myInstance, reg_req->gnb_id, ®_req->net_config, ®_req->setup_req);
|
||||||
e1_task_send_sctp_association_req(TASK_CUUP_E1, myInstance, ®_req->net_config);
|
e1_task_send_sctp_association_req(TASK_CUUP_E1, myInstance, ®_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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user