From e52203f739a9b148b4a06b74a87da73df16e6804 Mon Sep 17 00:00:00 2001 From: Brendan Date: Wed, 14 Dec 2022 12:29:21 +0100 Subject: [PATCH] e2ap, ric: add support for ric reset request and response --- srsgnb/hdr/stack/ric/e2ap.h | 11 ++++- srsgnb/hdr/stack/ric/ric_client.h | 15 +++++- srsgnb/src/stack/ric/e2ap.cc | 52 ++++++++++++++++++++- srsgnb/src/stack/ric/ric_client.cc | 64 ++++++++++++++++++++++---- srsgnb/src/stack/ric/test/e2ap_test.cc | 44 +++++++++++++++++- 5 files changed, 173 insertions(+), 13 deletions(-) diff --git a/srsgnb/hdr/stack/ric/e2ap.h b/srsgnb/hdr/stack/ric/e2ap.h index e20e83a28..d17b4e231 100644 --- a/srsgnb/hdr/stack/ric/e2ap.h +++ b/srsgnb/hdr/stack/ric/e2ap.h @@ -47,6 +47,11 @@ public: e2_ap_pdu_c generate_subscription_response(); int generate_subscription_failure(); int generate_indication(); + e2_ap_pdu_c generate_reset_request(); + e2_ap_pdu_c generate_reset_response(); + int process_reset_request(reset_request_s reset_request); + int process_reset_response(reset_resp_s reset_response); + int get_reset_id(); bool has_setup_response() { return setup_response_received; } private: @@ -57,9 +62,13 @@ private: int setup_procedure_transaction_id = 0; uint64_t plmn_id = 3617847; uint64_t gnb_id = 381210353; - global_ric_id_t global_ric_id = {}; + global_ric_id_t global_ric_id = {}; std::map ran_functions; srsenb::e2_interface_metrics* gnb_metrics = nullptr; + bool reset_response_received = false; + int reset_transaction_id = 1; + cause_c reset_cause = cause_c(); + int reset_id = 1; }; #endif /* RIC_E2AP_H */ diff --git a/srsgnb/hdr/stack/ric/ric_client.h b/srsgnb/hdr/stack/ric/ric_client.h index 69a78db0a..e78cc34c6 100644 --- a/srsgnb/hdr/stack/ric/ric_client.h +++ b/srsgnb/hdr/stack/ric/ric_client.h @@ -22,24 +22,35 @@ #include "srsran/srsran.h" static const int e2ap_ppid = 70; static const int e2ap_port = 36422; -enum e2_msg_type_t { E2_SETUP_REQUEST, E2_SUB_RESPONSE, E2_INDICATION }; + +enum e2_msg_type_t { E2_SETUP_REQUEST, E2_SUB_RESPONSE, E2_INDICATION, E2_RESET, E2_RESET_RESPONSE }; + namespace srsenb { class ric_client : public srsran::thread { public: ric_client(srslog::basic_logger& logger, srsenb::e2_interface_metrics* _gnb_metrics); + + // Initiate and Stop bool init(); void stop(); void run_thread(); + + // Send messages to RIC bool send_sctp(srsran::unique_byte_buffer_t& buf); bool send_e2_msg(e2_msg_type_t msg_type); + bool send_reset_response(); + + // Handle messages received from RIC bool - handle_e2_rx_msg(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags); + handle_e2_rx_msg(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags); bool handle_e2_init_msg(asn1::e2ap::init_msg_s& init_msg); bool handle_e2_successful_outcome(asn1::e2ap::successful_outcome_s& successful_outcome); bool handle_e2_unsuccessful_outcome(asn1::e2ap::unsuccessful_outcome_s& unsuccessful_outcome); bool handle_e2_setup_response(e2setup_resp_s setup_response); bool handle_ric_subscription_request(ricsubscription_request_s ric_subscription_request); + bool handle_reset_response(reset_resp_s& reset_response); + bool handle_reset_request(reset_request_s& reset_request); private: e2ap e2ap_; diff --git a/srsgnb/src/stack/ric/e2ap.cc b/srsgnb/src/stack/ric/e2ap.cc index 46248e4b9..85d2d96f8 100644 --- a/srsgnb/src/stack/ric/e2ap.cc +++ b/srsgnb/src/stack/ric/e2ap.cc @@ -16,9 +16,13 @@ e2_ap_pdu_c e2ap::generate_setup_request() e2setup_request_s& setup = initmsg.value.e2setup_request(); setup->transaction_id.crit = asn1::crit_opts::reject; +<<<<<<< HEAD setup->transaction_id.value.value = setup_procedure_transaction_id; setup->global_e2node_id.crit = asn1::crit_opts::reject; auto& gnb_ = setup->global_e2node_id.value.set_gnb(); +======= + setup->transaction_id.value.value = transaction_id; +>>>>>>> 456170567 (e2ap, ric: add support for ric reset request and response) gnb_.global_g_nb_id.plmn_id.from_number(plmn_id); gnb_.global_g_nb_id.gnb_id.gnb_id().from_number(gnb_id); @@ -114,4 +118,50 @@ int e2ap::process_subscription_request(ricsubscription_request_s subscription_re pending_subscription_request = true; // TODO process subscription request return 0; -} \ No newline at end of file +} +e2_ap_pdu_c e2ap::generate_reset_request() +{ + using namespace asn1::e2ap; + e2_ap_pdu_c pdu; + init_msg_s& request = pdu.set_init_msg(); + request.load_info_obj(ASN1_E2AP_ID_RESET); + reset_request_s& reset_request = request.value.reset_request(); + reset_request->transaction_id.crit = asn1::crit_opts::reject; + reset_request->transaction_id.value.value = reset_transaction_id; + reset_request->cause.crit = asn1::crit_opts::ignore; + reset_request->cause.value.set_misc(); + return pdu; +} + +e2_ap_pdu_c e2ap::generate_reset_response() +{ + e2_ap_pdu_c pdu; + successful_outcome_s& response = pdu.set_successful_outcome(); + response.load_info_obj(ASN1_E2AP_ID_RESET); + reset_resp_s& reset_response = response.value.reset_resp(); + reset_response->transaction_id.crit = asn1::crit_opts::reject; + reset_response->transaction_id.value.value = reset_transaction_id; + return pdu; +} + +int e2ap::process_reset_request(reset_request_s reset_request) +{ + reset_id = reset_request->transaction_id.value; + + // TO DO: Parse and store the cause for future extension of the ric client + + return 0; +} + +int e2ap::process_reset_response(reset_resp_s reset_response) +{ + // TO DO process reset response from RIC + reset_response_received = true; + + return 0; +} + +int e2ap::get_reset_id() +{ + return reset_id; +} diff --git a/srsgnb/src/stack/ric/ric_client.cc b/srsgnb/src/stack/ric/ric_client.cc index 3d506450d..e7f5eea89 100644 --- a/srsgnb/src/stack/ric/ric_client.cc +++ b/srsgnb/src/stack/ric/ric_client.cc @@ -20,6 +20,7 @@ ric_client::ric_client(srslog::basic_logger& logger, e2_interface_metrics* _gnb_ { gnb_metrics = _gnb_metrics; } + bool ric_client::init() { printf("RIC_CLIENT: Init\n"); @@ -35,7 +36,6 @@ bool ric_client::init() } // Bind socket - if (not ric_socket.bind_addr("172.17.0.3", 36422)) { ric_socket.close(); return false; @@ -59,13 +59,17 @@ bool ric_client::init() start(0); return SRSRAN_SUCCESS; } + void ric_client::stop() { running = false; wait_thread_finish(); } + void ric_client::run_thread() { + using namespace asn1::e2ap; + while (running) { if (!e2ap_.has_setup_response()) { send_e2_msg(E2_SETUP_REQUEST); @@ -73,9 +77,9 @@ void ric_client::run_thread() } sleep(1); task_sched.run_next_task(); - sleep(5); } } + bool ric_client::send_sctp(srsran::unique_byte_buffer_t& buf) { ssize_t ret; @@ -98,6 +102,7 @@ bool ric_client::send_sctp(srsran::unique_byte_buffer_t& buf) bool ric_client::send_e2_msg(e2_msg_type_t msg_type) { + std::string message_name; srsran::unique_byte_buffer_t buf = srsran::make_byte_buffer(); if (buf == nullptr) { // logger.error("Fatal Error: Couldn't allocate buffer for %s.", procedure_name); @@ -107,13 +112,23 @@ bool ric_client::send_e2_msg(e2_msg_type_t msg_type) switch (msg_type) { case e2_msg_type_t::E2_SETUP_REQUEST: send_pdu = e2ap_.generate_setup_request(); + message_name = "E2 SETUP REQUEST"; break; case e2_msg_type_t::E2_SUB_RESPONSE: send_pdu = e2ap_.generate_subscription_response(); + message_name = "E2 SUBSCRIPTION RESPONSE"; break; case e2_msg_type_t::E2_INDICATION: // TODO create E2 INDICATION generation break; + case e2_msg_type_t::E2_RESET: + send_pdu = e2ap_.generate_reset_request(); + message_name = "E2 RESET REQUEST"; + break; + case e2_msg_type_t::E2_RESET_RESPONSE: + send_pdu = e2ap_.generate_reset_response(); + message_name = "E2 RESET RESPONSE"; + break; default: printf("Unknown E2AP message type\n"); return false; @@ -126,7 +141,7 @@ bool ric_client::send_e2_msg(e2_msg_type_t msg_type) buf->N_bytes = bref.distance_bytes(); printf("try to send %d bytes to addr %s \n", buf->N_bytes, inet_ntoa(ric_addr.sin_addr)); if (!send_sctp(buf)) { - logger.error("failed to send e2 setup request"); + logger.error("failed to send {}", message_name); return false; } return true; @@ -176,7 +191,7 @@ bool ric_client::handle_e2_init_msg(asn1::e2ap::init_msg_s& init_msg) //handle_e2conn_upd(init_msg.value.e2conn_upd()); } else if (init_msg.value.type() == e2_ap_elem_procs_o::init_msg_c::types_opts::reset_request) { logger.info("Received E2AP E2 Reset Request"); - //handle_reset_request(init_msg.value.reset_request()); + handle_reset_request(init_msg.value.reset_request()); } else if (init_msg.value.type() == e2_ap_elem_procs_o::init_msg_c::types_opts::e2_removal_request) { logger.info("Received E2AP E2 Removal Request"); //handle_e2_removal_request(init_msg.value.e2_removal_request()); @@ -209,9 +224,9 @@ bool ric_client::handle_e2_successful_outcome(asn1::e2ap::successful_outcome_s& e2_ap_elem_procs_o::successful_outcome_c::types_opts::ricsubscription_delete_resp) { logger.info("Received E2AP RIC Subscription Delete Response \n"); // handle_ric_subscription_delete_response(successful_outcome.value.ric_subscription_delete()); - } else if (successful_outcome.value.type() == e2_ap_elem_procs_o::successful_outcome_c::types_opts::e2_removal_resp) { - logger.info("Received E2AP RIC Service Status Successful Outcome \n"); - // handle_e2_removal_response(successful_outcome.value.e2_removal()); + } else if (successful_outcome.value.type() == e2_ap_elem_procs_o::successful_outcome_c::types_opts::reset_resp) { + logger.info("Received E2AP RIC Reset Response \n"); + handle_reset_response(successful_outcome.value.reset_resp()); } else { logger.info("Received E2AP Unknown Successful Outcome \n"); } @@ -221,7 +236,7 @@ bool ric_client::handle_e2_successful_outcome(asn1::e2ap::successful_outcome_s& bool ric_client::handle_e2_setup_response(e2setup_resp_s setup_response) { if (e2ap_.process_setup_response(setup_response)) { - logger.error("Failed to process E2 Setup Response"); + logger.error("Failed to process E2 Setup Response \n"); return false; } return true; @@ -245,3 +260,36 @@ bool ric_client::handle_ric_subscription_request(ricsubscription_request_s ric_s // TODO handle RIC subscription request return true; } + +bool ric_client::handle_reset_request(reset_request_s& reset_request) +{ + printf("Received E2AP E2 Reset Request \n"); + // call process to handle reset request, if it fails log error and return false, else return true - success + if (e2ap_.process_reset_request(reset_request)) { + logger.error("Failed to process E2 Reset Request \n"); + return false; + } + + logger.info("Reset transaction with ID = {}", e2ap_.get_reset_id()); + + // send reset reset response + auto send_reset_resp = [this]() { send_e2_msg(E2_RESET_RESPONSE); }; + ric_rece_task_queue.push(send_reset_resp); + + return true; +} + +bool ric_client::handle_reset_response(reset_resp_s& reset_response) +{ + printf("Received E2AP E2 Reset Response \n"); + // call process to handle reset reponse, if it fails log error, else return true - success + // all processing of message will be done in process_reset_response (e2ap.cc) + if (e2ap_.process_reset_response(reset_response)) { + logger.error("Failed to process E2 Reset Response \n"); + return false; + } + + logger.info("Reset Response successfully processed \n"); + + return true; +} diff --git a/srsgnb/src/stack/ric/test/e2ap_test.cc b/srsgnb/src/stack/ric/test/e2ap_test.cc index 1504a50b4..f7d25bae2 100644 --- a/srsgnb/src/stack/ric/test/e2ap_test.cc +++ b/srsgnb/src/stack/ric/test/e2ap_test.cc @@ -142,6 +142,26 @@ void test_native_e2ap_subscription_response() e2ap e2ap_(logger, &dummy_metrics); pdu = e2ap_.generate_subscription_response(); + pdu = e2ap_.generate_subscription_response(); + asn1::bit_ref bref(buf->msg, buf->get_tailroom()); + if (pdu.pack(bref) != asn1::SRSASN_SUCCESS) { + printf("Failed to pack TX E2 PDU\n"); + return; + } + + asn1::cbit_ref bref2(buf->msg, buf->get_tailroom()); + asn1::SRSASN_CODE unpack_ret = pdu2.unpack(bref2); + TESTASSERT_EQ(asn1::SRSASN_SUCCESS, unpack_ret); + printf("Unpacked native E2AP PDU (subscription response) %d\n", (int)unpack_ret); +} + +void test_native_e2ap_reset_request() +{ + srsran::unique_byte_buffer_t buf = srsran::make_byte_buffer(); + e2_ap_pdu_c pdu, pdu2; + e2ap e2ap_; + + pdu = e2ap_.generate_reset_request(); asn1::bit_ref bref(buf->msg, buf->get_tailroom()); if (pdu.pack(bref) != asn1::SRSASN_SUCCESS) { printf("Failed to pack TX E2 PDU\n"); @@ -149,11 +169,30 @@ void test_native_e2ap_subscription_response() } asn1::cbit_ref bref2(buf->msg, buf->get_tailroom()); + asn1::SRSASN_CODE unpack_ret = pdu2.unpack(bref2); + TESTASSERT_EQ(asn1::SRSASN_SUCCESS, unpack_ret); + printf("Unpacked native E2AP PDU RESET %d\n", (int)unpack_ret); +} + +void test_native_e2ap_reset_response() +{ + srsran::unique_byte_buffer_t buf = srsran::make_byte_buffer(); + e2_ap_pdu_c pdu, pdu2; + e2ap e2ap_; + pdu = e2ap_.generate_reset_response(); + asn1::bit_ref bref(buf->msg, buf->get_tailroom()); + if (pdu.pack(bref) != asn1::SRSASN_SUCCESS) { + printf("Failed to pack TX E2 PDU\n"); + return; + } + + asn1::cbit_ref bref2(buf->msg, buf->get_tailroom()); asn1::SRSASN_CODE unpack_ret = pdu2.unpack(bref2); TESTASSERT_EQ(asn1::SRSASN_SUCCESS, unpack_ret); - printf("Unpacked native E2AP PDU (subscription response) %d\n", (int)unpack_ret); + printf("Unpacked native E2AP PDU RESET RESPONSE %d\n", (int)unpack_ret); } +// add tets for set-up request and response int main() { @@ -161,5 +200,8 @@ int main() test_native_e2ap_setup_request(); test_reference_e2ap_subscription_request(); test_native_e2ap_subscription_response(); + test_native_e2ap_reset_request(); + test_native_e2ap_reset_response(); + // call reset test functions here return 0; } \ No newline at end of file