255 lines
12 KiB
Markdown
255 lines
12 KiB
Markdown
<table style="border-collapse: collapse; border: none;">
|
|
<tr style="border-collapse: collapse; border: none;">
|
|
<td style="border-collapse: collapse; border: none;">
|
|
<a href="http://www.openairinterface.org/">
|
|
<img src="./images/oai_final_logo.png" alt="" border=3 height=50 width=150>
|
|
</img>
|
|
</a>
|
|
</td>
|
|
<td style="border-collapse: collapse; border: none; vertical-align: center;">
|
|
<b><font size = "5">F1 split design</font></b>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
# 1. Introduction
|
|
|
|
We use OpenAirInterface source code, and it's regular deployment scheme.
|
|
|
|
F1 specification is in 3GPP documents: TS 38.470 header document and all documents listed in chapter 2 References of TS 38.470.
|
|
|
|
This document explains how the source code works.
|
|
|
|
Offered features and deployment instructions are described in:
|
|
https://gitlab.eurecom.fr/oai/openairinterface5g/-/wikis/f1-interface
|
|
|
|
# 2. Common multi-threading architecture #
|
|
|
|
The CU and DU interfaces are based on ITTI threads (see oai/common/utils/ocp_itti/itti.md)
|
|
|
|
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.
|
|
|
|
```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
|
|
|
|
app task manages the initial configuration
|
|
|
|
sctp task mamanges the SCTP Linux sockets
|
|
|
|
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.
|
|
|
|
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
|
|
|
|
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
|
|
callbacks in `mac_rrc_dl.h`, whose implementation is defined in files
|
|
`mac_rrc_dl_direct.c` (monolithic) and `mac_rrc_dl_f1ap.c` (for F1AP). In the
|
|
monolithic case, the RRC calls directly into the message handler on the DU side
|
|
(`mac_rrc_dl_handler.c`). In the F1 case, an ITTI message is sent to the CU
|
|
task, sending an ASN.1-encoded F1AP message. The DU side's DU task decodes the
|
|
message, and then calls the corresponding handler in `mac_rrc_dl_handler.c`.
|
|
Thus, the message flow is the same in both F1 and monolithic cases, with the
|
|
difference that F1AP encodes the messages using ASN.1 and sends over a socket.
|
|
|
|
In UL, the callbacks defined in `mac_rrc_ul.h` are implemented by
|
|
`mac_rrc_ul_direct.c` (monolithic) and `mac_rrc_ul_f1ap.c` (F1). In the direct
|
|
case, an ITTI message is directly sent to the RRC task (hence, there is no
|
|
dedicated handler). In F1, the DU task receives the ITTI message, encodes using
|
|
ASN.1, and sends it over a network socket. The CU task decodes, and sends the
|
|
same ITTI message to the RRC task as done directly in the monolithic case.
|
|
|
|
```
|
|
+-------------+
|
|
| |
|
|
| CU/RRC |
|
|
| |
|
|
+-------------+
|
|
| ^
|
|
Callback def: mac_rrc_dl.h | | No handler needed:
|
|
F1 impl: mac_rrc_dl_f1ap.c | | RRC has ITTI
|
|
Monolithic: mac_rrc_dl_direct.c | |
|
|
| |
|
|
DL | | UL
|
|
| |
|
|
| | Callback def: mac_rrc_ul.h
|
|
Message handler: | | F1 impl: mac_rrc_ul_f1ap.c
|
|
mac_rrc_dl_handler.c | | Monolithic: mac_rrc_ul_direct.c
|
|
v |
|
|
+-------------+
|
|
| |
|
|
| DU/MAC |
|
|
| |
|
|
+-------------+
|
|
```
|