E1AP interface architecture

How OCUDU implements both ends of the E1AP (E1) interface — class ownership on CU-CP and CU-UP sides, bearer context procedures, connection modes, and concurrency model. Reference: 3GPP TS 38.463.

Target audience: RAN engineers. Scope: the E1AP (E1) interface implementation in OCUDU — class ownership, procedure layout, bearer context management (Setup, Modification, Release), connection and transport, and concurrency. Reference: 3GPP TS 38.463.


1. What E1AP Does

E1 is the interface between the Central Unit Control Plane (CU-CP) and the Central Unit User Plane (CU-UP). The E1AP protocol (3GPP TS 38.463) runs over this interface and carries one category of messages: bearer context management. The CU-CP directs the CU-UP to create, modify, or release PDCP/SDAP entities for a UE; the CU-UP executes those instructions and reports back.

In OCUDU the two sides are separate compilation units:

  • e1ap_cu_cp_impl (lib/e1ap/cu_cp/e1ap_cu_cp_impl.h) — lives inside the CU-CP process, owns the initiating side of all procedures.
  • e1ap_cu_up_impl (lib/e1ap/cu_up/e1ap_cu_up_impl.h) — lives inside the CU-UP process, executes bearer operations and reports metrics.

When both run in the same process (the typical single-binary deployment) they connect through e1_local_connector_factory, which wires the two sides together without any SCTP hop. In split deployments each side connects to a separate SCTP endpoint.


2. Design Principles

  1. Strict CU-CP initiator model. All bearer-context procedures (Setup, Modification, Release) are started by the CU-CP side. The CU-UP may emit unsolicited notifications (Release Request, Inactivity Notification, DL Data Notification), but it never initiates a transactional exchange.

  2. Global transaction manager per side. Each implementation holds a single e1ap_event_manager (CU-CP calls it e1ap_transaction_manager) with 256 transaction slots. This is a shared pool across all UEs, not one manager per UE.

  3. Per-UE bearer transaction manager on the CU-CP side. In addition to the global pool, e1ap_cu_cp_impl creates one e1ap_bearer_transaction_manager per UE. This manager tracks the three per-UE transactional outcomes: context_setup_outcome, context_modification_outcome, and context_release_complete. This design lets the global pool handle the wire-level transaction ID while the per-UE object correlates outcomes to specific UE state.

  4. Coroutine-based procedures. Initiating procedures are async_task<R> coroutines using CORO_BEGIN / CORO_AWAIT_VALUE / CORO_RETURN. They suspend at the point of sending the request and resume when the response arrives or the transaction times out.

  5. Two distinct UE ID namespaces. The CU-CP allocates gnb_cu_cp_ue_e1ap_id using a sequential hole-filling scan. The CU-UP allocates gnb_cu_up_ue_e1ap_id using a simple monotonic counter. Both IDs are exchanged and must appear in every subsequent message for that UE.

  6. Transport abstraction. e1_connection_server (CU-CP), e1_connection_client (CU-UP), and e1_local_connector_factory implement the same gateway pattern used by F1AP. The application picks the transport at startup based on whether it is running in split or co-located mode.

  7. Metrics on the CU-UP side. The CU-UP implementation maintains e1ap_cu_up_metrics_collector and a periodic metrics_timer. The CU-CP side has no equivalent metrics object.


3. Class Structures

3.1 CU-CP Side — e1ap_cu_cp_impl

e1ap_cu_cp_impl
├── cu_up_index_t                          one instance per CU-UP
├── e1ap_transaction_manager              global 256-slot transaction pool
├── e1ap_ue_context_list                  map: gnb_cu_cp_ue_e1ap_id → e1ap_ue_context
│   └── e1ap_ue_context
│       ├── gnb_cu_cp_ue_e1ap_id          sequential, hole-filling
│       ├── gnb_cu_up_ue_e1ap_id          received from CU-UP
│       └── e1ap_bearer_transaction_manager
│           ├── context_setup_outcome
│           ├── context_modification_outcome
│           └── context_release_complete
└── e1_release_in_progress                bool flag, prevents duplicate release

ID Allocation — CU-CP Side. gnb_cu_cp_ue_e1ap_id is assigned during Bearer Context Setup. The allocator scans the used-ID set from 0 upward and assigns the first gap (hole-filling). This keeps IDs compact when UEs leave and new ones arrive.

3.2 CU-UP Side — e1ap_cu_up_impl

