srsRAN Uplink User Plane Analysis Part 2: gNB DU/CU

Introduction

Starting off from where the previous article left off, the UE has transmitted User Plane data over the air interface destined for the gNB. The UE has sent two PUSCH transmissions, one with a TBS of 544 Bytes and the subsequent transmission with a TBS of 1089 Bytes. The reason we are analyzing both transmissions here is because the data was segmented at the RLC layer of UE. The data will arrive at the gNB-DU, then transfer to the gNB-CU-UP before being sent to the UPF in 5GC.

gNB-DU

The two PUSCH transmissions are received at the scheduled TTI at the Physical Layer of the gNB DU.

[PHY ] [ 662.9] PUSCH: rnti=0x4601 h_id=0 prb=[8, 14) symb=[0, 14) mod=64QAM rv=0 tbs=544 crc=OK
[PHY ] [ 663.9] PUSCH: rnti=0x4601 h_id=0 prb=[8, 20) symb=[0, 14) mod=64QAM rv=0 tbs=1089 crc=OK

The data is transferred from the physical layer to the MAC layer where the data is extracted into subPDUs, where some data will stay at the MAC layer and other data will continue to be transferred to the upper layers. Transmission 1 contains

  • LCID 4: 70 bytes
  • LCID 4: 70 bytes
  • LCID 4: 392 Bytes
  • Short BSR
  • Power Headroom

Tranmission 2 contains

  • LCID 4: 847 Bytes
  • Short BSR
  • Power Headroom
  • Padding: 233 Bytes

Only the LCID 4 subPDUs will be transferred to the RLC layer. I will refer to the data as Data 1, Data 2, Data 3, and Data 4 in respect to the order the data is sent from the MAC layer to the RLC layer.

## TX 1
[MAC ] [ 663.4] UL rnti=0x4601 ue=0 subPDUs: [lcid=4: len=70, lcid=4: len=70, lcid=4: len=392, SBSR: lcg=2 bs=15, SE_PHR: ph=[21..22)dB p_cmax=[20..21)dBm]
## Data 1
[MAC ] [ 663.4] UL rnti=0x4601 ue=0 lcid=4 UL-DCCH: Forwarding SDU of 70 bytes
## Data 2
[MAC ] [ 663.4] UL rnti=0x4601 ue=0 lcid=4 UL-DCCH: Forwarding SDU of 70 bytes
## Data 3
[MAC ] [ 663.4] UL rnti=0x4601 ue=0 lcid=4 UL-DCCH: Forwarding SDU of 392 bytes
## TX 2
[MAC ] [ 664.4] UL rnti=0x4601 ue=0 subPDUs: [lcid=4: len=847, SBSR: lcg=0 bs=0, SE_PHR: ph=[18..19)dB p_cmax=[20..21)dBm, PAD: len=233]
## Data 4
[MAC ] [ 664.4] UL rnti=0x4601 ue=0 lcid=4 UL-DCCH: Forwarding SDU of 847 bytes

The RLC layer receives each PDU, where each PDU becomes an SDU once the RLC header is processed and removed. The relevant RLC header information is the segment indication (SI) and Sequence Number (SN). Data 1 and Data 2 are complete, and can be transferred to the PDCP layer. Since this is a DU/CU split configuration, the data will need to be sent over the F1-U interface to the gNB-CU-UP that contains the PDCP and SDAP layers.

Data 3 has a segment indication of first, meaning it is not the complete data packet and it is the first segment of data, so the RLC layer should subsequently receive a PDU that has a segment indication of “last” or “neither first or last” to indicate the remainder of the data for the sequence number.

Data 4 has a segment indication of “last” and has the same sequence number as the Data 3 (SN: 2) and also includes the segment offset of 389 bytes, meaning that this data starts 389 bytes offset from the Data 3 segment. Now that the gNB-DU RLC entity has the complete data packet for SN:2, it can re-assemble the data as a 1231 byte SDU.

