Skip to content

Commit b9adc66

Browse files
author
Piotr Gawlowicz
committed
e2: add e2 connection update procedure, that sends failure
1 parent e516b8d commit b9adc66

File tree

8 files changed

+283
-0
lines changed

8 files changed

+283
-0
lines changed

lib/e2/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ set(SOURCES
1212
procedures/e2_subscription_delete_procedure.cpp
1313
procedures/e2_indication_procedure.cpp
1414
procedures/e2_ric_control_procedure.cpp
15+
procedures/e2_connection_update_procedure.cpp
1516
common/e2_connection_handler.cpp
1617
common/e2ap_asn1_packer.cpp
1718
common/e2_factory.cpp

lib/e2/common/e2_impl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "e2_impl.h"
1212
#include "e2ap_asn1_helpers.h"
13+
#include "procedures/e2_connection_update_procedure.h"
1314
#include "srsran/asn1/e2ap/e2ap.h"
1415
#include "srsran/e2/e2.h"
1516
#include "srsran/ran/nr_cgi.h"
@@ -152,6 +153,12 @@ void e2_impl::handle_ric_subscription_delete_request(const asn1::e2ap::ric_sub_d
152153
msg, *events, *tx_pdu_notifier, subscription_proc, timers, logger));
153154
}
154155

