libe3 0.2.5
C++ library for E3AP RAN vendor integration
Loading...
Searching...
No Matches
sm_registry.cpp
Go to the documentation of this file.
1/**
2 * @file sm_registry.cpp
3 * @brief Service Model Registry implementation
4 *
5 * SPDX-FileCopyrightText: Copyright (c) 2026 Northeastern University
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
10#include "libe3/logger.hpp"
11#include <algorithm>
12
13namespace libe3 {
14
15namespace {
16constexpr const char* LOG_TAG = "SmReg";
17}
18
19SmRegistry& SmRegistry::instance() {
20 static SmRegistry registry;
21 return registry;
22}
23
24ErrorCode SmRegistry::register_sm(std::unique_ptr<ServiceModel> sm) {
25 if (!sm) {
26 return ErrorCode::INVALID_PARAM;
27 }
28
29 // E3-RanFunctionDefinition.ranFunctionData is a mandatory
30 // OCTET STRING (SIZE (1..32768)): an SM that cannot advertise at least its
31 // own name has nothing to advertise, and the SetupResponse carrying it
32 // would fail to encode for every other registered RAN function too.
33 // Reject here rather than at encode time, where the only options left are
34 // padding the value or dropping the whole response.
35 const size_t rfd_len = sm->ran_function_data().size();
36 if (rfd_len == 0 || rfd_len > MAX_PROTOCOL_DATA_SIZE) {
37 E3_LOG_ERROR(LOG_TAG) << "SM '" << sm->name() << "' advertises "
38 << rfd_len << " bytes of ran_function_data; E3AP"
39 << " requires 1.." << MAX_PROTOCOL_DATA_SIZE;
40 return ErrorCode::INVALID_PARAM;
41 }
42
43 std::lock_guard lock(mutex_);
44
45 uint32_t ran_func = sm->ran_function_id();
46
47 // Check for conflict
48 if (sms_.count(ran_func) > 0) {
49 E3_LOG_ERROR(LOG_TAG) << "SM already registered for RAN function " << ran_func;
50 return ErrorCode::SM_ALREADY_REGISTERED;
51 }
52
53 // Initialize the SM
54 ErrorCode init_result = sm->init();
55 if (init_result != ErrorCode::SUCCESS) {
56 E3_LOG_ERROR(LOG_TAG) << "Failed to initialize SM: " << sm->name();
57 return init_result;
58 }
59
60 E3_LOG_INFO(LOG_TAG) << "Registered SM '" << sm->name()
61 << "' for RAN function " << ran_func;
62
63 sms_[ran_func] = std::move(sm);
64
65 return ErrorCode::SUCCESS;
66}
67
68ErrorCode SmRegistry::register_sm_factory(uint32_t ran_function_id, SmFactory factory) {
69 if (!factory) {
70 return ErrorCode::INVALID_PARAM;
71 }
72
73 std::lock_guard lock(mutex_);
74
75 if (sms_.count(ran_function_id) > 0 || factories_.count(ran_function_id) > 0) {
76 E3_LOG_ERROR(LOG_TAG) << "SM or factory already registered for RAN function "
77 << ran_function_id;
78 return ErrorCode::SM_ALREADY_REGISTERED;
79 }
80
81 factories_[ran_function_id] = std::move(factory);
82 E3_LOG_INFO(LOG_TAG) << "Registered SM factory for RAN function " << ran_function_id;
83
84 return ErrorCode::SUCCESS;
85}
86
87ErrorCode SmRegistry::unregister_sm(uint32_t ran_function_id) {
88 std::lock_guard lock(mutex_);
89
90 auto it = sms_.find(ran_function_id);
91 if (it != sms_.end()) {
92 if (it->second->is_running()) {
93 it->second->stop();
94 }
95 it->second->destroy();
96 sms_.erase(it);
97 E3_LOG_INFO(LOG_TAG) << "Unregistered SM for RAN function " << ran_function_id;
98 return ErrorCode::SUCCESS;
99 }
100
101 auto factory_it = factories_.find(ran_function_id);
102 if (factory_it != factories_.end()) {
103 factories_.erase(factory_it);
104 return ErrorCode::SUCCESS;
105 }
106
107 return ErrorCode::SM_NOT_FOUND;
108}
109
111 std::lock_guard lock(mutex_);
112
113 // Direct lookup
114 auto it = sms_.find(ran_function_id);
115 if (it != sms_.end()) {
116 return it->second.get();
117 }
118
119 // Check if there's a factory for this RAN function
120 auto factory_it = factories_.find(ran_function_id);
121 if (factory_it != factories_.end()) {
122 // Create SM from factory
123 auto sm = factory_it->second();
124 if (sm) {
125 ErrorCode init_result = sm->init();
126 if (init_result == ErrorCode::SUCCESS) {
127 ServiceModel* ptr = sm.get();
128 sms_[ran_function_id] = std::move(sm);
129 factories_.erase(factory_it);
130 return ptr;
131 }
132 }
133 }
134
135 return nullptr;
136}
137
138std::vector<uint32_t> SmRegistry::get_available_ran_functions() const {
139 std::lock_guard lock(mutex_);
140
141 std::vector<uint32_t> result;
142 result.reserve(sms_.size() + factories_.size());
143
144 for (const auto& [id, sm] : sms_) {
145 result.push_back(id);
146 }
147
148 for (const auto& [id, factory] : factories_) {
149 result.push_back(id);
150 }
151
152 std::sort(result.begin(), result.end());
153 return result;
154}
155
156ErrorCode SmRegistry::start_sm(uint32_t ran_function_id) {
157 std::lock_guard lock(mutex_);
158
159 auto it = sms_.find(ran_function_id);
160 if (it == sms_.end()) {
161 E3_LOG_ERROR(LOG_TAG) << "SM not found for RAN function " << ran_function_id;
162 E3_LOG_ERROR(LOG_TAG) << "SM not found for RAN function " << ran_function_id;
163 return ErrorCode::SM_NOT_FOUND;
164 }
165
166 auto& sm = it->second;
167
168 if (sm->is_running()) {
169 E3_LOG_DEBUG(LOG_TAG) << "SM already running for RAN function " << ran_function_id;
170 return ErrorCode::SUCCESS;
171 }
172
173 ErrorCode result = sm->start();
174 if (result != ErrorCode::SUCCESS) {
175 E3_LOG_ERROR(LOG_TAG) << "Failed to start SM for RAN function " << ran_function_id;
176 return result;
177 }
178
179 E3_LOG_INFO(LOG_TAG) << "Started SM for RAN function " << ran_function_id;
180 return ErrorCode::SUCCESS;
181}
182
183ErrorCode SmRegistry::stop_sm(uint32_t ran_function_id) {
184 std::lock_guard lock(mutex_);
185
186 auto it = sms_.find(ran_function_id);
187 if (it == sms_.end()) {
188 return ErrorCode::SM_NOT_FOUND;
189 }
190
191 auto& sm = it->second;
192
193 if (!sm->is_running()) {
194 return ErrorCode::SUCCESS;
195 }
196
197 sm->stop();
198 E3_LOG_INFO(LOG_TAG) << "Stopped SM for RAN function " << ran_function_id;
199 return ErrorCode::SUCCESS;
200}
201
202bool SmRegistry::is_sm_running(uint32_t ran_function_id) const {
203 std::lock_guard lock(mutex_);
204
205 auto it = sms_.find(ran_function_id);
206 if (it != sms_.end()) {
207 return it->second->is_running();
208 }
209
210 return false;
211}
212
214 std::lock_guard lock(mutex_);
215
216 for (auto& [id, sm] : sms_) {
217 if (sm->is_running()) {
218 sm->stop();
219 }
220 sm->destroy();
221 }
222
223 sms_.clear();
224 factories_.clear();
225 E3_LOG_INFO(LOG_TAG) << "SM registry cleared";
226}
227
228} // namespace libe3
Abstract Service Model interface.
ErrorCode start_sm(uint32_t ran_function_id)
Start SM for a RAN function.
static SmRegistry & instance()
Get the singleton instance.
ServiceModel * get_by_ran_function(uint32_t ran_function_id)
Get SM by RAN function ID.
bool is_sm_running(uint32_t ran_function_id) const
Check if SM is running.
ErrorCode unregister_sm(uint32_t ran_function_id)
Unregister a Service Model by RAN function ID.
ErrorCode register_sm(std::unique_ptr< ServiceModel > sm)
Register a Service Model.
ErrorCode stop_sm(uint32_t ran_function_id)
Stop SM for a RAN function.
ErrorCode register_sm_factory(uint32_t ran_function_id, SmFactory factory)
Register a Service Model factory.
std::vector< uint32_t > get_available_ran_functions() const
Get all available RAN function IDs.
void clear()
Clear all registered SMs.
Logging facility for libe3.
#define E3_LOG_DEBUG(component)
Definition logger.hpp:228
#define E3_LOG_INFO(component)
Definition logger.hpp:227
#define E3_LOG_ERROR(component)
Definition logger.hpp:225
ErrorCode
Error codes returned by libe3 operations Use shared error-code list (see libe3/error_codes....
Definition types.hpp:141
constexpr size_t MAX_PROTOCOL_DATA_SIZE
Definition types.hpp:160
std::function< std::unique_ptr< ServiceModel >()> SmFactory
Factory function type for creating SM instances.
Service Model Interface - Extension point for RAN vendors.