## Data 1
[RLC ] du=0 ue=0 DRB1 UL: RX PDU. pdu_len=70 dc=data p=0 si=full sn=0
[RLC ] du=0 ue=0 DRB1 UL: RX SDU. payload_len=67 dc=data p=0 si=full sn=0
[RLC ] du=0 ue=0 DRB1 UL: Adding sn=0 to window.
[RLC ] du=0 ue=0 DRB1 UL: RX entity state. rx_next=0 rx_next_status_trigger=0 rx_highest_status=0 rx_next_highest=0
[RLC ] du=0 ue=0 DRB1 UL: Updated rx_next_highest=1.
[RLC ] du=0 ue=0 DRB1 UL: RX SDU. sn=0 sdu_len=67
## Data 2
[RLC ] du=0 ue=0 DRB1 UL: RX PDU. pdu_len=70 dc=data p=0 si=full sn=1
[RLC ] du=0 ue=0 DRB1 UL: RX SDU. payload_len=67 dc=data p=0 si=full sn=1
[RLC ] du=0 ue=0 DRB1 UL: Adding sn=1 to window.
[RLC ] du=0 ue=0 DRB1 UL: RX entity state. rx_next=1 rx_next_status_trigger=0 rx_highest_status=1 rx_next_highest=1
[RLC ] du=0 ue=0 DRB1 UL: Updated rx_next_highest=2.
[RLC ] du=0 ue=0 DRB1 UL: RX SDU. sn=1 sdu_len=67
## Data 3
[RLC ] du=0 ue=0 DRB1 UL: RX PDU. pdu_len=392 dc=data p=0 si=first sn=2
[RLC ] du=0 ue=0 DRB1 UL: RX SDU segment. payload_len=389 dc=data p=0 si=first sn=2
[RLC ] du=0 ue=0 DRB1 UL: Adding sn=2 to window.
[RLC ] du=0 ue=0 DRB1 UL: RX entity state. rx_next=2 rx_next_status_trigger=0 rx_highest_status=2 rx_next_highest=2
[RLC ] du=0 ue=0 DRB1 UL: Updated rx_next_highest=3.
[RLC ] du=0 ue=0 DRB1 UL: Post-processing for AMD PDU: status_changed=true status_requested=false
[RLC ] du=0 ue=0 DRB1 UL: Generating status PDU. rx_next=2 rx_highest_status=2 stop_sn=2
[RLC ] du=0 ue=0 DRB1 UL: Refreshed status_report. ack_sn=2 n_nack=0
## Data 4
[RLC ] du=0 ue=0 DRB1 UL: RX PDU. pdu_len=847 dc=data p=1 si=last sn=2 so=389
[RLC ] du=0 ue=0 DRB1 UL: Status report requested via polling bit.
[RLC ] du=0 ue=0 DRB1 UL: RX SDU segment. payload_len=842 dc=data p=1 si=last sn=2 so=389
[RLC ] du=0 ue=0 DRB1 UL: RX entity state. rx_next=2 rx_next_status_trigger=0 rx_highest_status=2 rx_next_highest=3
[RLC ] du=0 ue=0 DRB1 UL: Chaining segment. sn=2 so=0 len=389
[RLC ] du=0 ue=0 DRB1 UL: Chaining segment. sn=2 so=389 len=842
[RLC ] du=0 ue=0 DRB1 UL: Assembled SDU from segments. sn=2 sdu_len=1231
[RLC ] du=0 ue=0 DRB1 UL: RX SDU. sn=2 sdu_len=1231

Data 3 and Data 4 will now be referred to as Data 3 since they have been combined. Next, the data is sent over the DU F1-U interface to the gNB-CU. The RLC layer updates that it is waiting to receive rx_highest_status as 3, since the last data packet processed indicated “rx_highest_status=2 rx_next_highest=3“. This process aids with the RLC entity reception buffer, since more data is expected to be received from the UE. The last packet that the RLC entity processed also contained a polling bit set to 1 (p=1) which triggers a Status Report to provide positive acknowledgement of RLC SDUs and provides the rx_next information.The Status Report is sent from the receiving RLC entity to the transmitting RLC entity. (TS 38.221: 5.3.3.3)

[RLC ] du=0 ue=0 DRB1 UL: Updated rx_highest_status=3.
[RLC ] du=0 ue=0 DRB1 UL: Removing sn=2 from window
[RLC ] du=0 ue=0 DRB1 UL: Updated rx_next=3.
[RLC ] du=0 ue=0 DRB1 UL: Post-processing for AMD PDU: status_changed=true status_requested=true
[RLC ] du=0 ue=0 DRB1 UL: Generating status PDU. rx_next=3 rx_highest_status=3 stop_sn=3
[RLC ] du=0 ue=0 DRB1 UL: Refreshed status_report. ack_sn=3 n_nack=0
[RLC ] du=0 ue=0 DRB1 UL: Notifying TX that status report has changed.
[RLC ] du=0 ue=0 DRB1 DL: Triggering buffer state update to lower layer
[RLC ] du=0 ue=0 DRB1 DL: Sending buffer state update to lower layer. bs=3

Looking at the du_rlc.pcap, observe the initial four data packets, followed by the “RLC-NR [CONTROL]” packet, which contains the Status Report.