156+
void e2_impl::handle_e2_connection_update(const asn1::e2ap::e2conn_upd_s& msg)
157+
{
158+
logger.info("Received E2 Connection Update");
159+
async_tasks.schedule(launch_async<e2_connection_update_procedure>(msg, *tx_pdu_notifier, timers, logger));
160+
}
161+
155162
void e2_impl::handle_message(const e2_message& msg)
156163
{
157164
logger.info("Handling E2 PDU of type {}", msg.pdu.type().to_string());
@@ -195,6 +202,9 @@ void e2_impl::handle_initiating_message(const asn1::e2ap::init_msg_s& msg)
195202
case asn1::e2ap::e2ap_elem_procs_o::init_msg_c::types_opts::options::ric_ctrl_request:
196203
handle_ric_control_request(msg.value.ric_ctrl_request());
197204
break;
205+
case asn1::e2ap::e2ap_elem_procs_o::init_msg_c::types_opts::options::e2conn_upd:
206+
handle_e2_connection_update(msg.value.e2conn_upd());
207+
break;
198208
default:
199209
logger.error("Invalid E2AP initiating message type");
200210
break;

lib/e2/common/e2_impl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ class e2_impl final : public e2_interface
8585
/// \param[in] msg The received ric subscription delete request message.
8686
void handle_ric_subscription_delete_request(const asn1::e2ap::ric_sub_delete_request_s& msg);
8787

88+
/// \brief Notify about the reception of a E2 Connection Update message.
89+
/// \param[in] msg The received E2 Connection Update message.
90+
void handle_e2_connection_update(const asn1::e2ap::e2conn_upd_s& msg);
91+
8892
/// \brief handle e2 setup response message from the ric interface.
8993
/// @param[in] msg The received e2 setup response message.
9094
void handle_e2_setup_response(const e2_setup_response_message& msg);
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
*
3+
* Copyright 2021-2025 Software Radio Systems Limited
4+
*
5+
* By using this file, you agree to the terms and conditions set
6+
* forth in the LICENSE file which can be found at the top level of
7+
* the distribution.
8+
*
9+
*/
10+
11+
#include "e2_connection_update_procedure.h"
12+
using namespace srsran;
13+
using namespace asn1::e2ap;
14+
15+
e2_connection_update_procedure::e2_connection_update_procedure(const e2conn_upd_s& request_,
16+
e2_message_notifier& ric_notif_,
17+
timer_factory timers_,
18+
srslog::basic_logger& logger_) :
19+
request(request_), logger(logger_), ric_notif(ric_notif_), timers(timers_)
20+
{
21+
}
22+
23+
void e2_connection_update_procedure::operator()(coro_context<async_task<void>>& ctx)
24+
{
25+
logger.info("E2AP: Received E2 Connection Update");
26+
CORO_BEGIN(ctx);
27+
logger.debug("\"{}\" initialized", name());
28+
29+
// E2 Connection Update not implemented -> always send failure.
30+
send_e2_connection_update_failure();
31+
32+
logger.debug("\"{}\" finalized", name());
33+
CORO_RETURN();
34+
}
35+
36+
void e2_connection_update_procedure::send_e2_connection_update_ack()
37+
{
38+
logger.info("E2AP: Sending E2 Connection Update Ack");
39+
e2_message msg;
40+
msg.pdu.set_successful_outcome().load_info_obj(ASN1_E2AP_ID_E2CONN_UPD);
41+
msg.pdu.successful_outcome().value.e2conn_upd_ack()->transaction_id = request->transaction_id;
42+
ric_notif.on_new_message(msg);
43+
}
44+
45+
void e2_connection_update_procedure::send_e2_connection_update_failure()
46+
{
47+
logger.info("E2AP: Sending E2 Connection Update Failure");
48+
e2_message msg;
49+
msg.pdu.set_unsuccessful_outcome().load_info_obj(ASN1_E2AP_ID_E2CONN_UPD);
50+
msg.pdu.unsuccessful_outcome().value.e2conn_upd_fail()->transaction_id = request->transaction_id;
51+
msg.pdu.unsuccessful_outcome().value.e2conn_upd_fail()->cause_present = true;
52+
msg.pdu.unsuccessful_outcome().value.e2conn_upd_fail()->cause.set_transport() =
53+
cause_transport_e::transport_res_unavailable;
54+
ric_notif.on_new_message(msg);
55+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
*
3+
* Copyright 2021-2025 Software Radio Systems Limited
4+
*
5+
* By using this file, you agree to the terms and conditions set
6+
* forth in the LICENSE file which can be found at the top level of
7+
* the distribution.
8+
*
9+
*/
10+
11+
#pragma once
12+
13+
#include "srsran/asn1/e2ap/e2ap.h"
14+
#include "srsran/e2/e2.h"
15+
#include "srsran/e2/e2_event_manager.h"
16+
#include "srsran/support/async/async_task.h"
17+
#include "srsran/support/timers.h"
18+
19+
namespace srsran {
20+
21+
class e2_connection_update_procedure
22+
{
23+
public:
24+
e2_connection_update_procedure(const asn1::e2ap::e2conn_upd_s& request_,
25+
e2_message_notifier& ric_notif_,
26+
timer_factory timers_,
27+
srslog::basic_logger& logger_);
28+
29+
void operator()(coro_context<async_task<void>>& ctx);
30+
31+
static const char* name() { return "E2 Connection Update Procedure"; }
32+
33+
private:
34+
// results senders
35+
void send_e2_connection_update_ack();
36+
void send_e2_connection_update_failure();
37+
38+
const asn1::e2ap::e2conn_upd_s request;
39+
srslog::basic_logger& logger;
40+
e2_message_notifier& ric_notif;
41+
timer_factory timers;
42+
};
43+
44+
} // namespace srsran

tests/unittests/e2/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,8 @@ add_executable(e2sm_kpm_test e2sm_kpm_test.cpp)
5353
target_link_libraries(e2sm_kpm_test srslog srsran_network srsran_e2 e2ap_asn1 srsran_pcap srsran_gateway srsran_support gtest gtest_main)
5454
target_include_directories(e2sm_kpm_test PRIVATE ${CMAKE_SOURCE_DIR})
5555
gtest_discover_tests(e2sm_kpm_test)
56+
57+
add_executable(e2_conn_upd_procedure_test e2_conn_upd_procedure_test.cpp)
58+
target_link_libraries(e2_conn_upd_procedure_test srslog srsran_network srsran_e2 e2ap_asn1 srsran_pcap srsran_gateway srsran_support gtest gtest_main)
59+
target_include_directories(e2_conn_upd_procedure_test PRIVATE ${CMAKE_SOURCE_DIR})
60+
gtest_discover_tests(e2_conn_upd_procedure_test)

tests/unittests/e2/common/e2_test_helpers.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,16 @@ inline e2_message generate_e2_setup_response(unsigned transaction_id)
583583
setup->ran_functions_accepted.push_back(ran_func_item);
584584
setup->global_ric_id.plmn_id.from_number(131014);
585585
setup->global_ric_id.ric_id.from_number(699598);
586+
// fill the required part with dummy data
587+
setup->e2node_component_cfg_addition_ack.resize(1);
588+
asn1::e2ap::e2node_component_cfg_addition_ack_item_s& e2node_component_cfg_addition_ack_item =
589+
setup->e2node_component_cfg_addition_ack[0].value().e2node_component_cfg_addition_ack_item();
590+
e2node_component_cfg_addition_ack_item.e2node_component_interface_type =
591+
asn1::e2ap::e2node_component_interface_type_e::e2node_component_interface_type_opts::e1;
592+
e2node_component_cfg_addition_ack_item.e2node_component_id.set_e2node_component_interface_type_e1().gnb_cu_up_id =
593+
123;
594+
e2node_component_cfg_addition_ack_item.e2node_component_cfg_ack.upd_outcome =
595+
asn1::e2ap::e2node_component_cfg_ack_s::upd_outcome_opts::success;
586596
return e2_setup_response;
587597
}
588598

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
*
3+
* Copyright 2021-2025 Software Radio Systems Limited
4+
*
5+
* By using this file, you agree to the terms and conditions set
6+
* forth in the LICENSE file which can be found at the top level of
7+
* the distribution.
8+
*
9+
*/
10+
11+
#include "lib/e2/common/e2ap_asn1_packer.h"
12+
#include "lib/e2/e2sm/e2sm_kpm/e2sm_kpm_cu_meas_provider_impl.h"
13+
#include "lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h"
14+
#include "tests/unittests/e2/common/e2_test_helpers.h"
15+
#include "srsran/support/executors/task_worker.h"
16+
#include "srsran/support/srsran_test.h"
17+
#include <gtest/gtest.h>
18+
19+
using namespace srsran;
20+
21+
// Helper global variables to pass pcap_writer to all tests.
22+
bool g_enable_pcap = false;
23+
dlt_pcap* g_pcap = nullptr;
24+
25+
class e2_agent_test_with_pcap : public e2_test_base_with_pcap
26+
{
27+
protected:
28+
dlt_pcap* external_pcap_writer;
29+
30+
void SetUp() override
31+
{
32+
external_pcap_writer = GetParam();
33+
34+
srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::debug);
35+
srslog::init();
36+
37+
cfg = config_helpers::make_default_e2ap_config();
38+
cfg.e2sm_kpm_enabled = true;
39+
40+
gw = std::make_unique<dummy_network_gateway_data_handler>();
41+
pcap = std::make_unique<dummy_e2ap_pcap>();
42+
if (external_pcap_writer) {
43+
packer = std::make_unique<srsran::e2ap_asn1_packer>(*gw, *e2, *external_pcap_writer);
44+
} else {
45+
packer = std::make_unique<srsran::e2ap_asn1_packer>(*gw, *e2, *pcap);
46+
}
47+
e2_client = std::make_unique<dummy_e2_connection_client>();
48+
du_metrics = std::make_unique<dummy_e2_du_metrics>();
49+
f1ap_ue_id_mapper = std::make_unique<dummy_f1ap_ue_id_translator>();
50+
factory = timer_factory{timers, task_worker};
51+
du_rc_param_configurator = std::make_unique<dummy_du_configurator>();
52+
e2agent = create_e2_du_agent(cfg,
53+
*e2_client,
54+
du_metrics.get(),
55+
f1ap_ue_id_mapper.get(),
56+
du_rc_param_configurator.get(),
57+
factory,
58+
task_worker);
59+
}
60+
61+
void TearDown() override
62+
{
63+
// flush logger after each test
64+
srslog::flush();
65+
pcap->close();
66+
}
67+
};
68+
69+
TEST_P(e2_agent_test_with_pcap, e2_connection_update_failure)
70+
{
71+
// We need this test to generate E2 Setup Request, so Wireshark can decode the following RIC indication messages.
72+
test_logger.info("Launch e2 setup request procedure with task worker...");
73+
e2agent->start();
74+
75+
if (g_enable_pcap) {
76+
// Save E2 Setup Request
77+
packer->handle_message(e2_client->last_tx_e2_pdu);
78+
}
79+
80+
// Need to send setup response, so the transaction can be completed.
81+
unsigned transaction_id = get_transaction_id(e2_client->last_tx_e2_pdu.pdu).value();
82+
e2_message e2_setup_response = generate_e2_setup_response(transaction_id);
83+
e2_setup_response.pdu.successful_outcome()
84+
.value.e2setup_resp()
85+
->ran_functions_accepted[0]
86+
->ran_function_id_item()
87+
.ran_function_id = e2sm_kpm_asn1_packer::ran_func_id;
88+
test_logger.info("Injecting E2SetupResponse");
89+
90+
if (g_enable_pcap) {
91+
// Save E2 Setup Request (send to pcap)
92+
packer->handle_message(e2_setup_response);
93+
}
94+
e2agent->get_e2_interface().handle_message(e2_setup_response);
95+
96+
// Inject packed E2 Connection Update.
97+
uint8_t e2_conn_upd[] = {0x00, 0x0b, 0x00, 0x1b, 0x00, 0x00, 0x02, 0x00, 0x31, 0x00, 0x02,
98+
0x00, 0x03, 0x00, 0x2c, 0x00, 0x0e, 0x00, 0x00, 0x2b, 0x40, 0x09,
99+
0x21, 0xf0, 0x0a, 0x2a, 0x00, 0x61, 0x8e, 0x45, 0x40};
100+
byte_buffer e2_conn_upd_buf = byte_buffer::create(e2_conn_upd, e2_conn_upd + sizeof(e2_conn_upd)).value();
101+
102+
asn1::cbit_ref bref(e2_conn_upd_buf);
103+
e2_message e2_conn_upd_msg = {};
104+
if (e2_conn_upd_msg.pdu.unpack(bref) != asn1::SRSASN_SUCCESS) {
105+
return;
106+
}
107+
if (g_enable_pcap) {
108+
// Save E2 Setup Request (send to pcap)
109+
packer->handle_message(e2_conn_upd_msg);
110+
}
111+
e2agent->get_e2_interface().handle_message(e2_conn_upd_msg);
112+
113+
e2_message& msg = e2_client->last_tx_e2_pdu;
114+
if (g_enable_pcap) {
115+
// Save E2 Setup Request (send to pcap)
116+
packer->handle_message(msg);
117+
}
118+
119+
// Currently, E2 Connection Update is not implemented, so always return failure.
120+
ASSERT_EQ(msg.pdu.type().value, asn1::e2ap::e2ap_pdu_c::types_opts::unsuccessful_outcome);
121+
ASSERT_EQ(msg.pdu.unsuccessful_outcome().value.type().value,
122+
asn1::e2ap::e2ap_elem_procs_o::unsuccessful_outcome_c::types_opts::e2conn_upd_fail);
123+
e2agent->stop();
124+
}
125+
126+
INSTANTIATE_TEST_SUITE_P(e2_agent_test_with_pcap, e2_agent_test_with_pcap, testing::Values(g_pcap));
127+
128+
int main(int argc, char** argv)
129+
{
130+
// Check for '--enable_pcap' cmd line argument, do not use getopt as it interferes with gtest.
131+
for (int i = 1; i < argc; ++i) {
132+
std::string arg = argv[i];
133+
if (arg == "--enable_pcap") {
134+
g_enable_pcap = true;
135+
}
136+
}
137+
138+
srslog::init();
139+
140+
std::unique_ptr<task_worker_executor> pcap_exec;
141+
std::unique_ptr<task_worker> pcap_worker;
142+
std::unique_ptr<dlt_pcap> common_pcap_writer;
143+
144+
if (g_enable_pcap) {
145+
pcap_worker = std::make_unique<task_worker>("pcap_worker", 128);
146+
pcap_exec = std::make_unique<task_worker_executor>(*pcap_worker);
147+
common_pcap_writer = create_e2ap_pcap("/tmp/e2_conn_upd_test.pcap", *pcap_exec);
148+
g_pcap = common_pcap_writer.get();
149+
}
150+
151+
::testing::InitGoogleTest(&argc, argv);
152+
int ret = RUN_ALL_TESTS();
153+
return ret;
154+
}

0 commit comments

Comments
 (0)