|
libe3 0.2.5
C++ library for E3AP RAN vendor integration
|
Files | |
| e3_dapp_session.cpp | |
| Implementation of the batched dApp Python seam. See e3_dapp_session.hpp. | |
| e3_dapp_session.hpp | |
| Python-facing dApp session over libe3 — batched, low-latency seam. | |
| libe3_swig.hpp | |
SWIG bindings that let Python drive libe3 in the dApp role. A Python dApp can delete its pure-Python E3AP stack (ZMQ + asn1tools) and let libe3 own E3AP on both ends of the link — exactly the split OAI already uses on the RAN side. An example consumer is available in dApp-library.
libe3 owns E3AP: transport, the setup handshake, subscribe/unsubscribe, indication/control framing, and all wire encodings (ASN.1 / JSON / Protobuf, selected at runtime by E3Config.encoding). Python owns E3SM: the service-model payloads ride opaque, as bytes, and are encoded/decoded in Python. libe3py never touches SM contents.
| Symbol | Purpose |
|---|---|
| E3Config, enums (E3Role, E3LinkLayer, E3TransportLayer, EncodingFormat, ResponseCode, AgentState, ErrorCode) | Configure a session. |
| E3Agent (minimal view) | Backwards-compatible seam: construct/config/start, push opaque bytes. Kept for the smoke test. |
| DAppSession + E3Event | The real dApp seam: full lifecycle + a batched, lock-free inbound queue. This is what a Python dApp consumes. |
See e3_dapp_session.hpp for the authoritative, Doxygen-documented API.
E3AP runs at real-time sub-millisecond cadence with very high message throughput, so the binding must not become the bottleneck. At those rates the limiters are the count of GIL acquisitions, the count of Python↔C++ boundary crossings, and libe3's C++ worker threads stalling on the GIL — not payload copy size (E3AP payloads are small; bulk IQ travels out-of-band in shared memory).
DAppSession therefore:
Rejected alternatives: SWIG directors run the Python callback on libe3's inbound thread under the GIL (serialises dispatch, deadlock-prone if Python re-enters libe3); a per-message poll pays one GIL round-trip per message and caps throughput with no latency benefit over batching.
On Linux (x86_64 and aarch64, glibc 2.28 or newer, Python 3.10 to 3.13) the binding is a prebuilt wheel that contains libe3, so one command in any virtual environment is enough, with no libe3 installed:
Elsewhere, and from a checkout (pip install .), install libe3 once (./build_libe3 --all-encodings --install, see the main README) and pip builds the module from these sources against the installed libe3 (python/CMakeLists.txt); it needs swig >= 4.0, the Python headers and a C++17 compiler (./build_libe3 -I installs them), and it stops with an error if the installed libe3 is not the same version. For a libe3 outside /usr and /usr/local: pip install --no-binary libe3py libe3py --config-settings=cmake.define.CMAKE_PREFIX_PATH=<prefix>.
For development, ./build_libe3 --enable-swig builds the module in build/swig (run the smoke test with PYTHONPATH=build/swig python3 tests/test_swig_smoke.py); cmake --install installs it only if -DLIBE3_PYTHON_INSTALL_DIR=<dir> is given.
The Simple SM grammar is installed alongside the library under <datadir>/libe3/sm/sm_simple/ — both e3sm_simple.asn (ASN.1) and e3sm_simple.proto (Protobuf) — discoverable via pkg-config --variable=smdir libe3, so Python dApps can reuse the exact grammar their C++ counterpart (examples/simple_agent.cpp) uses instead of copying it.