RLC Status Report

gNB-DU F1-U

The gNB DU 127.0.10.2 sends the data using the F1-U GTP-U protocol, where the Tunnel Endpoint Identity (TEID) identifies the CU when transmitting towards the CU. The addition of the GTP-U and UDP headers changes the packet size from 67 to 75 bytes, and 1231 to 1239 bytes respectively.

## Data 1
[DU-F1-U ] ue=0 DRB1 addr=127.0.10.2 dl-teid=0x000001: F1-U bearer received SDU with size=67
[DU-F1-U ] ue=0 DRB1 addr=127.0.10.2 dl-teid=0x000001: Adding desired buffer size for DRB. bs=6172672
[GTPU ] ue=0 TX teid=0x000001: TX PDU. pdu_len=75 teid=0x000001
[UDP-GW ] Sent PDU of 75 bytes
## Data 2
[DU-F1-U ] ue=0 DRB1 addr=127.0.10.2 dl-teid=0x000001: F1-U bearer received SDU with size=67
[DU-F1-U ] ue=0 DRB1 addr=127.0.10.2 dl-teid=0x000001: Adding desired buffer size for DRB. bs=6172672
[GTPU ] ue=0 TX teid=0x000001: TX PDU. pdu_len=75 teid=0x000001
[UDP-GW ] Sent PDU of 75 bytes
## Data 3
[DU-F1-U ] ue=0 DRB1 addr=127.0.10.2 dl-teid=0x000001: F1-U bearer received SDU with size=1231
[DU-F1-U ] ue=0 DRB1 addr=127.0.10.2 dl-teid=0x000001: Adding desired buffer size for DRB. bs=6172672
[GTPU ] ue=0 TX teid=0x000001: TX PDU. pdu_len=1239 teid=0x000001
[UDP-GW ] Sent PDU of 1239 bytes

The du_f1u.pcap, doesn’t provide a lot of useful information for Uplink data, though if you happen to run a tdpdump on the gNB-DU machine, then you can get a little more data.

du_f1u.pcap

To get the most out of the tcpdump, you should configure the GTP protocol in Wireshark appropriately. See my configuration below, where I dissect T-PDUs as “PDCP-NR” and configure the GTP PDCP-NR Keys.

The details of the TCP and QUIC packets show the original UE generated data encapsulated by GTP-U and UDP where the gNB DU (127.0.10.2) sends the T-PDUs on UDP GTP-U Port 2152 to the gNB-CU (127.0.0.88) using TEID: 1

gNB CU

The gNB CU receives the data on the gNB CU F1-U interface using GTP-U, the GTP-U and UDP headers are removed and the data is back to it’s original size, where it is passed to the PDCP layer.

## Data 1
[UDP-GW ] Received 75 bytes on UDP socket. Pool occupancy 0.03% 75 bytes
[GTPU ] Forwarding PDU. pdu_len=75 teid=0x000001
[GTPU ] ue=0 RX teid=0x000001: RX PDU. pdu_len=75
[GTPU ] ue=0 RX teid=0x000001: RX DL data delivery status. t_pdu_len=67
[CU-F1-U ] ue=0 DRB1 ul-teid=0x000001: F1-U bearer received PDU
[CU-F1-U ] ue=0 DRB1 ul-teid=0x000001: Delivering T-PDU of size=67
## Data 2
[UDP-GW ] Received 75 bytes on UDP socket. Pool occupancy 0.03% 75 bytes
[GTPU ] Forwarding PDU. pdu_len=75 teid=0x000001
[GTPU ] ue=0 RX teid=0x000001: RX PDU. pdu_len=75
[GTPU ] ue=0 RX teid=0x000001: RX DL data delivery status. t_pdu_len=67
[CU-F1-U ] ue=0 DRB1 ul-teid=0x000001: F1-U bearer received PDU
[CU-F1-U ] ue=0 DRB1 ul-teid=0x000001: Delivering T-PDU of size=67
## Data 3
[UDP-GW ] Received 1239 bytes on UDP socket. Pool occupancy 0.03%
[GTPU ] Forwarding PDU. pdu_len=1239 teid=0x000001
[GTPU ] ue=0 RX teid=0x000001: RX PDU. pdu_len=1239
[GTPU ] ue=0 RX teid=0x000001: RX DL data delivery status. t_pdu_len=1231
[CU-F1-U ] ue=0 DRB1 ul-teid=0x000001: F1-U bearer received PDU
[CU-F1-U ] ue=0 DRB1 ul-teid=0x000001: Delivering T-PDU of size=1231