e1ap_cu_up_impl
├── e1ap_cu_up_connection_handler         SCTP or local connector
├── e1ap_event_manager                    global 256-slot transaction pool
├── e1ap_ue_context_list                  map: gnb_cu_up_ue_e1ap_id → e1ap_cu_up_ue_context
│   └── e1ap_cu_up_ue_context
│       ├── gnb_cu_up_ue_e1ap_id          monotonic counter (++)
│       └── gnb_cu_cp_ue_e1ap_id          received from CU-CP
├── metrics_timer                         periodic trigger
└── e1ap_cu_up_metrics_collector          per-bearer metrics aggregation

ID Allocation — CU-UP Side. gnb_cu_up_ue_e1ap_id is a simple next_id++ counter. There is no hole-filling; IDs grow monotonically for the lifetime of the CU-UP process.


4. ASN.1 Layer

Namespace: asn1::e1ap

Root PDU type: e1ap_pdu_c — a discriminated union of init_msg, successful_outcome, unsuccessful_outcome, each wrapping the procedure-specific IE set.

Packers:

  • e1ap_asn1_packer — common encoder/decoder sitting on the SCTP transport.
  • e1ap_cu_cp_asn1_helpers.h — helper functions for CU-CP message construction.
  • e1ap_cu_up_asn1_helpers.h — helper functions for CU-UP message construction.

All PDUs are encoded as aligned PER (Packed Encoding Rules) per the standard.


5. E1 Setup

E1 Setup bootstraps the association between one CU-CP and one CU-UP. The CU-UP is always the initiator.

sequenceDiagram
    participant CU_UP as CU-UP<br/>e1ap_cu_up_impl
    participant CU_CP as CU-CP<br/>e1ap_cu_cp_impl

    CU_UP->>CU_CP: E1SetupRequest
    Note over CU_UP: e1ap_cu_up_setup_procedure<br/>async_task<cu_up_e1_setup_response><br/>timeout = 3000 ms
    alt Setup accepted
        CU_CP-->>CU_UP: E1SetupResponse
        Note over CU_UP: CORO_AWAIT resolves success
    else Setup rejected with time_to_wait
        CU_CP-->>CU_UP: E1SetupFailure (time_to_wait IE)
        Note over CU_UP: Procedure retries after wait
    end

CU-UP procedure class: e1ap_cu_up_setup_procedure (lib/e1ap/cu_up/procedures/e1ap_cu_up_setup_procedure.h). It is a coroutine (async_task<cu_up_e1_setup_response>). The transaction timeout is 3000 ms. On time_to_wait in the failure response, the procedure waits the indicated duration and retries.

CU-CP response: Handled inline — there is no procedure class on the CU-CP side for E1 Setup. The CU-CP validates the request and responds synchronously within the message handler.


6. E1 Reset

Reset is bidirectional: either side may initiate it. Both sides have dedicated procedure classes.

DirectionInitiator ClassResponder Class
CU-CP initiatescu_cp_e1_reset_proceduree1ap_cu_up_reset_procedure
CU-UP initiatese1ap_cu_up_reset_procedure (initiator)cu_cp_e1_reset_procedure (responder)

Reset tears down UE contexts on both sides. On the CU-CP, a reset cascades through the UE context list and triggers release of any active bearer transaction managers.


7. E1 Removal

E1 Removal gracefully tears down the CU-UP association. The CU-UP initiates.

  • CU-UP side: e1ap_cu_up_release_procedure — sends E1RemovalRequest, awaits E1RemovalResponse.
  • CU-CP side: e1_release_procedure — responds inline. The e1_release_in_progress flag is set before the response is sent to prevent any parallel bearer procedures from starting.

8. Bearer Context Procedures

8.1 Bearer Context Setup

The CU-CP instructs the CU-UP to create PDCP/SDAP entities for a new UE or new bearer.

sequenceDiagram
    participant CU_CP as CU-CP
    participant CU_UP as CU-UP

    CU_CP->>CU_UP: BearerContextSetupRequest<br/>(gnb_cu_cp_ue_e1ap_id, bearer list)
    Note over CU_CP: bearer_context_setup_procedure<br/>async_task, CORO_AWAIT(txn)
    Note over CU_UP: Allocates gnb_cu_up_ue_e1ap_id<br/>Creates PDCP/SDAP entities
    CU_UP-->>CU_CP: BearerContextSetupResponse<br/>(gnb_cu_up_ue_e1ap_id, tunnel endpoints)
    Note over CU_CP: CORO_AWAIT resolves<br/>Stores gnb_cu_up_ue_e1ap_id
  • CU-CP: bearer_context_setup_procedure — coroutine, allocates gnb_cu_cp_ue_e1ap_id, sends request, awaits context_setup_outcome.
  • CU-UP: Inline handler — no separate procedure class. Allocates gnb_cu_up_ue_e1ap_id, creates bearer context, sends response synchronously.

