Repository navigation
Conversation
…DAPP Add the E2SM-DAPP grammar (a byte-identical copy of flexric's e2sm_dapp_v0_standard.asn, so the two can be compared with cmp) and a second, independent asn1c run for it, with the same flags as the E3AP one. The output goes to its own directory and is built into its own OBJECT library, asn1_e2sm_dapp, with a copy of the asn1c runtime of its own, compiled -fPIC, -fvisibility=hidden and -w. It shares nothing with asn1_e3ap and does not touch it. An OBJECT library so that the codec libraries that follow can embed the objects and no separate asn1c archive has to be installed. The new option LIBE3_ENABLE_E2SM_DAPP defaults to ON. It needs LIBE3_ENABLE_ASN1: with ASN.1 off, configure prints a status message and treats the codec as off instead of failing. The grammar has no room for an inline SPDX header, so REUSE.toml annotates it. Assisted-by: Claude:claude-sonnet-5-5
Add libe3_e2sm_dapp (static, alias libe3::e2sm_dapp) and libe3_e2sm_dapp_shared (alias libe3::e2sm_dapp_shared), with the C++ API of include/libe3/e2sm_dapp.hpp and the C API of include/libe3/e2sm_dapp_c.h. Both embed the asn1_e2sm_dapp objects ($<TARGET_OBJECTS>) and depend on nothing else in libe3: no agent, no ZeroMQ, no tl::expected, no E3AP grammar. The main libe3 targets do not link them; they only gain a LIBE3_ENABLE_E2SM_DAPP feature define, which reaches libe3.pc like the other feature macros. Encoding builds the asn1c struct, checks every constraint of the grammar by hand first (asn1c can fault inside the encoder on an oversized payload, and silently uses its extension encoding for an out-of-range extensible integer), runs asn_check_constraints as a second net, and encodes APER aligned into a growing buffer, so the 32768 byte maximum of a control message fits. Anything outside the grammar is ASN_ERROR_ENCODE_FAIL and leaves the output empty. Decoding requires RC_OK and applies the same constraints, so a decoded struct always packs again; trailing bytes are accepted, an empty or null buffer, a truncated one and an unknown CHOICE alternative are ASN_ERROR_DECODE_FAIL. The asn1c struct is freed on every path. The extension flag is ignored on encode and false after decode: no extension additions are defined, and asn1c skips unknown ones. The C API is implemented on top of the C++ one and maps asn_code to e3_error_t. Everything it returns is malloc'ed, so the free_* functions and plain free both release it, and free_* zero the struct. The shared library exports only libe3::e2sm_dapp::* and libe3_e2sm_dapp_* (a version script on Linux, an exported symbols list on macOS); the asn1c runtime inside it is hidden, so a consumer with an asn1c of its own does not clash with it. Assisted-by: Claude:claude-sonnet-5-5
Install the two public headers, the grammar (to share/libe3/e2sm_dapp/) and both libraries, and put the libraries in the exported set under the names libe3::e2sm_dapp and libe3::e2sm_dapp_shared (EXPORT_NAME, so they are not libe3::libe3_e2sm_dapp). e2sm_dapp.hpp is excluded from the blanket header install, so a build without the codec does not install a header whose symbols are not there. A separate libe3_e2sm_dapp.pc carries the library, the include path and the feature define for pkg-config consumers. find_package(libe3 REQUIRED COMPONENTS e2sm_dapp) now works: the component is found exactly when the install has both targets, and a required component that is missing (or unknown) fails with a message that says why. Without COMPONENTS nothing changes. The generated asn1c headers of the codec are private and live outside the messages/ build directory, whose *.h are all installed for the E3AP grammar; the CMakeFiles directory of that tree is no longer installed as empty directories. tests/consume checks the installed package: the existing executable also packs and unpacks one message through libe3::e2sm_dapp next to the E3 agent, and a new consume_e2sm_dapp (static and shared) links the codec alone, from C++ and from C, on both the CMake and the pkg-config route. LIBE3_CONSUME_E2SM_DAPP=AUTO|ON|OFF selects whether the codec is required. Assisted-by: Claude:claude-sonnet-5-5
tests/e2sm_dapp_golden.hpp holds the APER bytes flexric's own encoder produces
for 31 inputs (hex for the small ones, length and FNV-1a 64 for the four that
are too large to inline), and tests/e2sm_dapp_fixtures.inc builds the same
inputs in C++ against the names libe3 and OCUDU share (a byte-identical copy
lives in OCUDU). The vectors are the byte-compatibility contract: libe3 must
reproduce each one exactly and decode it back to an equal struct.
test_e2sm_dapp_encode every fixture packs to its golden vector; optional
fields; boundary values; every value outside the
grammar is ASN_ERROR_ENCODE_FAIL with `out` empty
test_e2sm_dapp_decode golden bytes unpack to the fixture; every proper
prefix of every vector is rejected (none is a valid
shorter PDU); empty and null input; trailing bytes;
extension bit; deterministic fuzz, which also
checks that whatever decodes packs again
test_e2sm_dapp_roundtrip pack, unpack, compare, re-pack, including the
32768 byte control message that has no golden vector
test_e2sm_dapp_c_api the C API on every message type: golden bytes, NULL
arguments, double free, error codes, plain free
test_e2sm_dapp_link_coexist
libe3 and libe3::e2sm_dapp, each with its own asn1c
runtime, in one executable: static + static, and
shared libe3 + static codec
The first four are built against both the static and the shared codec library.
They link libe3::e2sm_dapp alone, and are skipped when the codec is not built.
Assisted-by: Claude:claude-sonnet-5-5
regen.sh <flexric-checkout> <asn1c-binary> <gcc> [output-file] rebuilds tests/e2sm_dapp_golden.hpp from an unmodified flexric checkout: it copies the parts of dapp_sm that the codec needs into a scratch tree, drops four unused includes that pull in other service models, regenerates the asn1c code from flexric's grammar, compiles gen_golden.c against flexric's real encoder and decoder with a GCC (flexric's defer macro needs nested functions), and runs gen_header.py on the output. The flexric commit named in the header comes from git rev-parse HEAD of the checkout. Run against flexric 71631466 it reproduces the committed header byte for byte. gen_golden.c and gen_header.py, which produced the vectors, join the tree here. gen_golden.c gets its SPDX header, and gen_header.py wraps the SPDX lines it prints in REUSE-IgnoreStart/End so that reuse lint does not read them as its own; its output is unchanged. Assisted-by: Claude:claude-sonnet-5-5
Specify E2SM-DAPP sections 1 to 3: RAN function id, OID and how the definition is announced in E2 Setup and RIC Service Update; every information element with fields, ranges, formats and the service to format table, including the control outcome payload and the Spectrum worked example; and the discovery, subscription, indication and deferred-acknowledge flow with the sequence-id chain and the code of each step in flexric, OAI, xDevSM and OCUDU. Assisted-by: Claude:claude-sonnet-5-5
Specify E2SM-DAPP sections 4 to 6: the APER rules with byte-level worked examples re-derived against the golden vectors, size limits, the type map across flexric, libe3 and OCUDU and the build switches; units, clocks, absent versus zero, validation and error paths per implementation; and the list of discrepancies, limits, aborts and dead code found in the code, with file and line. Assisted-by: Claude:claude-sonnet-5-5
Add the dispatcher page that maps the six sections to their files, the integrator guide for a RAN stack adopting the codec (link libe3, run asn1c, the OCUDU to libe3 interface, the shared fixtures, the golden vector contract and a checklist), and link the specification from the top-level README and its directory tree. Assisted-by: Claude:claude-sonnet-5-5
…bles The E2SM-DAPP codec is a new public API, so the next free minor is 0.3.0. Assisted-by: Claude:claude-sonnet-5-5
The generator's offset basis had its last digit dropped, so the hashes of the four vectors too large to inline were not FNV-1a 64 values, although the documentation said they were. Fix the constant in the generator and the test helper, regenerate the header, and update the hashes in the encoding notes. The bytes of every vector are unchanged. Assisted-by: Claude:claude-sonnet-5-5
…ound Assisted-by: Claude:claude-sonnet-5-5
Contributor
CI report —
|
| Workflow | Result | Time | Run |
|---|---|---|---|
| E2E Topologies (multi-dApp / multi-RAN) | ❌ failure (Topologies (zmq/tcp)) | 5m36s | #135 |
| Commit policy | ✅ success | 11m15s | #132 |
| E2E dApp Integration | ✅ success | 8m20s | #137 |
| Full-loop Latency Benchmark | ✅ success | 1m24s | #136 |
| Unit Tests | ✅ success | 8m52s | #163 |
| latrec portability | ⏭️ not triggered (paths filter) | — | — |
| MPMC Queue Benchmark | ⏭️ not triggered (paths filter) | — | — |
Failing required checks: Topologies (zmq/tcp)
E2E Topologies (multi-dApp / multi-RAN)
zmq/ipc
- ✅ 1 RAN - 1 dApp: indications=
5dapppeer=t11 ran=ran-solo sub=1 indications=5 seq=[0..4] dropped=0 (0%) age_ms(avg=0.8 max=1 @seq=0) hist[<=1:5 2-5:0 6-10:0 >10:0]
- ✅ 1 RAN - 2 dApps: dApp#1 ind=
5sub=1, dApp#2 ind=6sub=2, RAN saw2dApps - ✅ 2 RANs - 1 dApp: from ran-a ind=
5, from ran-b ind=5
E2E dApp Integration
✅ posix/ipc
- dApp exit:
0 - Indications received:
7
✅ posix/tcp
- dApp exit:
0 - Indications received:
7
✅ zmq/ipc
- dApp exit:
0 - Indications received:
7
✅ zmq/tcp
- dApp exit:
0 - Indications received:
7
Full-loop Latency Benchmark
Full-loop latency
Full-loop latency benchmark (N=1021 after 50 warmup)
All values in microseconds (μs). Link: zmq, transport: ipc, encoding: ASN.1 APER.
| # | Description | Tags | mean | p50 | p99 | max |
|---|---|---|---|---|---|---|
| 1 | Collect indication data | RECORD_BEGIN to ENCODE_E3SM_BEGIN |
0.12 | 0.11 | 0.35 | 2.13 |
| 2 | Create & encode indication | ENCODE_E3SM_BEGIN to ENCODE_E3SM_DONE |
0.99 | 1.00 | 1.51 | 3.68 |
| 3 | Encode E3AP (indication) | EMIT_ENTER to ENQUEUE, then DEQUEUE to ENCODE_E3AP_DONE |
3.02 | 3.02 | 5.52 | 5.86 |
| 4 | Queuing (indication) | ENQUEUE to DEQUEUE |
4.44 | 3.57 | 12.02 | 77.52 |
| 5 | Delivery (indication) | ENCODE_E3AP_DONE to SEND_DONE |
0.27 | 0.25 | 0.70 | 1.86 |
| 6 | E3 wire (RAN -> dApp) | SEND_DONE to RECV |
52.11 | 53.17 | 63.37 | 175.40 |
| 7 | Decode E3AP (indication) | RECV to DECODE_E3AP_DONE |
1.62 | 1.45 | 2.58 | 18.50 |
| 8 | libe3 dispatch (indication) | DECODE_E3AP_DONE to DELIVER_BEGIN |
0.10 | 0.10 | 0.16 | 0.27 |
| 9 | Decode indication | DELIVER_BEGIN to DECODE_E3SM_DONE |
0.55 | 0.52 | 0.83 | 1.09 |
| 10 | Process data | DECODE_E3SM_DONE to ENCODE_E3SM_BEGIN |
0.04 | 0.04 | 0.05 | 0.16 |
| 11 | Create & encode control | ENCODE_E3SM_BEGIN to ENCODE_E3SM_DONE |
0.35 | 0.35 | 0.50 | 0.64 |
| 12 | Encode E3AP (control) | EMIT_ENTER to ENQUEUE, then DEQUEUE to ENCODE_E3AP_DONE |
3.90 | 3.92 | 4.83 | 6.61 |
| 13 | Queuing (control) | ENQUEUE to DEQUEUE |
17.81 | 17.09 | 24.20 | 77.88 |
| 14 | Delivery (control) | ENCODE_E3AP_DONE to SEND_DONE |
5.49 | 5.21 | 8.24 | 11.11 |
| 15 | E3 wire (dApp -> RAN) | SEND_DONE to RECV |
51.01 | 51.46 | 59.91 | 304.75 |
| 16 | Decode E3AP (control) | RECV to DECODE_E3AP_DONE |
2.87 | 2.79 | 4.20 | 10.86 |
| 17 | libe3 dispatch (control) | DECODE_E3AP_DONE to DECODE_E3SM_BEGIN |
0.30 | 0.30 | 0.42 | 0.50 |
| 18 | Decode & handle control | DECODE_E3SM_BEGIN to DECODE_E3SM_DONE |
0.41 | 0.38 | 0.57 | 0.79 |
| Total | Total round-trip | 145.86 | 146.95 | 166.50 | 603.06 |
ubuntu-latest, Release build, ZMQ + IPC, ASN.1 APER.
These numbers are measured inside a GitHub Actions container and should be treated as an upper bound on E3AP's and the library's own latency, not a representative deployment measurement.
One comment per PR, rewritten in place once every workflow for
5703c81finished.
This branch has not been deployed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
1.3.6.1.4.1.53148.1.1.255.3). Until now the grammar and its meaning lived only inside one RAN stack's source tree, so no other stack could encode or decode these messages.docs/e2sm-dapp/is the specification, in six parts, plus a separate integrator guide.What changes for a user
find_package(libe3 REQUIRED COMPONENTS e2sm_dapp)giveslibe3::e2sm_dapp(static) andlibe3::e2sm_dapp_shared. Headers:libe3/e2sm_dapp.hppandlibe3/e2sm_dapp_c.h. The grammar goes toshare/libe3/e2sm_dapp/.LIBE3_ENABLE_E2SM_DAPP, default ON, needsLIBE3_ENABLE_ASN1. With ASN.1 off it is skipped with a status message, not an error.libe3library. The main library does not link the new one.How it is checked
tests/e2sm_dapp_golden.hpp) are APER encodings of 31 inputs produced by an existing, independent E2SM-DAPP encoder. Every one must pack to those exact bytes and unpack to an equal struct.tools/e2sm_dapp_golden/regen.shreproduces the header from a pristine checkout of that encoder.tests/e2sm_dapp_fixtures.incbuilds every test input through those shared names.Things to know
libe3andlibe3::e2sm_dappcarry an asn1c runtime. The one in the codec is hidden, and a test links and runs both together.VERSIONgoes to 0.3.0 (new public API).libe3.pcgains-DLIBE3_ENABLE_E2SM_DAPPin its Cflags, and a separatelibe3_e2sm_dapp.pcis installed.Type of change
Linked issue
No issue exists for this yet. I can file one if you want it linked.
Test checklist
./build_libe3 -c -d build -j $(nproc) -r -t(Release): not run through the script. The E2SM-DAPP tests pass in a Release build; CI runs the full set../build_libe3 -c -d build -j $(nproc) -g -t(Debug): the equivalent plain CMake Debug build passes 30 of 30 tests on macOS arm64, with ZeroMQ on and JSON and protobuf off.cd build && ctest --output-on-failure: see above. Also built with the flag OFF (20 of 20) and with ASN.1 OFF (19 of 19).mpmc_queue.hppis untouched.VERSIONbumped (0.2.2 to 0.3.0)../build_libe3 --docs: not run. Public headers carry Doxygen comments.libe3.pcconsumers: the Cflags change above is additive. I could not checkdApp-openairinterface5g.Twin-repo coordination
Workflow confirmation
main, no merge commits.Commit policyjob covers the rest.CONTRIBUTING.md.