Rewrite F1 documentation
This commit is contained in:
+256
-186
@@ -12,204 +12,44 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
# 1. Introduction
|
||||
[[_TOC_]]
|
||||
|
||||
We use OpenAirInterface source code, and it's regular deployment scheme.
|
||||
# Introduction
|
||||
|
||||
F1 specification is in 3GPP documents: TS 38.470 header document and all documents listed in chapter 2 References of TS 38.470.
|
||||
The F1 interface is the functional split of 3GPP between the CU (centralized
|
||||
unit: PDCP, RRC, SDAP) and the DU (distributed unit: RLC, MAC, PHY). It is
|
||||
standardized in TS 38.470 - 38.473 for 5G NR. No equivalent for 4G exists.
|
||||
|
||||
This document explains how the source code works.
|
||||
We assume that each DU handles only one cell. Multiple DUs connected to one CU
|
||||
are supported. Mobility over F1 is not yet supported.
|
||||
|
||||
Offered features and deployment instructions are described in:
|
||||
https://gitlab.eurecom.fr/oai/openairinterface5g/-/wikis/f1-interface
|
||||
# Control plane status (F1-C)
|
||||
|
||||
# 2. Common multi-threading architecture #
|
||||
## Implementation Status
|
||||
|
||||
The CU and DU interfaces are based on ITTI threads (see oai/common/utils/ocp_itti/itti.md)
|
||||
Note that OAI uses F1 "internally". That means, that even if you run a
|
||||
monolithic gNB, the internal information exchange uses F1. You can therefore
|
||||
expect that everything working in a monolithic deployment should also work in
|
||||
F1. The current implementation is based on R16.3.
|
||||
|
||||
All OAI upper layers use the ITTI framework to run isolated threads dedicated to one feature.
|
||||
The lower layers adopt case by case specific software architecture.
|
||||
Note that NSA does NOT follow this logic yet, and does not work with F1.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Linux[configuration file] --> APP[gNB_app_task]
|
||||
Socks[Linux UDP] --> GTP[nr_gtpv1u_gNB_task]
|
||||
APP --> CU
|
||||
APP --> DU
|
||||
A[Linux SCTP] -->|sockets| SCTP(OAI itti thread TASK_SCTP)
|
||||
SCTP-->|TASK_NGAP| NG[ngap_gNB_task]
|
||||
NG-->|TASK_SCTP| SCTP
|
||||
SCTP-->|TASK_DU_F1| DU[F1AP_DU_task]
|
||||
SCTP-->|TASK_CU_F1| CU[F1AP_CU_task]
|
||||
CU-->|TASK_RRC_GNB| RRC
|
||||
RRC -->|non ITTI| PHY[OAI L1+L2]
|
||||
RRC -->|API calls to create tunnels| GTP
|
||||
PHY --> |user plane| GTP
|
||||
CU --> |TASK_GTPV1_U| GTP
|
||||
DU --> |TASK_GTPV1_U| GTP
|
||||
```
|
||||
A "task" is a Linux thread running infinite waiting loop on one ITTI queue
|
||||
The following messages are currently implemented:
|
||||
|
||||
app task manages the initial configuration
|
||||
- F1 Setup Request and F1 Setup Response/Failure
|
||||
- Initial UL RRC, UL/DL RRC Message Transfer
|
||||
- F1 UE Context management messages for the "good case"
|
||||
* Setup Request/Response
|
||||
* Modification Request/Response
|
||||
* Release Request/Command/Complete
|
||||
|
||||
sctp task mamanges the SCTP Linux sockets
|
||||
All other messages are not implemented or not working reliably:
|
||||
|
||||
CU code runs in the task F1AP_CU_task. It stores it's private data context in a static variable. No mutex is used, as the single interface to CU ITTI tast in incoming ITTI messages. CU task is a single ITTI queue, but multiple CU could exist in one Linux process, using the "instance id" (called "module id" also) to create separate contextual information for each CU instance.
|
||||
- F1 CU/DU configuration updade
|
||||
- Paging messages
|
||||
- Warning Message transmissions
|
||||
|
||||
DU code runs in the task F1AP_DU_task. The design is similar to CU task
|
||||
|
||||
All GTP-U tunnels are managed in a Linux Thread, that have partially ITTI design:
|
||||
|
||||
1. tunnel creation/deletion is by C API functions direct calls (a mutex protects it)
|
||||
2. outgoing packets are pushed in a ITTI queue to the gtp thread
|
||||
3. incoming packets are sent to the tunnel creator using a C callback (the callback function is given in tunnel creation order). The callback should not block
|
||||
|
||||
|
||||
# 3. CU F1AP messages #
|
||||
|
||||
## startup
|
||||
|
||||
CU thread starts when the CU starts. It opens listening socket on F1AP_PORT_NUMBER by sending the appropriate message to TASK_SCTP.
|
||||
|
||||
It will accept the first incoming connection on this port
|
||||
|
||||
## F1 SETUP
|
||||
|
||||
DU has connected, and sent this message.
|
||||
|
||||
The CU receives, decode it and send relevant information to RRC thread by message F1AP_SETUP_REQ
|
||||
|
||||
## F1 SETUP response
|
||||
|
||||
RRC sends two messages to CU F1 task: the information to encode the F1 setup response and a second message to encode F1AP_GNB_CU_CONFIGURATION_UPDATE
|
||||
|
||||
Upon reception of these two messages the CU task encodes and sends the messages to the DU
|
||||
|
||||
## UE entry
|
||||
|
||||
When CCH channel decoding finds a new UE identity, it call rrc_gNB_generate_RRCSetup() that will send F1AP_DL_RRC_MESSAGE to the CU task.
|
||||
|
||||
The CU encodes and sends to DU DLRRCMessageTransfer
|
||||
|
||||
## UE attach/detach
|
||||
|
||||
When rrc_gNB_process_RRCReconfigurationComplete() occurs, the RRC sends to CU task the message F1AP_UE_CONTEXT_SETUP_REQ. The CU task encodes the F1 message UEContextSetup and send it to the DU over F1AP.
|
||||
|
||||
This function rrc_gNB_process_RRCReconfigurationComplete() also creates the GTP-U user plane bearers.
|
||||
|
||||
## F1AP incoming messages
|
||||
|
||||
SCTP tasks sends a ITTI message SCTP_DATA_IND to the CU task.
|
||||
|
||||
A array of functions pointers and the F1AP standard identifier "procedureCode", the CU calls the appropriate function
|
||||
|
||||
Hereafter the most significant messages processing
|
||||
|
||||
### CU_handle_F1_SETUP_REQUEST
|
||||
|
||||
Transcodes information to the same message toward RRC (F1AP_SETUP_REQ)
|
||||
|
||||
### CU_handle_INITIAL_UL_RRC_MESSAGE_TRANSFER
|
||||
|
||||
Transcodes information to the same message toward RRC (NR_RRC_MAC_CCCH_DATA_IND)
|
||||
|
||||
### CU_handle_UL_RRC_MESSAGE_TRANSFER
|
||||
|
||||
Encode and send data to PDCP (calling pdcp_data_ind ()) for processing UL data.
|
||||
|
||||
# DU F1 Messages
|
||||
|
||||
## Startup
|
||||
|
||||
The task "gNB app" after rzading the configuration file, sends a first message F1AP_SETUP_REQ to DU task
|
||||
|
||||
Using this message, the uniq DU task (Linux Thread) creates a DU instance context memory space, calls SCTP task to create a socket to the CU.
|
||||
|
||||
When it receives from the SCTP task the socket creation success, the DU task encodes+sends the F1 setup message to the CU.
|
||||
|
||||
## F1AP_INITIAL_UL_RRC_MESSAGE
|
||||
|
||||
When MAC layer push UL data to DU task, the DU sends to CU the message InitialULRRCMessageTransfer
|
||||
|
||||
## F1AP_UL_RRC_MESSAGE
|
||||
|
||||
In case of SRB bearer, the RLC layer use this message to push rlc bearer payload to DU task, that forward to CU
|
||||
|
||||
## pdcp_data_ind
|
||||
|
||||
This function call in RLC, when it is a DRB will be replaced by F1-U transport to CU
|
||||
|
||||
## F1AP incoming messages
|
||||
|
||||
SCTP tasks sends a ITTI message SCTP_DATA_IND to the DU task.
|
||||
|
||||
A array of functions pointers and the F1AP standard identifier "procedureCode", the DU calls the appropriate function
|
||||
|
||||
Hereafter the most significant messages processing
|
||||
|
||||
### DU_send_F1_SETUP_RESPONSE
|
||||
|
||||
Decode the CU message, then encode a message to TASK_GNB_APP. The thread "APP" extracts the system information block and reconfigure the DU with: du_extract_and_decode_SI(), configure_gnb_du_mac()
|
||||
|
||||
### DU_handle_gNB_CU_CONFIGURATION_UPDATE
|
||||
|
||||
No developped
|
||||
|
||||
### DU_handle_UE_CONTEXT_SETUP_REQUEST
|
||||
|
||||
Push data to RLC layer for transmisstion in DL (to the UE) by calling enqueue_rlc_data_req()
|
||||
|
||||
### DU_handle_DL_RRC_MESSAGE_TRANSFER
|
||||
|
||||
Depending on the content, adds UE context in DU low layers and/or send data to the UE with rlc_data_req()
|
||||
|
||||
# F1-U messages
|
||||
|
||||
The data path by itself doesn't make any difficulty:
|
||||
1. for UL, rlc calls pdcp_data_ind (DRB) or sends a message to RRC (SRB). So, we can replace pdcp_data_ind() by du_pdcp_data_ind() that will push the message in the GTP tunnel. In CU, assuming the tunnel is in place, the right call back decapsulate the transport (cu_ul_recv()), then calls pdcp_data_ind() in CU
|
||||
The SRB are sent in DU RRC tasks via itti F1AP_UL_RRC_MESSAGE (see above the processing)
|
||||
2. For DL, pdcp (in CU for DRBs) calls rlc_data_req (by a decoupling queue and thread rlc_data_req_thread, so function du_rlc_data_req() or enqueue_rlc_data_req()). in DU, assuming the gtp-u tunnel exists, a reception call back (du_dl_recv()) decapsulate the gtp-u packet and calls du_rlc_data_req()
|
||||
|
||||
Hereafter the processing design, that doesn't require to setup a new context storage, as we can use the GTP-U internal tables: rnti+rb=>teid for outgoing gtp-u packets and teid=>rnti+rb for incoming gtp-u packets
|
||||
|
||||
In CU case, the DRB tunnel to DU and the tunnel on N3 have the same key (rnti, rb id), but they run in two different GTP-U instances.
|
||||
Each instance binds on diffrent sockets.
|
||||
|
||||
For F1-U, both DU and CU binds on the full quadruplet (IP source, port source, IP destination, port destination) from the configuration file parameters:
|
||||
local_s_address, remote_s_address,local_s_portd, remote_s_portd
|
||||
|
||||
These 4 values are in:
|
||||
CU: at cell level (same level as nr_cellid parameter), they are read if tr_s_preference = "f1"; is set
|
||||
DU: in block MACRLCs, if tr_n_preference = "f1"; is set in this block
|
||||
|
||||
## tunnels setup
|
||||
In GTP-U, TS 29.281 specifies a option header (NR RAN Container This extension header may be transmitted in a G-PDU over the X2-U, Xn-U and F1-U user plane interfaces), but it is not mandatory optional header (as is the N3 one).
|
||||
|
||||
So, we can use this header a something reliable with other vendors implementation.
|
||||
|
||||
In DL, we need to associate the packet with: rnti, rb (radio bearer) and "mui" (a OAI internal id that is optional and may be removed soon) to call rlc_data_req()
|
||||
|
||||
In UL, we need also the RNTI, the rb
|
||||
|
||||
So, we need to create a gtp-u tunnel for each rb over F1, then manage in CU and DU the association between a uniq TEid and the pair(rnti, rb). This is already what we have in existing OAI GTP-U layer interface.
|
||||
|
||||
In F1AP, for each "DRB to Be Setup Item IEs", we have a field TNL (transport network layer) to set a specific GTP tunnel (@IP, TEid, udp port is always 2152). This is the same for each message related to DRBs. (F1AP carries the SRB payload inside F1AP).
|
||||
|
||||
So, For each F1AP containing DRB setup/modification/deletion, the related GTP-U tunnels will be modified one to one.
|
||||
The exception is the intialisation of new tunnel: in the call to tunnel creation, we need to send the remote TEID, but we don't know yet if we are the initial source. In this case, we issue a dummy (0xFFFF) remote teid; when we receive the remote answer, we get the source teid, that we can inform GTP-U with (using update tunnel).
|
||||
|
||||
## processing on GTP-U incoming message
|
||||
|
||||
Du_dl_recv() or cu_ul_recv() are called because we have set this callbacks in creat/update tunnel calls to gtp-u. As gtp-u maintains a pair(rnti,rbid) associated to each tunnel, the functions can be very simple stateless callback that calls pdcp_data_ind() or rlc_data_req() to get back in normal processing path
|
||||
|
||||
## CU/DU outgoing
|
||||
|
||||
DU rlc north output goes to du_pdcp_data_ind() that push a outgoing packet request to gtp-u, using the rnti+rb as ids. GTP-U must have the tunnel existing, then it simply implement the same as in N3 for exemple.
|
||||
|
||||
CU pdcp south output calls cu_rlc_data_ind() that do the same symetric processing.
|
||||
|
||||
|
||||
# High-level F1-C code structure
|
||||
## High-level F1-C code structure
|
||||
|
||||
The F1 interface is used internally between CU (mostly RRC) and DU (mostly MAC)
|
||||
to exchange information. In DL, the CU sends messages as defined by the
|
||||
@@ -252,3 +92,233 @@ Monolithic: mac_rrc_dl_direct.c | |
|
||||
| |
|
||||
+-------------+
|
||||
```
|
||||
|
||||
# Data plane status (F1-U)
|
||||
|
||||
F1-U uses GTP-U for information exchange. The GTP protocol uses some extensions
|
||||
for NR-U protocol to report buffer status, but this is not properly tested and
|
||||
might malfunction. One limitation is that the current implementation
|
||||
acknowledges each packet individually.
|
||||
|
||||
Multiple DUs at one CU are supported in the data plane (as in the control plane).
|
||||
|
||||
# How to run
|
||||
|
||||
As mentioned earlier, OAI uses F1 internally. It is always compiled in.
|
||||
To start CU/DU, you use `./nr-softmodem` with the appropriate configuration
|
||||
files, for instance:
|
||||
|
||||
```
|
||||
sudo cmake_targets/ran_build/build/nr-softmodem --sa -O ci-scripts/conf_files/gnb-cu.sa.band78.106prb.conf
|
||||
sudo cmake_targets/ran_build/build/nr-softmodem --sa -O ci-scripts/conf_files/gnb-du.sa.band78.106prb.rfsim.conf
|
||||
```
|
||||
|
||||
These files are tested in the CI, and are configured for use in docker,
|
||||
see [this `docker-compose` file](../ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml).
|
||||
|
||||
## Configuration of F1 IP/port information
|
||||
|
||||
For a local deployment, you should update the following fields.
|
||||
We assume that the CU will bind on `192.168.70.129` towards the core,
|
||||
`127.0.0.3` towards the DU, and the DU `127.0.0.4` towards the CU.
|
||||
|
||||
In the CU file:
|
||||
- Update the `gNBs.[0].amf_ip_address` and `gNBs.[0].NETWORK_INTERFACES`
|
||||
section towards the core (typically, OAI CN is configured to provide a docker
|
||||
bridge on `192.168.70.129` and the AMF is on `192.168.70.132`):
|
||||
- `gNBs.[0].amf_ip_address.[0].ipv4 192.168.70.132`
|
||||
- `gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NG_AMF 192.168.70.129`
|
||||
- `gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NGU 192.168.70.132`
|
||||
- Set `gNBs.[0].tr_s_preference` (transport south-bound) to `f1`
|
||||
- Update the `gNBs.[0].local_s_address` (CU-local south address) for the F1-C
|
||||
south-bound interface: `127.0.0.3`
|
||||
- Note: the `gNBs.[0].remote_s_address` (CU-remote/DU south address) is
|
||||
ignored, but we recommend to put `0.0.0.0` ("any")
|
||||
- Ports should match the ones in the DU config, but for simplicity and
|
||||
standards-conformity, simply set all to 2152:
|
||||
- `local_s_portc` in CU should match `remote_n_portc` in DU
|
||||
- `local_s_portd` in CU should match `remote_n_portd` in DU
|
||||
- `remote_s_portc` in CU should match `local_n_portc` in DU
|
||||
- `remote_s_portd` in CU should match `local_n_portd` in DU
|
||||
|
||||
In the DU file:
|
||||
- Set `MACRLCs.[0].tr_n_preference` to `f1`
|
||||
- Update `MACRLCs.[0].local_n_address` (local north-bound address of the DU) to
|
||||
`127.0.0.4`
|
||||
- Update `MACRLCs.[].remote_n_address` (remote north-bound address of the CU)
|
||||
to `127.0.0.3`
|
||||
|
||||
Note: all `local_*_if_name` parameters are ignored.
|
||||
|
||||
## Configuration of multiple DUs
|
||||
|
||||
Upon F1 Setup Request of a new DU, the CU cross-checks that
|
||||
|
||||
- no DUs have the same gNB-DU IDs, taken from `gNBs.[0].gNB_ID`, and
|
||||
- no cells have the same NR Cell ID, taken from `gNBs.[0].nr_cellid`, and
|
||||
- no cells have the same physical cell IDs, taken from `gNBs.[0].servingCellConfigCommon.[0].physCellId`.
|
||||
|
||||
If any of these are the same, the CU will reject the DU with an F1 Setup
|
||||
Failure. Thus, you should make sure that in the DU's configs, these parameters
|
||||
are set differently.
|
||||
|
||||
You have to of course make sure that the local interface of the DU
|
||||
(`MACRLCs.[0].local_n_address`) is different as well.
|
||||
|
||||
Assuming you use RFsim, you should make the RFsimulator server side (typically
|
||||
the gNB) bind on different hosts (`rfsimulator.serverport`).
|
||||
|
||||
# Code documentation
|
||||
|
||||
## Common multi-threading architecture
|
||||
|
||||
The CU and DU interfaces are based on ITTI threads (see `common/utils/ocp_itti/itti.md`)
|
||||
adopted by all OAI upper layers to run isolated threads dedicated to one feature.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Linux[configuration file] --> APP[gNB_app_task]
|
||||
Socks[Linux UDP] --> GTP[nr_gtpv1u_gNB_task]
|
||||
APP --> CU
|
||||
APP --> DU
|
||||
A[Linux SCTP] -->|sockets| SCTP(OAI itti thread TASK_SCTP)
|
||||
SCTP-->|TASK_NGAP| NG[ngap_gNB_task]
|
||||
NG-->|TASK_SCTP| SCTP
|
||||
SCTP-->|TASK_DU_F1| DU[F1AP_DU_task]
|
||||
SCTP-->|TASK_CU_F1| CU[F1AP_CU_task]
|
||||
CU-->|TASK_RRC_GNB| RRC
|
||||
RRC -->|non ITTI| PHY[OAI L1+L2]
|
||||
RRC -->|API calls to create tunnels| GTP
|
||||
PHY --> |user plane| GTP
|
||||
CU --> |TASK_GTPV1_U| GTP
|
||||
DU --> |TASK_GTPV1_U| GTP
|
||||
```
|
||||
|
||||
A "task" is a Linux thread running an infinite waiting loop on one ITTI queue.
|
||||
|
||||
The `app` task manages the initial configuration; the `sctp` task manages the
|
||||
SCTP Linux sockets.
|
||||
|
||||
The CU encoding/decoding runs in the task executing `F1AP_CU_task()`. It stores its private data context in a static variable.
|
||||
The DU encoding/decoding runs in the task executing `F1AP_DU_task()`. The design is similar to CU task.
|
||||
|
||||
All GTP-U tunnels are managed in a Linux Thread, that have partially ITTI design:
|
||||
|
||||
1. tunnel creation/deletion is by C API functions direct calls (a mutex protects it)
|
||||
2. outgoing packets are pushed in a ITTI queue to the gtp thread
|
||||
3. incoming packets are sent to the tunnel creator using a C callback (the callback function is given in tunnel creation order). The callback should not block
|
||||
|
||||
|
||||
## F1-C messages towards the CU
|
||||
|
||||
The CU thread starts when the CU starts. It opens listening socket on the
|
||||
configuration-specified IP/port by sending the appropriate message to
|
||||
`TASK_SCTP`. It will accept any incoming connection and forward any F1 message
|
||||
to RRC.
|
||||
|
||||
You can trace any message by looking up the handler
|
||||
`cu_task_handle_sctp_data_ind()`, which ultimately triggers a corresponding
|
||||
ITTI message sent to RRC. All ITTI messages arriving are dispatched in the ITTI
|
||||
message handling function in `rrc_gNB.c`. For your convenience, find below a
|
||||
table of same messages that might arrive from the DU and how they are
|
||||
forwarded.
|
||||
|
||||
After handling messages, the RRC uses a callback that determines if messages go
|
||||
directly to the MAC or are sent to the CU ITTI task (see
|
||||
[above](#high-level-f1-c-code-structure))
|
||||
|
||||
You might also want to consult TS 38.401 regarding the message exchange.
|
||||
|
||||
| Incoming F1 message | ITTI message to RRC | RRC handler | Comments |
|
||||
|---------------------|---------------------|-------------|----------|
|
||||
| F1 Setup Request | `F1AP_SETUP_REQ` | `rrc_gNB_process_f1_setup_req()` | will trigger either a response or failure |
|
||||
| Initial UL RRC Message Transfer | `F1AP_INITIAL_UL_RRC_MESSAGE` | `rrc_gNB_process_initial_ul_rrc_message()` | first message from UE, follows up with RRC Setup or Reestablishment |
|
||||
| UL RRC Message Transfer | `F1AP_UL_RRC_MESSAGE` | `rrc_gNB_decode_dcch()` | UL RRC messages contain DCCH |
|
||||
| UE Context Response | `F1AP_UE_CONTEXT_SETUP_RESP` | `rrc_CU_process_ue_context_setup_response()` | does not trigger a follow-up, as UE sends Security Response |
|
||||
| UE Context Modification Response | `F1AP_UE_CONTEXT_MODIFICATION_RESP` | `rrc_CU_process_ue_context_modification_response()` | triggers Reconfiguration if CellGroup in answer |
|
||||
| UE Context Modification Required | `F1AP_UE_CONTEXT_MODIFICATION_REQUIRED` | `rrc_CU_process_ue_modification_required()` | triggers Reconfiguration |
|
||||
| UE Context Release Request | `F1AP_UE_CONTEXT_RELEASE_REQ` | `rrc_CU_process_ue_context_release_request()` | RRC will trigger UE release |
|
||||
| UE Context Release Complete | `F1AP_UE_CONTEXT_RELEASE_COMPLETE` | `rrc_CU_process_ue_context_release_complete()` | frees UE Context, signals to NGAP |
|
||||
|
||||
## F1-C Messages towards the DU
|
||||
|
||||
The task "gNB app", after reading the configuration file, sends a message
|
||||
`F1AP_DU_REGISTER_REQ` to the DU task. This message contains network
|
||||
configuration for the establishment of the SCTP connection, as well as the F1
|
||||
Setup Request to be sent to the CU.
|
||||
|
||||
Using the network configuration, the DU task sets up an SCTP connection via the
|
||||
SCTP task. When it receives from the SCTP task the socket creation success,
|
||||
the DU task encodes and sends the F1 setup message to the CU.
|
||||
|
||||
Similarly as for the CU, you can trace any message by looking up the handler
|
||||
`du_task_handle_sctp_data_ind()`. Unlike in the CU, the decoders do NOT send an
|
||||
ITTI message, but directly call into the scheduler via a message handling
|
||||
function. This handler acquires the scheduler mutex and executes the
|
||||
corresponding message handling functionality. All handlers are in
|
||||
`mac_rrc_dl_handler.c`.
|
||||
|
||||
After handling messages, the MAC uses a callback that determines if messages
|
||||
are sent back to RRC via ITTI, or are sent to the DU ITTI task (see
|
||||
[above](#high-level-f1-c-code-structure))
|
||||
|
||||
You might also want to consult TS 38.401 regarding the message exchange.
|
||||
|
||||
| Incoming F1 message | MAC handler | Comments |
|
||||
|---------------------|-------------|----------|
|
||||
| F1 Setup Response | `f1_setup_response()` | the DU does not start the radio before receiving this message |
|
||||
| DL RRC Message Transfer | `dl_rrc_message_transfer()` | Processing timer started if reconfiguration is present[^footnote-reconfig] |
|
||||
| UE Context Setup Request | `ue_context_setup_request()` | |
|
||||
| UE Context Modification Request | `ue_context_modification_request()` | |
|
||||
| UE Context Modification Confirm | `ue_context_modification_confirm()` | |
|
||||
| UE Context Modification Refuse | `ue_context_modification_refuse()` | Will trigger release request |
|
||||
| UE Context Release Command | `ue_context_release_command()` | Starts timer for release if UE in sync |
|
||||
|
||||
[^footnote-reconfig]: The DU does not decode RRC messages, and does not know
|
||||
whether an RRC message is a reconfiguration. However, the spec mandates that
|
||||
a reconfiguration has to be triggered if the CU receives a CellGroupConfig,
|
||||
originating at the DU. See also flag `expect_reconfiguration`.
|
||||
|
||||
## F1-U messages
|
||||
|
||||
### General
|
||||
|
||||
In the DU in UL, RLC checks in `deliver_sdu()` if we are operating in split
|
||||
mode, and either (direct) calls `pdcp_data_ind` (DRB) or (f1ap) sends an
|
||||
`GTPV1U_TUNNEL_DATA_REQ` ITTI message to the GTP task.
|
||||
|
||||
In the CU in UL, assuming the tunnel is in place, GTP decapsulates the packet
|
||||
and calls the callback `cu_f1u_data_req()`, which calls `pdcp_data_ind()` in CU.
|
||||
|
||||
In the CU in DL, the PDCP function `deliver_pdu_drb_gnb()` either (direct) calls
|
||||
into the RLC via `enqueue_rlc_data_req()`, or (f1ap) sends a
|
||||
`GTPV1U_TUNNEL_DATA_REQ` ITTI message to the GTP task.
|
||||
|
||||
In the DU in DL, assuming the GTP-U tunnel exists, GTP decapsulates the packet
|
||||
and calls the reception call back `du_rlc_data_req()`, which calls
|
||||
`enqueue_rlc_data_req()` in turn.
|
||||
|
||||
## Tunnel Setup
|
||||
|
||||
In GTP-U, TS 29.281 specifies a optional header (NR RAN Container). This
|
||||
extension header may be transmitted in a G-PDU over the X2-U, Xn-U and F1-U user
|
||||
plane interfaces, but it is not mandatory.
|
||||
|
||||
Note that the GTP-U uses internal tables. Instead of exposing TEIDs, it uses the
|
||||
UE ID (RNTI, RRC UE ID) and Radio Bearer ID to map to a TEID for outgoing GTP-U
|
||||
packets. Upon receiving, it does the reverse and calls the callbacks. In the CU
|
||||
case, the DRB tunnel to DU and the tunnel on N3 have the same keys (RRC UE ID,
|
||||
RB ID), but they run in two different GTP-U instances. Each instance binds on
|
||||
diffrent sockets, which is the reason you cannot have the same interface for
|
||||
F1-U and N3/NG-U interfaces (this can be considered a design flaw).
|
||||
|
||||
In F1AP, for each "DRB to Be Setup Item IEs", we have a field TNL (transport
|
||||
network layer) to set a specific GTP tunnel (@IP, TEid). This is the same for
|
||||
each message related to DRBs.
|
||||
|
||||
So, For each F1AP containing DRB setup/modification/deletion, the related GTP-U
|
||||
tunnels will be modified one to one. The exception is the intialisation of new
|
||||
tunnel: in the call to tunnel creation, we need to send the remote TEID, but we
|
||||
don't know yet if we are the initial source. In this case, we issue a dummy
|
||||
(0xFFFF) remote TEID; when we receive the remote answer, we get the source teid,
|
||||
with which the GTP-U endpoint is updadet.
|
||||
|
||||
Reference in New Issue
Block a user