8.2 Bearer Context Modification

The CU-CP modifies bearers for an existing UE (add/modify/release DRBs).

Both sides have dedicated procedure classes:

  • CU-CP: Coroutine that sends BearerContextModificationRequest, awaits context_modification_outcome.
  • CU-UP: Coroutine that receives the request, modifies the bearer entities, sends BearerContextModificationResponse or BearerContextModificationFailure.

8.3 Bearer Context Release (CU-CP Initiated)

The CU-CP releases all bearers for a UE.

Both sides have dedicated procedure classes:

  • CU-CP: Coroutine that sends BearerContextReleaseCommand, awaits context_release_complete.
  • CU-UP: Coroutine that receives the command, tears down PDCP/SDAP entities, sends BearerContextReleaseComplete.

9. Non-Transactional Notifications (CU-UP → CU-CP)

The following messages flow from CU-UP to CU-CP and carry no transaction correlation — the CU-UP sends them and does not await a response.

MessageTriggerHandler
Bearer Context Release RequestCU-UP detects a reason to release (e.g., lower-layer failure)Inline handler on CU-CP; cascades to UE release
Bearer Context Inactivity NotificationInactivity timer fires on a PDCP entityInline handler on CU-CP; may trigger release or modification
DL Data NotificationDownlink data arrives for a UE in RRC_INACTIVEInline handler on CU-CP; triggers paging

None of these messages has a matching procedure class on either side.


10. Object Lifecycle: UE E1AP Context


11. Connection and Transport

Three gateway implementations exist, selected at startup by the application:

ModeCU-CPCU-UP
Splite1_connection_server — listens on SCTPe1_connection_client — connects to CU-CP
Co-locatede1_local_connector_factorye1_local_connector_factory

The local connector wires the two e1ap_message_handler interfaces directly in memory with no serialization overhead. The SCTP paths run through e1ap_asn1_packer on both ends.


12. Concurrency

  • The global e1ap_transaction_manager (256 slots) is shared across all UEs. Transaction ID 0–255 is allocated per request and released when the response arrives or the transaction times out.
  • Per-UE e1ap_bearer_transaction_manager is single-threaded because the CU-CP UE task executor serializes all operations for a given UE.
  • The CU-UP event manager is accessed from the CU-UP task executor; no locking is needed inside the CU-UP implementation.
  • The e1_release_in_progress flag on the CU-CP side is checked before any new bearer procedure begins; this is a single-bool guard, not a mutex, relying on the strand semantics of the UE executor.

13. Not Implemented

Procedure3GPP ReferenceStatus
gNB-CU-UP Config UpdateTS 38.463 Section 8.2.4Not implemented — no procedure class, no handler
gNB-CU-CP Config UpdateTS 38.463 Section 8.2.5Not implemented — no procedure class, no handler
Bearer Context Modification RequiredTS 38.463 Section 8.3.3Not implemented — no CU-UP-initiated modification class

14. Procedure Cross-Reference

Procedure3GPP RefCU-CP ClassCU-UP ClassPattern
E1 SetupSection 8.2.1Inline handlere1ap_cu_up_setup_procedureCU-UP coroutine, 3000 ms timeout, retry on time_to_wait
E1 ResetSection 8.2.2cu_cp_e1_reset_proceduree1ap_cu_up_reset_procedureBoth sides bidirectional
E1 RemovalSection 8.2.3e1_release_proceduree1ap_cu_up_release_procedureCU-UP initiates, CU-CP responds
gNB-CU-UP Config UpdateSection 8.2.4Not implemented
gNB-CU-CP Config UpdateSection 8.2.5Not implemented
Bearer Context SetupSection 8.3.1bearer_context_setup_procedureInline handlerCU-CP coroutine, CORO_AWAIT(context_setup_outcome)
Bearer Context ModificationSection 8.3.2Procedure classProcedure classBoth sides coroutine
Bearer Context Modification RequiredSection 8.3.3Not implemented
Bearer Context Release (CP)Section 8.3.4Procedure classProcedure classCU-CP initiates, both coroutine
Bearer Context Release RequestSection 8.3.5Inline handlerInline sendNon-transactional
Bearer Context Inactivity NotificationSection 8.3.6Inline handlerInline sendNon-transactional
DL Data NotificationSection 8.4.1Inline handlerInline sendNon-transactional
Error IndicationSection 8.5Inline handlerInline sendNon-transactional