Generate CU-Plane Messages for O-RAN Fronthaul Test
This example shows how to generate fronthaul control and user (CU) plane messages for open radio access network (O-RAN) conformance tests using 5G Toolbox™. These O-RAN compliant messages are considered as split option 7.2x test vectors generated from an O-RAN distributed unit (O-DU). The example generates a packet capture (PCAP) file that contains these messages.
Introduction
This example shows how to build the O-RAN fronthaul CU-plane messages, as defined in TS O-RAN.WG4.CUS, which transmit an NR test model waveform, as defined in TS 38.141-1. These O-RAN compliant messages are considered as split option 7.2x test vectors generated from an O-DU. The example generates a PCAP file, which contains the messages. You can use the generated packets to test an O-RAN radio unit (O-RU) following the conformance test specifications in TS O-RAN.WG4.CONF. You can also analyze the generated PCAP file with third-party packet analysis tools. In this example, Wireshark is used to verify that the content of the CU-plane messages is as expected.
This example builds the CU-plane messages required to transmit the specified NR test model waveform. The example generates a single C-plane message per slot, using Section Type 1, and a single U-plane message per symbol. The U-plane messages encapsulate the IQ data using a single section per symbol. The following diagram shows the flow of the generated CU-plane messages.
Set Configuration Parameters
The data frame to transmit consists of a full band 5G NR test model waveform, as defined in TS 38.141-1. You can set the test model, the channel bandwidth, and the subcarrier spacing of the test waveform. This example supports FDD duplex mode only and does not apply any precoding or beamforming.
The generated PCAP file includes the Ethernet, eCPRI, and O-RAN protocols. In this section, you can configure parameters available in the three protocols:
O-RAN — Set the compression method and the IQ samples bit-width before and after compression.
eCPRI — Set the extended antenna-carrier identifier (eAxC ID) fields. All packets have the same eAxC ID because this example supports only a single stream.
Ethernet — Set the Ethernet VLAN tag, and the MAC source and destination addresses.
This example does not generate management plane (M-plane) messages. However, the example enables you to set these M-plane parameters: compression mode, byte order, and number of bits per field in eAxC ID.
% Select the NR test waveform parameters waveConfig.tm ="NR-FR1-TM1.1"; % Test model (must be full band) waveConfig.bw =
"100MHz"; % Channel bandwidth in MHz waveConfig.scs =
"30kHz"; % Subcarrier spacing in kHz % O-RAN configuration % Select the compression parameters oranConfig.method =
'BFP'; % Compression method oranConfig.IQWidth = 16; % IQ samples bit-width before compression oranConfig.cIQWidth = 9; % Compressed IQ samples bit-width (1 to 16) % eCPRI configuration % Select the eAxC ID fields eCPRIConfig.DUPortID = 0; % Distributed unit identifier eCPRIConfig.BandSectorID = 0; % Band and sector identifier eCPRIConfig.CCID = 0; % Component carrier identifier eCPRIConfig.RUPortID = 0; % Spatial stream identifier % Ethernet configuration % Select the Ethernet VLAN tag ethernetConfig.TPID =
0x8100; % Tag protocol identifier ethernetConfig.priority = 7; % Priority level (0 to 7) ethernetConfig.DEI =
0; % Drop eligible indicator ethernetConfig.VID = 1; % Unique VLAN identifier (0 to 4095) % Select the MAC source and destination addresses ethernetConfig.sourceAddress = ["56","3b","be","a9","92","4c"]; % MAC source address ethernetConfig.destAddress = ["da","14","de","b0","55","63"]; % MAC destination address % Select the M-plane parameters mPlaneConfig.compMode =
0; % Compression mode mPlaneConfig.byteOrder =
0; % Byte order mPlaneConfig.eAxCIDBits = [2 6 4 4]; % Number of bits per field in eAxC ID % Set the name of the PCAP file pcapFileName = 'CUMessages'; % PCAP file name
Generate U-Plane Data
Use the hNRReferenceWaveformGenerator
class to generate the complete 5G NR configuration of the frame that you selected in the previous section. The resource grid of the NR frame (split option 7.2x) is the data carried in the U-plane messages.
% Create waveform generator object waveConfig.dm = "FDD"; % FDD duplexing mode tmWaveGen = hNRReferenceWaveformGenerator(waveConfig.tm,waveConfig.bw, ... waveConfig.scs,waveConfig.dm); % Generate waveform and get resource grid of one frame of data [~,gridSet] = generateWaveform(tmWaveGen); grid = gridSet.ResourceGridBWP;
Compress U-Plane Data
Next, compress the generated resource by using the nrORANBlockCompress
function. Compression method options include block floating point (BFP), block scaling, and mu-law, as defined in TS O-RAN.WG4.CUS Annex A.1.1, A.2.1, and A.3.1, respectively. Before applying the compression, scale the IQ samples in the resource grid to the bit-width specified by oranConfig.IQWidth
.
% Scale the IQ samples in the resource grid using IQWidth peak = max(abs([real(grid(:)); imag(grid(:))])); scaleFactor = peak / (0.95*(2^(oranConfig.IQWidth-1)-1)); oranConfig.scaledGrid = round(grid/scaleFactor); % Apply compression to the scaled resource grid if selected if ~strcmp(oranConfig.method,'No compression') [oranConfig.cGrid,oranConfig.cParam] = nrORANBlockCompress(oranConfig.scaledGrid, ... oranConfig.method,oranConfig.cIQWidth,oranConfig.IQWidth); end
Extract CU-Plane Message Configuration
Use the getCUMessagesConfig
local function to get the configuration per CU-plane message:
Ethernet header
eCPRI header
eCPRI payload (O-RAN configuration)
% Get the number of symbols per slot and the number of slots per subframe waveConfig.symbolsPerSlot = gridSet.Info.SymbolsPerSlot; waveConfig.slotsPerSubframe = gridSet.Info.SlotsPerSubframe; % Obtain set of CU-plane messages [cMessagesConfig,uMessagesConfig] = getCUMessagesConfig(waveConfig,oranConfig, ... eCPRIConfig,ethernetConfig);
Generate CU-Plane Messages
The generateCUMessages
local function generates the CU-plane messages according to their configuration in cMessagesConfig
and uMessagesConfig
, respectively, and writes the messages to a PCAP file. The generated C-plane messages are Section Type 1, see TS O-RAN.WG4.CUS section 5.4.
% Generate CU-plane messages and write the packets to PCAP file
generateCUMessages(cMessagesConfig,uMessagesConfig,mPlaneConfig,pcapFileName);
Visualize Generated CU-Plane Messages
You can open the PCAP file containing the generated CU-plane messages in a packet analyzer. The packets decoded by Wireshark match the configuration selected. These figures show the analysis of two captured CU-plane messages in Wireshark.
First C-Plane Message
First U-Plane Message
References
3GPP TS 38.141-1. "NR; Base Station (BS) conformance testing Part 1: Conducted conformance testing." 3rd Generation Partnership Project; Technical Specification Group Radio Access Network.
TS O-RAN.WG4.CUS. "O-RAN Fronthaul Working Group - Control, User and Synchronization Plane Specification".
TS O-RAN.WG4.CONF. "O-RAN Fronthaul Working Group - Conformance Test Specification".
Wireshark: https://www.wireshark.org/. Accessed 13 July 2022.
Local Functions
function [cMessagesConfig,uMessagesConfig] = getCUMessagesConfig(waveConfig,oranConfig,eCPRIConfig,ethernetConfig) % Obtain CU-plane messages configuration. This function considers Section Type 1 C-plane messages. % Get the following information per PRB: % - PRBNumber: PRB number % - cParam: computational parameter specific to the compression method % - cIQWidth: compressed IQ samples bit-width (same as IQWidth if uncompressed) % - IQData: IQ samples K = size(oranConfig.scaledGrid,1); L = size(oranConfig.scaledGrid,2); if ~strcmp(oranConfig.method,'No compression') grid = oranConfig.cGrid; cParam = oranConfig.cParam; cIQWidth = oranConfig.cIQWidth; else grid = oranConfig.scaledGrid; cParam = NaN(K/12,L); cIQWidth = oranConfig.IQWidth; end PRBsInfo = struct; if length(cIQWidth) == 1 cIQWidth = repmat(cIQWidth,[K/12 L]); end for l = 1:L PRBNumber = 0; for k = 1:K/12 PRBsInfo(k,l).PRBNumber = PRBNumber; PRBsInfo(k,l).CompParam = [cParam(k,l) cIQWidth(k,l)]; PRBsInfo(k,l).IQData = grid((k-1)*12+1:k*12,l); PRBNumber = PRBNumber+1; end end % Get time configuration of first U-plane message uTimeInfo.DataDirection = 1; uTimeInfo.PayloadVersion = 1; uTimeInfo.FilterIndex = 0; uTimeInfo.FrameID = 0; uTimeInfo.SubframeID = 0; uTimeInfo.SlotID = 0; uTimeInfo.SymbolID = 0; % Indicate compression method according to TS O-RAN.WG4.CUS switch oranConfig.method case 'BFP' udCompMeth = 1; case 'blockScaling' udCompMeth = 2; case 'muLaw' udCompMeth = 3; otherwise % No compression udCompMeth = 0; end % Get section configuration of first U-plane message uSectionsInfo.SectionID = 0; uSectionsInfo.RB = 0; uSectionsInfo.SymInc = 0; uSectionsInfo.StartPRBu = 0; uSectionsInfo.NumPRBu = 0; % All PRBs in the specified SCS and carrier bandwidth uSectionsInfo.UdCompHdr = [cIQWidth(1),udCompMeth]; uSectionsInfo.Reserved = 0; uSectionsInfo.PRBs = PRBsInfo(:,1); % Set O-RAN configuration of first U-plane message uOran.TimeInfo = uTimeInfo; uOran.Sections = uSectionsInfo; % Generate eCPRI header fields ecpri.ProtocolRevision = 1; ecpri.Reserved = 0; ecpri.Concatenation = 0; ecpri.MessageType = 'IQData'; % Message type for U-plane message ecpri.eAxCID = [eCPRIConfig.DUPortID,eCPRIConfig.BandSectorID,eCPRIConfig.CCID, ... eCPRIConfig.RUPortID]; sequenceID = 0; EBit = 1; subSequenceID = 0; ecpri.SEQ_ID = [sequenceID,EBit,subSequenceID]; % Generate Ethernet header fields eth.DestinationAddress = ethernetConfig.destAddress; eth.SourceAddress = ethernetConfig.sourceAddress; etherType = 0xAEFE; % eCPRI uses Ethernet with the Ethertype 0xAEFE vlanTag = [ethernetConfig.TPID,ethernetConfig.priority,ethernetConfig.DEI, ... ethernetConfig.VID]; eth.Type = [vlanTag etherType]; % Combine all configurations (Ethernet header, eCPRI header, and O-RAN % information) of first U-plane message uMessagesConfig = struct; uMessagesConfig(1).eth = eth; uMessagesConfig(1).ecpri = ecpri; uMessagesConfig(1).oran = uOran; % Get configuration of remaining U-plane messages uPackets = size(PRBsInfo,2); % Number of U-plane messages per OFDM symbol symbolsPerSlot = waveConfig.symbolsPerSlot; slotsPerSubframe = waveConfig.slotsPerSubframe; for i = 1:uPackets-1 uOran.TimeInfo.SubframeID = floor(i/(symbolsPerSlot*slotsPerSubframe)); uOran.TimeInfo.SlotID = mod(floor(i/symbolsPerSlot),slotsPerSubframe); uOran.TimeInfo.SymbolID = mod(i,symbolsPerSlot); uOran.Sections.PRBs = PRBsInfo(:,i+1); ecpri.SEQ_ID(1,1) = ecpri.SEQ_ID(1,1)+1; ecpri.SEQ_ID(1,1) = mod(ecpri.SEQ_ID(1,1),256); uMessagesConfig(i+1).eth = eth; uMessagesConfig(i+1).ecpri = ecpri; uMessagesConfig(i+1).oran = uOran; end % Get time configuration of first C-plane message cTimeInfo.DataDirection = 1; cTimeInfo.PayloadVersion = 1; cTimeInfo.FilterIndex = 0; cTimeInfo.FrameID = 0; cTimeInfo.SubframeID = 0; cTimeInfo.SlotID = 0; cTimeInfo.SymbolID = 0; % Start symbol ID % Get section type and compression configurations of first C-plane message typeCompInfo.NumberOfSections = 1; typeCompInfo.SectionType = 1; typeCompInfo.UdCompHdr = 0; % This parameter will be ignored in DL typeCompInfo.Reserved = 0; % Generate section configuration of first C-plane message cSectionsInfo.SectionID = 0; cSectionsInfo.RB = 0; cSectionsInfo.SymInc = 0; cSectionsInfo.StartPRBc = 0; cSectionsInfo.NumPRBc = 0; % All PRBs in the specified SCS and carrier bandwidth cSectionsInfo.REMAsk = ones(1,12); cSectionsInfo.NumSymbol = 14; cSectionsInfo.Ef = 0; % No section extensions cSectionsInfo.BeamID = 0; % No beamforming % Set O-RAN information of first C-plane message cOran.TimeInfo = cTimeInfo; cOran.SectionInfo = typeCompInfo; cOran.Sections = cSectionsInfo; % Combine all configurations (Ethernet header, eCPRI header, and O-RAN % information) of first C-plane message cMessagesConfig = struct; cMessagesConfig(1).eth = eth; ecpri.MessageType = 'RealTimeControlData'; % Message type for C-plane message ecpri.SEQ_ID(1,1) = 0; cMessagesConfig(1).ecpri = ecpri; cMessagesConfig(1).oran = cOran; % Get configuration of remaining C-plane messages NSubframes = 10; cPackets = slotsPerSubframe*NSubframes; for i = 1:cPackets-1 cOran.TimeInfo.SubframeID = floor(i/slotsPerSubframe); cOran.TimeInfo.SlotID = mod(i,slotsPerSubframe); ecpri.SEQ_ID(1,1) = ecpri.SEQ_ID(1,1)+1; ecpri.SEQ_ID(1,1) = mod(ecpri.SEQ_ID(1,1),256); cMessagesConfig(i+1).eth = eth; cMessagesConfig(i+1).ecpri = ecpri; cMessagesConfig(i+1).oran = cOran; end end function generateCUMessages(cMessagesConfig,uMessagesConfig,mPlaneConfig,pcapFileName) % Generate CU-plane messages and write the packets to PCAP file % Create a PCAP file writer object and write a global header to the PCAP file pcapObj = pcapWriter(FileName = pcapFileName); linkType = 1; % Link type for Ethernet protocol writeGlobalHeader(pcapObj, linkType); timeStamp = 0; % Packet arrival time in microseconds timeDelay = 40; % Time delay between packets in microseconds % Encode Ethernet header of CU-plane messages ethHeader = hORANProtocolEncoder.ethernetHeader(cMessagesConfig(1).eth); % Calculate number of U-plane packets per slot NuPacketsPerSlot = size(uMessagesConfig,2)/size(cMessagesConfig,2); % Generate CU-plane packets and write the packets to the PCAP file for i = 1:size(cMessagesConfig,2) % Encode eCPRI payload of C-plane message cECPRIPayload = hORANProtocolEncoder.eCPRIPayloadControl(cMessagesConfig(i).oran); % Encode eCPRI header of C-plane message cECPRIHeader = hORANProtocolEncoder.eCPRIHeader(cMessagesConfig(i).ecpri, ... length(cECPRIPayload),mPlaneConfig.eAxCIDBits); % Generate C-plane packet cPacket = [ethHeader; cECPRIHeader; cECPRIPayload]; % Write C-plane packet to PCAP file write(pcapObj, cPacket, timeStamp); timeStamp = timeStamp+timeDelay*7; for j = 1:NuPacketsPerSlot % Encode eCPRI payload of U-plane message uECPRIPayload = hORANProtocolEncoder.eCPRIPayloadUser(uMessagesConfig(j+NuPacketsPerSlot*(i-1)).oran, ... mPlaneConfig.compMode,mPlaneConfig.byteOrder); % Encode eCPRI header of U-plane message uECPRIHeader = hORANProtocolEncoder.eCPRIHeader(uMessagesConfig(j+NuPacketsPerSlot*(i-1)).ecpri, ... length(uECPRIPayload),mPlaneConfig.eAxCIDBits); % Generate U-plane packet uPacket = [ethHeader; uECPRIHeader; uECPRIPayload]; % Write U-plane packet to PCAP file write(pcapObj, uPacket, timeStamp); timeStamp = timeStamp+timeDelay; end end end