The PDCP layer receives and processes the data, to include security checking (Deciphering and Integrity checking). Packet re-ordering will occur at the PDCP layer if packets are received out of order. The PDCP header is removed, and the data is passed to the SDAP layer where the configured DRB to QFI mapping is confirmed. No SDAP header was added to the data at the UE, so there is no header to be removed.

## Data 1
[PDCP ] ue=0 DRB1 UL: RX PDU. pdu_len=67
[PDCP ] ue=0 DRB1 UL: RX entity state. rx_next=0 rx_deliv=0 rx_reord=0
[PDCP ] ue=0 DRB1 UL: RX PDU. type=data pdu_len=67 sn=0 count=0
## Data 2
[PDCP ] ue=0 DRB1 UL: RX PDU. pdu_len=67
[PDCP ] ue=0 DRB1 UL: RX entity state. rx_next=0 rx_deliv=0 rx_reord=0
[PDCP ] ue=0 DRB1 UL: RX PDU. type=data pdu_len=67 sn=1 count=1
## Data 1 & 2
[PDCP ] ue=0 DRB1 UL: Using sec_engine with worker_idx=0. count=0 pdu_len=67
[PDCP ] ue=0 DRB1 UL: Using sec_engine with worker_idx=2. count=1 pdu_len=67
[PDCP ] ue=0 DRB1 UL: Security passed. count=0
[PDCP ] ue=0 DRB1 UL: Security passed. count=1
## Data 1
[PDCP ] ue=0 DRB1 UL: Adding sn=0 to window.
[PDCP ] ue=0 DRB1 UL: RX SDU. count=0
[SDAP ] ue=0 psi=1 QFI=1 DRB1 UL: RX SDU. QFI=1 sdu_len=64
[PDCP ] ue=0 DRB1 UL: Removing sn=0 from window
[PDCP ] ue=0 DRB1 UL: RX entity state. rx_next=1 rx_deliv=1 rx_reord=0
## Data 2
[PDCP ] ue=0 DRB1 UL: Adding sn=1 to window.
[PDCP ] ue=0 DRB1 UL: RX SDU. count=1
[SDAP ] ue=0 psi=1 QFI=1 DRB1 UL: RX SDU. QFI=1 sdu_len=64
[PDCP ] ue=0 DRB1 UL: Removing sn=1 from window
[PDCP ] ue=0 DRB1 UL: RX entity state. rx_next=2 rx_deliv=2 rx_reord=0
## Data 3
[PDCP ] ue=0 DRB1 UL: RX PDU. pdu_len=1231
[PDCP ] ue=0 DRB1 UL: RX entity state. rx_next=2 rx_deliv=2 rx_reord=0
[PDCP ] ue=0 DRB1 UL: RX PDU. type=data pdu_len=1231 sn=2 count=2
[PDCP ] ue=0 DRB1 UL: Using sec_engine with worker_idx=0. count=2 pdu_len=1231
[PDCP ] ue=0 DRB1 UL: Security passed. count=2
[PDCP ] ue=0 DRB1 UL: Adding sn=2 to window.
[PDCP ] ue=0 DRB1 UL: RX SDU. count=2
[SDAP ] ue=0 psi=1 QFI=1 DRB1 UL: RX SDU. QFI=1 sdu_len=1228

The gNB CU now transfers the data across the NG-U/N3 interface to the UPF using GTP-U. The biggest difference here is that the GTP-U TEID for the NG-U interface is used (teid=0x000814) TEID: 2068. The gNB CU also uses a different IP address that is assigned to this interface, 127.0.0.87 and transmits to the UPF destination IP address of 127.0.0.7

## Data 1
[GTPU ] ue=0 UL teid=0x000814: TX PDU. pdu_len=80 teid=0x000814 qfi=QFI=1
[UDP-GW ] Sent PDU of 80 bytes
## Data 2
[GTPU ] ue=0 UL teid=0x000814: TX PDU. pdu_len=80 teid=0x000814 qfi=QFI=1
[UDP-GW ] Sent PDU of 80 bytes
## Data 3
[GTPU ] ue=0 UL teid=0x000814: TX PDU. pdu_len=1244 teid=0x000814 qfi=QFI=1
[UDP-GW ] Sent PDU of 1244 bytes

Conclusion

The data is now destined for the UPF, where it will be processed for transmission to the application server. Part 3 of this series of uplink user plane data will cover the aspects of the UPF and application server, as well as the downlink data to be sent back to the UE.

Leave a Reply

Discover more from

Subscribe now to keep reading and get access to the full archive.

Continue reading