-
Notifications
You must be signed in to change notification settings - Fork 50
Implementation of the E3 Agent for dApps and E3AP (no service models) #204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
447ff67
build: add opt-in E3_AGENT build option for the O-RAN E3 agent
Thecave3 0a885dc
e3ap: add E3 agent configuration and CMake target
Thecave3 29c20ac
e3ap: add E3 agent lifecycle and nr-softmodem init hook
Thecave3 602d729
e3ap: add README with dApp overview, prerequisites, and startup guide
Thecave3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| # SPDX-License-Identifier: LicenseRef-CSSL-1.0 | ||
|
|
||
| find_package(PkgConfig REQUIRED) | ||
|
arora-sagar marked this conversation as resolved.
|
||
| pkg_check_modules(CLIBE3 REQUIRED libe3) | ||
|
teodora-vladic marked this conversation as resolved.
|
||
|
|
||
| if(NOT CLIBE3_FOUND) | ||
| message(FATAL_ERROR "libe3 not found and required for E3 Agent") | ||
| endif() | ||
|
|
||
| message(STATUS "Using for E3AP libe3 version: ${CLIBE3_VERSION}") | ||
|
|
||
| include_directories(${CLIBE3_INCLUDE_DIRS}) | ||
|
|
||
| # Set default encoding format if not specified | ||
| if(NOT DEFINED E3_ENCODING_FORMAT) | ||
| set(E3_ENCODING_FORMAT "ASN1" CACHE STRING "E3AP encoding format (ASN1 or JSON)") | ||
| endif() | ||
|
|
||
| # Validate encoding format | ||
| if(NOT E3_ENCODING_FORMAT MATCHES "^(ASN1|JSON)$") | ||
| message(FATAL_ERROR "Invalid E3_ENCODING_FORMAT: ${E3_ENCODING_FORMAT}. Must be ASN1 or JSON") | ||
| endif() | ||
|
|
||
| message(STATUS "E3AP encoding format: ${E3_ENCODING_FORMAT}") | ||
|
|
||
| add_library(e3ap e3_agent.c config/e3_config.c) | ||
|
rorsc marked this conversation as resolved.
|
||
|
|
||
| # target_link_libraries(e3ap PUBLIC OCP_ITTI) # TODO | ||
|
|
||
| # Set encoding format compile definitions - both string value and format flags | ||
| target_compile_definitions(e3ap PRIVATE E3_ENCODING_FORMAT="${E3_ENCODING_FORMAT}") | ||
|
|
||
| if(E3_ENCODING_FORMAT STREQUAL "ASN1") | ||
| target_compile_definitions(e3ap PRIVATE E3_ASN1_FORMAT) | ||
| target_link_libraries(e3ap PUBLIC ${CLIBE3_LIBRARIES}) | ||
| elseif(E3_ENCODING_FORMAT STREQUAL "JSON") | ||
| target_compile_definitions(e3ap PRIVATE E3_JSON_FORMAT) | ||
| pkg_check_modules(JSON_C REQUIRED json-c) | ||
| if(NOT JSON_C_FOUND) | ||
| message(FATAL_ERROR "JSON-C not found and required for JSON encoding, install it with apt-get install libjson-c-dev") | ||
| endif() | ||
| target_link_libraries(e3ap PUBLIC ${CLIBE3_LIBRARIES} ${JSON_C_LIBRARIES}) | ||
| target_include_directories(e3ap PUBLIC ${JSON_C_INCLUDE_DIRS}) | ||
| endif() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| <!-- SPDX-License-Identifier: CC-BY-4.0 --> | ||
|
|
||
| # Overview | ||
|
|
||
| This document describes the E3 Agent for dApps integrated in OAI gNB, and explains how to | ||
| build, configure, and connect a dApp. | ||
|
|
||
| [[_TOC_]] | ||
|
|
||
| dApps can be real-time microservices co-located with the RAN node (DU or CU). Unlike xApps, | ||
| which run on a nearRT-RIC and operate at 10 ms–1 s timescales, dApps execute directly on the | ||
| RAN node and interact with user-plane data that is unavailable to RICs due to timing or | ||
| privacy constraints. This enables sub-millisecond control loops for use cases such as spectrum | ||
| sharing, positioning, and scheduling optimization. | ||
|
|
||
| The E3 interface connects the gNB to co-located dApps. The `libe3` library implements both | ||
| sides of this interface — the RAN agent (this module) and the dApp client — using a unified | ||
| C++/Python API that hides transport, encoding, and protocol complexity. | ||
|
|
||
| For a complete description of the dApp architecture and the E3 interface, refer to: | ||
|
|
||
| - [Paper: dApp architecture and E3 interface (Computer Networks, 2025)](https://doi.org/10.1016/j.comnet.2025.111342) | ||
| - [Tutorial: deploying dApps with OAI](https://openrangym.com/tutorials/dapps-oai) | ||
| - [dApp Python library](https://pypi.org/project/dapps/) | ||
|
|
||
| ## 1. Prerequisites — libe3 | ||
|
|
||
| The E3 Agent requires the external `libe3` library, discovered at build time via | ||
| `pkg_check_modules(CLIBE3 REQUIRED libe3)`. It is not vendored in OAI. | ||
|
|
||
| ```bash | ||
| git clone https://github.com/wineslab/libe3 && cd libe3 | ||
| ./build_libe3 -I # install system prerequisites if not already present | ||
| ./build_libe3 --install | ||
| ``` | ||
|
|
||
| ## 2. Build OAI with the E3 Agent | ||
|
|
||
| The E3 Agent is **opt-in** and gated behind the `E3_AGENT` CMake option (`OFF` by default). | ||
| The default OAI build is entirely unaffected when `E3_AGENT` is not set. | ||
|
|
||
| ```bash | ||
| cd cmake_targets/ | ||
| ./build_oai -w SIMU --ninja --gNB --nrUE --build-e3 | ||
| ``` | ||
|
|
||
| To build without the E3 Agent, omit `--build-e3`. To clean and rebuild, add the `-c` flag. | ||
|
|
||
| ## 3. Configuration | ||
|
|
||
| The agent reads an optional `E3Configuration` block from the gNB configuration file. | ||
| If the block is absent, the agent falls back to built-in defaults (`posix`/`ipc`). | ||
|
|
||
| ``` | ||
| E3Configuration : { | ||
| link = "zmq"; # posix | zmq | ||
| transport = "ipc"; # tcp | sctp | ipc | ||
| }; | ||
| ``` | ||
|
|
||
| The same parameters can be set on the command line without editing the config file: | ||
|
|
||
| ```bash | ||
| sudo ./nr-softmodem -O <gnb.conf> ... --E3Configuration.link zmq --E3Configuration.transport ipc | ||
| ``` | ||
|
|
||
| Valid link/transport combinations: | ||
|
|
||
| | link | transport | | ||
| |-------|-----------| | ||
| | zmq | ipc | | ||
| | zmq | tcp | | ||
| | posix | ipc | | ||
| | posix | tcp | | ||
| | posix | sctp | | ||
|
|
||
| ## 4. dApp development | ||
|
|
||
| dApps are written in Python using the `dapps` library: | ||
|
|
||
| ```bash | ||
| pip install "dapps[all]" | ||
| ``` | ||
|
|
||
| A dApp subclasses the `DApp` base class and implements service-model-specific encode/decode | ||
| and a control loop. The library handles the E3 connection transparently: setup handshake, | ||
| subscription, indication receive, and control send. | ||
|
|
||
| At the current status, no service models have been included so far. | ||
|
|
||
| For a full end-to-end example including service model usage, follow the | ||
| [tutorial on the OpenRAN Gym website](https://openrangym.com/tutorials/dapps-oai). | ||
|
|
||
| ## 5. Start the process | ||
|
|
||
| ### 5.1 Start the gNB with E3 agent enabled | ||
|
|
||
| The example below uses RFsim for local testing. A 5G Core Network must already be running; | ||
| see [`doc/NR_SA_Tutorial_OAI_CN5G.md`](../../doc/NR_SA_Tutorial_OAI_CN5G.md). | ||
|
|
||
| ```bash | ||
| cd cmake_targets/ran_build/build | ||
| sudo ./nr-softmodem \ | ||
| -O <path>/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci0.rfsim.conf \ | ||
| --rfsim \ | ||
| --E3Configuration.link zmq --E3Configuration.transport ipc | ||
| ``` | ||
|
|
||
| If the agent initializes correctly, the log will show `Init E3 Agent` and the setup socket | ||
| will appear at `/tmp/dapps/setup`. | ||
|
|
||
| An `E3AP` log component is available for debugging: pass `--log_config.e3ap_log_level debug` | ||
| to increase verbosity. | ||
|
|
||
| ### 5.2 Connect a dApp | ||
|
|
||
| Follow the [deployment tutorial](https://openrangym.com/tutorials/dapps-oai) for a complete | ||
| end-to-end example. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| /* | ||
| * SPDX-License-Identifier: LicenseRef-CSSL-1.0 | ||
| */ | ||
|
|
||
| #include "e3_config.h" | ||
|
arora-sagar marked this conversation as resolved.
teodora-vladic marked this conversation as resolved.
|
||
| #include "common/utils/LOG/log.h" | ||
| #include "common/config/config_paramdesc.h" | ||
| #include "common/config/config_userapi.h" | ||
|
|
||
| #define E3CONFIG_SECTION "E3Configuration" | ||
|
|
||
| #define simOpt PARAMFLAG_NOFREE | PARAMFLAG_CMDLINE_NOPREFIXENABLED | ||
|
|
||
| /* String-to-integer mappings for link, transport, and encoding. | ||
| * Values must match the libe3 e3_config_t enum ordering. */ | ||
| // clang-format off | ||
| #define E3_LINK_OKSTRINGS {"zmq", "posix"} | ||
| #define E3_LINK_VALUES {E3_LINK_ZMQ, E3_LINK_POSIX} | ||
| #define E3_TRANSPORT_OKSTRINGS {"sctp", "tcp", "ipc"} | ||
| #define E3_TRANSPORT_VALUES {E3_TRANSPORT_SCTP, E3_TRANSPORT_TCP, E3_TRANSPORT_IPC} | ||
| #define E3_ENCODING_OKSTRINGS {"asn1", "json"} | ||
| #define E3_ENCODING_VALUES {E3_ENCODING_ASN1, E3_ENCODING_JSON} | ||
|
|
||
| #define E3_LINK_IDX 0 | ||
| #define E3_TRANSPORT_IDX 1 | ||
| #define E3_ENCODING_IDX 2 | ||
| // clang-format on | ||
|
|
||
| void e3_readconfig(e3_cmdline_config_t *config) | ||
| { | ||
| /* Temporary string storage for the string→int parameters. */ | ||
| char *s_link = NULL, *s_transport = NULL, *s_encoding = NULL; | ||
|
|
||
| // clang-format off | ||
| paramdef_t e3_params[] = { | ||
| /* optname helpstr paramflags value defval type numelt */ | ||
| {"link", "Link layer for E3 (zmq|posix)", simOpt, .strptr = &s_link, .defstrval = "posix", TYPE_STRING, 0}, | ||
| {"transport", "Transport layer for E3 (sctp|tcp|ipc)", simOpt, .strptr = &s_transport, .defstrval = "ipc", TYPE_STRING, 0}, | ||
| {"encoding", "Encoding format for E3 (asn1|json)", simOpt, .strptr = &s_encoding, .defstrval = "asn1", TYPE_STRING, 0}, | ||
| {"setup_port", "E3 setup port (0=libe3 default)", simOpt, .u16ptr = &config->setup_port, .defuintval = 0, TYPE_UINT16, 0}, | ||
| {"subscriber_port", "E3 subscriber port (0=libe3 default)", simOpt, .u16ptr = &config->subscriber_port, .defuintval = 0, TYPE_UINT16, 0}, | ||
| {"publisher_port", "E3 publisher port (0=libe3 default)", simOpt, .u16ptr = &config->publisher_port, .defuintval = 0, TYPE_UINT16, 0}, | ||
| }; | ||
|
|
||
| checkedparam_t e3_checks[] = { | ||
| {.s3a = {config_checkstr_assign_integer, E3_LINK_OKSTRINGS, E3_LINK_VALUES, 2}}, | ||
| {.s3a = {config_checkstr_assign_integer, E3_TRANSPORT_OKSTRINGS, E3_TRANSPORT_VALUES, 3}}, | ||
| {.s3a = {config_checkstr_assign_integer, E3_ENCODING_OKSTRINGS, E3_ENCODING_VALUES, 2}}, | ||
| {.s5 = {NULL}}, | ||
| {.s5 = {NULL}}, | ||
| {.s5 = {NULL}}, | ||
| }; | ||
| // clang-format on | ||
|
|
||
| config_set_checkfunctions(e3_params, e3_checks, sizeofArray(e3_params)); | ||
|
|
||
| int ret = config_get(config_get_if(), e3_params, sizeofArray(e3_params), E3CONFIG_SECTION); | ||
| AssertFatal(ret >= 0, "E3Configuration: config_get failed\n"); | ||
|
|
||
| config->link_layer = config_get_processedint(config_get_if(), &e3_params[E3_LINK_IDX]); | ||
| config->transport_layer = config_get_processedint(config_get_if(), &e3_params[E3_TRANSPORT_IDX]); | ||
| config->encoding = config_get_processedint(config_get_if(), &e3_params[E3_ENCODING_IDX]); | ||
| /* setup_port, subscriber_port, publisher_port written directly by config_get via u16ptr */ | ||
|
|
||
| LOG_I(E3AP, | ||
| "E3 configuration: link=%d transport=%d encoding=%d setup_port=%u subscriber_port=%u publisher_port=%u\n", | ||
| config->link_layer, | ||
| config->transport_layer, | ||
| config->encoding, | ||
| config->setup_port, | ||
| config->subscriber_port, | ||
| config->publisher_port); | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.