libe3 0.2.5
C++ library for E3AP RAN vendor integration
Loading...
Searching...
No Matches
sm_interface.hpp
Go to the documentation of this file.
1/**
2 * @file sm_interface.hpp
3 * @brief Service Model Interface - Extension point for RAN vendors
4 *
5 * Defines the interface that Service Models must implement to integrate
6 * with the E3 agent. E3SM logic is treated as opaque to E3AP - this
7 * interface provides extension points without embedding SM-specific logic.
8 *
9 * SPDX-FileCopyrightText: Copyright (c) 2026 Northeastern University
10 * SPDX-License-Identifier: Apache-2.0
11 */
12
13#ifndef LIBE3_SM_INTERFACE_HPP
14#define LIBE3_SM_INTERFACE_HPP
15
16#include "types.hpp"
17#include <memory>
18#include <functional>
19#include <vector>
20#include <string>
21#include <atomic>
22#include <mutex>
23
24namespace libe3 {
25
26// Forward declarations
27class ServiceModel;
28
29/**
30 * @brief Abstract Service Model interface
31 *
32 * This is the extension point for RAN vendors to implement their
33 * Service Models. The E3 agent treats E3SM as opaque - all SM-specific
34 * encoding/decoding happens in the implementations of this interface.
35 *
36 * RAN vendors should:
37 * 1. Derive from this class for each supported SM
38 * 2. Implement the required virtual methods
39 * 3. Register their SMs with the E3Agent
40 */
42public:
43 virtual ~ServiceModel() = default;
44
45 /**
46 * @brief Get SM name
47 */
48 virtual std::string name() const = 0;
49
50 /**
51 * @brief Get SM version
52 */
53 virtual uint32_t version() const = 0;
54
55 /**
56 * @brief Get RAN function ID for this SM
57 */
58 virtual uint32_t ran_function_id() const = 0;
59
60 /**
61 * @brief Get telemetry IDs supported by this SM
62 */
63 virtual std::vector<uint32_t> telemetry_ids() const = 0;
64
65 /**
66 * @brief Get control IDs supported by this SM
67 */
68 virtual std::vector<uint32_t> control_ids() const = 0;
69
70 /**
71 * @brief RAN-function-specific opaque data (required, 1..32768 bytes)
72 *
73 * Returns the byte vector advertised for this RAN function in the
74 * SetupResponse (ranFunctionList->ranFunctionData). E3AP declares the field
75 * mandatory and non-empty -- `OCTET STRING (SIZE (1..32768))` -- so every SM
76 * must override this: even the most minimal SM carries at least its own
77 * name. An SM with nothing to advertise is not advertisable at all, since
78 * ranFunctionList itself is optional but its entries are not.
79 *
80 * Registration fails with ErrorCode::INVALID_PARAM if the returned vector is
81 * empty or longer than MAX_PROTOCOL_DATA_SIZE. The base implementation
82 * returns an empty vector so that failure is a loud diagnostic rather than a
83 * compile error in every existing SM; it is not a usable default.
84 */
85 virtual std::vector<uint8_t> ran_function_data() const { return {}; }
86
87 /**
88 * @brief Initialize the SM
89 *
90 * Called when the SM is first registered.
91 * @return ErrorCode::SUCCESS on success
92 */
93 virtual ErrorCode init() = 0;
94
95 /**
96 * @brief Destroy the SM and release resources
97 *
98 * Called when the SM is being unregistered.
99 */
100 virtual void destroy() = 0;
101
102 /**
103 * @brief Start the SM processing
104 *
105 * Called when the first dApp subscribes to this SM's RAN function.
106 * @return ErrorCode::SUCCESS on success
107 */
108 virtual ErrorCode start() = 0;
109
110 /**
111 * @brief Stop the SM processing
112 *
113 * Called when the last dApp unsubscribes from this SM's RAN function.
114 */
115 virtual void stop() = 0;
116
117 /**
118 * @brief Check if SM is currently running
119 */
120 virtual bool is_running() const = 0;
121
122 /**
123 * @brief Process a control action from a dApp
124 *
125 * Called by the E3 interface when a DAppControlAction is received for this
126 * service model. Implementations can emit outbound PDUs (e.g. MessageAck,
127 * IndicationMessage) via emit_outbound().
128 */
130 uint32_t request_message_id,
131 const DAppControlAction& action
132 ) = 0;
133
134protected:
135 ServiceModel() = default;
136
137 /**
138 * @brief Build a MessageAck PDU for a control/request message.
139 *
140 * This helper only builds the PDU. Implementations can decide whether to
141 * emit it with emit_outbound() or suppress it when protocol semantics allow.
142 */
144 uint32_t request_message_id,
145 ResponseCode response_code
146 ) {
148 MessageAck ack;
149 ack.request_id = request_message_id;
150 ack.response_code = response_code;
151 pdu.choice = ack;
152 return pdu;
153 }
154
155 /**
156 * @brief Build an IndicationMessage PDU.
157 *
158 * This helper only builds the PDU. Implementations can emit it with
159 * emit_outbound() when appropriate.
160 */
162 uint32_t dapp_id,
163 uint32_t ran_function_id,
164 std::vector<uint8_t> protocol_data
165 ) {
168 msg.dapp_identifier = dapp_id;
170 msg.protocol_data = std::move(protocol_data);
171 pdu.choice = std::move(msg);
172 return pdu;
173 }
174
175 /**
176 * @brief Emit an outbound PDU produced by the SM.
177 */
179 if (!outbound_emitter_) {
180 return ErrorCode::NOT_INITIALIZED;
181 }
182 return outbound_emitter_(std::move(pdu));
183 }
184
185 /**
186 * @brief Get currently subscribed dApps for this SM's RAN function.
187 */
188 std::vector<uint32_t> get_subscribers() const {
189 if (!subscribers_provider_) {
190 return {};
191 }
192 return subscribers_provider_();
193 }
194
195 /**
196 * @brief Set the outbound PDU emitter callback (used by E3Interface).
197 */
198 void set_outbound_emitter(std::function<ErrorCode(Pdu&&)> emitter) {
199 outbound_emitter_ = std::move(emitter);
200 }
201
202 /**
203 * @brief Set subscriber provider callback (used by E3Interface).
204 */
205 void set_subscribers_provider(std::function<std::vector<uint32_t>()> provider) {
206 subscribers_provider_ = std::move(provider);
207 }
208
209private:
210 std::function<ErrorCode(Pdu&&)> outbound_emitter_;
211 std::function<std::vector<uint32_t>()> subscribers_provider_;
212
213 friend class E3Interface;
214};
215
216/**
217 * @brief Factory function type for creating SM instances
218 */
219using SmFactory = std::function<std::unique_ptr<ServiceModel>()>;
220
221/**
222 * @brief SM Registry for managing registered Service Models
223 *
224 * This class provides a central registry for Service Models.
225 * It's used by the E3Agent to find and manage SMs.
226 */
227class SmRegistry {
228public:
229 /**
230 * @brief Get the singleton instance
231 */
232 static SmRegistry& instance();
233
234 /**
235 * @brief Register a Service Model
236 *
237 * @param sm Service Model to register
238 * @return ErrorCode::SUCCESS on success
239 * @return ErrorCode::SM_ALREADY_REGISTERED if SM for this RAN function exists
240 */
241 ErrorCode register_sm(std::unique_ptr<ServiceModel> sm);
242
243 /**
244 * @brief Register a Service Model factory
245 *
246 * Use this to defer SM creation until needed.
247 */
248 ErrorCode register_sm_factory(uint32_t ran_function_id, SmFactory factory);
249
250 /**
251 * @brief Unregister a Service Model by RAN function ID
252 */
253 ErrorCode unregister_sm(uint32_t ran_function_id);
254
255 /**
256 * @brief Get SM by RAN function ID
257 *
258 * @param ran_function_id RAN function ID to look up
259 * @return Pointer to SM, nullptr if not found
260 */
261 ServiceModel* get_by_ran_function(uint32_t ran_function_id);
262
263 /**
264 * @brief Get all available RAN function IDs
265 */
266 std::vector<uint32_t> get_available_ran_functions() const;
267
268 /**
269 * @brief Start SM for a RAN function
270 */
271 ErrorCode start_sm(uint32_t ran_function_id);
272
273 /**
274 * @brief Stop SM for a RAN function
275 */
276 ErrorCode stop_sm(uint32_t ran_function_id);
277
278 /**
279 * @brief Check if SM is running
280 */
281 bool is_sm_running(uint32_t ran_function_id) const;
282
283 /**
284 * @brief Clear all registered SMs
285 */
286 void clear();
287
288private:
289 SmRegistry() = default;
290 ~SmRegistry() = default;
291 SmRegistry(const SmRegistry&) = delete;
292 SmRegistry& operator=(const SmRegistry&) = delete;
293
294 mutable std::mutex mutex_;
295 std::unordered_map<uint32_t, std::unique_ptr<ServiceModel>> sms_;
296 std::unordered_map<uint32_t, SmFactory> factories_;
297};
298
299} // namespace libe3
300
301#endif // LIBE3_SM_INTERFACE_HPP
Abstract Service Model interface.
virtual std::string name() const =0
Get SM name.
virtual uint32_t ran_function_id() const =0
Get RAN function ID for this SM.
virtual std::vector< uint32_t > telemetry_ids() const =0
Get telemetry IDs supported by this SM.
static Pdu make_message_ack_pdu(uint32_t request_message_id, ResponseCode response_code)
Build a MessageAck PDU for a control/request message.
std::vector< uint32_t > get_subscribers() const
Get currently subscribed dApps for this SM's RAN function.
virtual uint32_t version() const =0
Get SM version.
static Pdu make_indication_pdu(uint32_t dapp_id, uint32_t ran_function_id, std::vector< uint8_t > protocol_data)
Build an IndicationMessage PDU.
void set_subscribers_provider(std::function< std::vector< uint32_t >()> provider)
Set subscriber provider callback (used by E3Interface).
virtual ~ServiceModel()=default
virtual void destroy()=0
Destroy the SM and release resources.
void set_outbound_emitter(std::function< ErrorCode(Pdu &&)> emitter)
Set the outbound PDU emitter callback (used by E3Interface).
ServiceModel()=default
ErrorCode emit_outbound(Pdu &&pdu)
Emit an outbound PDU produced by the SM.
virtual ErrorCode handle_control_action(uint32_t request_message_id, const DAppControlAction &action)=0
Process a control action from a dApp.
virtual ErrorCode start()=0
Start the SM processing.
friend class E3Interface
virtual void stop()=0
Stop the SM processing.
virtual std::vector< uint8_t > ran_function_data() const
RAN-function-specific opaque data (required, 1..32768 bytes).
virtual std::vector< uint32_t > control_ids() const =0
Get control IDs supported by this SM.
virtual bool is_running() const =0
Check if SM is currently running.
virtual ErrorCode init()=0
Initialize the SM.
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.
ErrorCode
Error codes returned by libe3 operations Use shared error-code list (see libe3/error_codes....
Definition types.hpp:141
ResponseCode
E3AP response codes.
Definition types.hpp:101
std::function< std::unique_ptr< ServiceModel >()> SmFactory
Factory function type for creating SM instances.
E3AP dApp Control Action structure.
Definition types.hpp:272
E3AP Indication Message structure.
Definition types.hpp:263
uint32_t ran_function_identifier
RAN function identifier.
Definition types.hpp:265
std::vector< uint8_t > protocol_data
Definition types.hpp:266
E3AP Message Acknowledgment structure.
Definition types.hpp:285
ResponseCode response_code
Response code (positive/negative).
Definition types.hpp:287
uint32_t request_id
ID of the request being acknowledged.
Definition types.hpp:286
Generic E3AP PDU structure.
Definition types.hpp:345
PduChoice choice
Definition types.hpp:347
E3AP Protocol Types - Vendor-neutral type definitions.