feat: subscribe() returns request id, monotonic message id, protobuf via C API - #47
Merged
Merged
Conversation
…obuf via C API Enable request/response correlation and unblock protobuf E3AP for C-API peers: - subscribe() now returns the assigned E3-MessageID (via a new out-param threaded through queue_subscription_request -> E3Agent::subscribe -> the SWIG DAppSession::subscribe, which returns the positive id on success and a negative ErrorCode on failure). The RAN already echoes request_id in the SubscriptionResponse, so a caller can now correlate a response to the originating subscribe by id instead of relying on FIFO ordering. - generate_message_id() is now a lock-free monotonic counter wrapping into the ASN.1 E3-MessageID (1..1000) range, replacing the random draw that could collide and defeat correlation. Matches the counter scheme already used on the aerial/cuBB side. - c_api encoding clamp widened 0..1 -> 0..2 so config->encoding = PROTOBUF (2) reaches libe3 instead of being silently dropped; c_api.h doc updated. - VERSION 0.0.9 -> 0.0.10 (ABI change). Assisted-by: Claude:claude-opus-4-8
JSON had no build_libe3 flag and defaulted off, so `build_libe3 --enable-swig` silently produced a libe3/libe3py without the JSON encoder (encoding=json then failed at start() with INTERNAL_ERROR). Add --enable-json/--disable-json mirroring asn1/protobuf and default JSON on, so asn1+json build by default (protobuf stays opt-in). Release .deb variants are unaffected (the workflow calls cmake with explicit -DLIBE3_ENABLE_* flags, not build_libe3). Assisted-by: Claude:claude-opus-4-8
Contributor
⏱️ Full-loop Latency Benchmark (commit
|
| Phase | mean | p50 | p99 | max |
|---|---|---|---|---|
| 1. Collect indication data | 0.16 | 0.14 | 0.30 | 7.27 |
| 2. Create & encode indication | 0.74 | 0.67 | 1.70 | 8.90 |
| 3. Deliver indication (RAN -> dApp) | 92.87 | 87.92 | 162.21 | 183.45 |
| 4. Decode indication | 0.60 | 0.56 | 1.20 | 8.23 |
| 5. Process data | 0.04 | 0.03 | 0.04 | 9.16 |
| 6. Create & encode control | 0.30 | 0.27 | 0.66 | 8.72 |
| 7. Deliver control (dApp -> RAN) | 108.81 | 109.47 | 178.82 | 552.91 |
| 8. Decode & handle control | 0.53 | 0.47 | 1.11 | 14.18 |
| Total round-trip | 204.06 | 195.52 | 330.84 | 594.45 |
Benchmarked on
ubuntu-latest, Release build, ZMQ + IPC, ASN.1 APER.
Contributor
🔄 E2E dApp Integration Results (commit
|
Contributor
🔀 E2E Topologies — multi-dApp / multi-RAN (commit
|
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
subscribe()so a dApp can correlate aSubscriptionResponse(which echoesrequest_id) back to the originating request by id, instead of relying on FIFO ordering that desyncs on a dropped/reordered response. The id is threaded via an out-paramqueue_subscription_request→E3Agent::subscribe→ the SWIGDAppSession::subscribe, which now returns the positive id on success / negativeErrorCodeon failure.generate_message_id()a lock-free monotonic counter wrapping into the ASN.1E3-MessageID (1..1000)range, replacing the random draw that could collide within the in-flight window and defeat that correlation.e3_config_t.encodingclamp inc_api.cppfrom0..1to0..2(it silently droppedPROTOBUF=2), and document it inc_api.h.build_libe3: add--enable-json/--disable-jsonand default JSON on — JSON previously had no flag and defaulted off, sobuild_libe3 --enable-swigproduced a library/binding without the JSON encoder (a JSON peer then failed atstart()withINTERNAL_ERROR). ASN.1+JSON now build by default; protobuf stays opt-in.Type of change
Linked issue
No standalone tracking issue — this is coordinated with paired changes in the twin repos (see Twin-repo coordination). Happy to file one if preferred.
Mandatory test checklist
./build_libe3 -c -d build -j $(nproc) -r -tpasses (Release build + tests)./build_libe3 -c -d build -j $(nproc) -g -tpasses (Debug build + tests)cd build && ctest --output-on-failureis clean (18/18)main(this PR does not touchmpmc_queue.hpp)VERSIONbumped per SemVer (0.0.9 → 0.0.10; ABI change —subscribe()return contract)include/touched;./build_libe3 --docsrenders with no new Doxygen warnings vsmainlibe3.pcinterface unchanged; downstream consumers still link cleanly (verified: the OAI gNB twin builds and runs against this)CI checklist
Unit Testsworkflow is green (Debug + Release matrix) — will run on this PRCommit policyworkflow is green — commits carryAssisted-by:and noCo-authored-by/Signed-off-by; verified locally withscripts/check_commit_trailers.pyMPMC Queue Benchmark— not triggered (mpmc_queue.hppunchanged)Twin-repo coordination
This PR changes the public ABI (
subscribe()return contract) and the C-API encoding acceptance, so it is released together with paired changes in the twins:dapps): consumes the returned request id for id-based subscription correlation, and adds the protobuf E3SM codec path.encoding = PROTOBUFthrough the C API and adds a protobuf-c SM payload codec.Validated end-to-end: the OAI gNB (rfsim, core-less) driving the real spectrum dApp passes for asn1, json, and protobuf.
Paired PR(s): prepared in the
dApp-libraryanddApp-openairinterface5gtwins; released alongside this PR.Workflow confirmation
main, no merge commits.CONTRIBUTING.md.