feat(nfapi): OAI nFAPI Delay Management implementation#242
Conversation
|
|
CI Build: #529 | Not performing CI due to the absence of one of the following mandatory labels:
|
There was a problem hiding this comment.
Pull request overview
This PR adds OAI nFAPI Delay Management for NR, including a VNF autonomous timing thread and updated PNF/VNF timing/jitter reporting, and also improves stability around PRACH handling and thread naming.
Changes:
- Implement VNF-side autonomous timing thread and EWMA-based slot-ahead delay controller driven by
TIMING_INFO. - Add PNF-side RFC3550-style jitter calculation and richer timing window checks; extend NR timing info fields (including renames for TX_DATA timing/jitter fields).
- Improve PRACH segmented packet handling in the O-RAN FHI path and relax hard asserts on queue-length conditions during delay situations.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| radio/fhi_72/oaioran.c | Adds PRACH segmentation support during PRACH read/decompression and relaxes strict asserts on delay conditions. |
| nfapi/open-nFAPI/vnf/src/vnf_p7.c | Adds NR timing extraction, EWMA delay-management controller, and wrap-safe time computations; refactors UL node sync handling. |
| nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c | Adjusts socket IP_TOS and initializes new timing/mutex fields for P7 connection nodes. |
| nfapi/open-nFAPI/vnf/src/vnf_interface.c | Uses user-configured timing parameters instead of hardcoded defaults during PHY allocation. |
| nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h | Widens timing_window type and adds timing config fields to VNF config. |
| nfapi/open-nFAPI/vnf/inc/vnf_p7.h | Introduces delay-management constants/state, mutex/condvar fields, and timing stats types. |
| nfapi/open-nFAPI/pnf/src/pnf_p7.c | Implements RFC3550 jitter tracking, wrap-safe time diffs, timing-window enforcement, and periodic/aperiodic timing-info send logic changes. |
| nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c | Initializes PNF config defaults for timing-info sending and improves cleanup of allocated buffers. |
| nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h | Adds per-message receive timestamps into the PNF slot buffer for timing calculations. |
| nfapi/open-nFAPI/pnf/inc/pnf_p7.h | Adds jitter state, timing trigger fields, and buffer sizing constants for PNF P7 processing. |
| nfapi/open-nFAPI/nfapi/src/nfapi_nr_p7.c | Updates packing/unpacking for renamed NR timing-info TX_DATA fields. |
| nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h | Renames NR timing-info TX_DATA fields to match updated pack/unpack and usage. |
| nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h | Widens NR timing_window TLV from uint8 to uint16. |
| nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c | Packs/unpacks widened timing-window TLV and adds TLVs for per-message timing offsets. |
| nfapi/oai_integration/socket/socket_vnf.c | Sets IP_TOS for VNF socket to prioritize timing-sensitive traffic. |
| nfapi/oai_integration/socket/socket_pnf.c | Allocates RX/reassembly buffers and sets IP_TOS for PNF socket; adjusts slot handling behavior. |
| nfapi/oai_integration/nfapi_vnf.h | Widens timing window types and adds timing offset configuration fields. |
| nfapi/oai_integration/nfapi_vnf.c | Adds autonomous VNF timing thread, timing-info configuration wiring, offset TLV wiring, and adjusts message ordering. |
| nfapi/oai_integration/nfapi_pnf.c | Wires timing offsets and timing-info configuration from VNF into PNF P7 behavior; gates slot indications under WLS. |
| common/utils/system.c | Avoids aborting on pthread_setname_np() failure; logs error instead. |
| int num_total_prbs = 0; | ||
| for (int i = 0; i < nRxPkt; i++) { | ||
| num_total_prbs += p_rx_packet_ctl->nRBSize[i]; | ||
| } | ||
| int16_t local_dst[num_total_prbs * 2 * N_SC_PER_PRB] __attribute__((aligned(64))); | ||
| memset(local_dst, 0, sizeof(local_dst)); | ||
|
|
||
| for (int pkt_idx = 0; pkt_idx < nRxPkt; pkt_idx++) { | ||
| src = (int16_t *)p_rx_packet_ctl->pData[pkt_idx]; | ||
| if (src == NULL) { | ||
| LOG_E(HW, "read_prach %d.%d.%d saa = %d: src[%d] = NULL!!\n", *frame, *slot, sym_idx, aa, pkt_idx); | ||
| continue; | ||
| } | ||
| int num_prbu_local = p_rx_packet_ctl->nRBSize[pkt_idx]; | ||
| int start_prbu = p_rx_packet_ctl->nRBStart[pkt_idx]; | ||
| int16_t *decom_dst = local_dst + (start_prbu - p_rx_packet_ctl->nRBStart[0]) * N_SC_PER_PRB * 2; | ||
|
|
| uint64_t pnf_timehr_to_us(pnf_p7_t* pnf_p7, uint32_t time_hr) | ||
| { | ||
| uint32_t sec = TIMEHR_SEC(time_hr); | ||
| uint32_t usec = TIMEHR_USEC(time_hr); | ||
| // Convert to 64-bit microseconds (relative, will wrap at 4096 seconds) | ||
| return (uint64_t)sec * 1000000ULL + (uint64_t)usec; | ||
| } |
| /* Function Declaration */ | ||
| // Extract timing info points from a timing_info message | ||
| // Returns the number of valid stats extracted (0-8) | ||
| int vnf_nr_extract_timing_info(const nfapi_nr_timing_info_t *ind, | ||
| nfapi_vnf_p7_connection_info_t *p7_info, | ||
| vnf_timing_stats_t *out_stats); |
| static int32_t ceil_div_pos_i32(int32_t num, int32_t den) | ||
| { | ||
| if (den <= 0) | ||
| return 0; | ||
|
|
||
| if (num <= 0) | ||
| return 0; | ||
|
|
||
| return (num + den - 1) / den; | ||
| } | ||
|
|
||
| static int32_t abs_i32(int32_t v) | ||
| { | ||
| return v < 0 ? -v : v; | ||
| } | ||
| static inline int32_t p7_max_i32(int32_t a, int32_t b) | ||
| { | ||
| return a > b ? a : b; | ||
| } |
| static inline int p7_ewma_effectively_zero_i32( | ||
| int32_t value, | ||
| int32_t denom) | ||
| { |
| pthread_mutex_lock(&p7_con->mutex); | ||
| p7_con->timing_info_accum_count = 0; | ||
| p7_con->timing_info_accum_worst_late = INT32_MIN; | ||
| pthread_mutex_unlock(&p7_con->mutex); | ||
|
|
||
| vnf_nr_delay_management(p7_con, &aggregated_stats); |
| p7_info->sync_slot_counter++; | ||
| } | ||
|
|
||
| int target_ind_dec = (sfnslot_dec + p7_info->slot_ahead) % max_sfnslotdec; |
| nfapi_vnf_p7_connection_info_t *p7_info = NULL; | ||
|
|
||
| while (1) { | ||
| if (nr_start_resp_received) { |
| int nr_start_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_start_response_scf_t *resp) { | ||
| UNUSED(config); | ||
| NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Received NFAPI_START_RESP idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); | ||
| nr_start_resp_received = 1; |
8fc8c91 to
44a7d01
Compare
|
CI Build: #530 | Not performing CI due to the absence of one of the following mandatory labels:
|
| AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMapPrach == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id); | ||
| for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) { | ||
| AssertFatal(pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt <= 1, "PRACH segmentation is not supported\n"); | ||
| if (pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt > 1) { |
There was a problem hiding this comment.
please open a separate PR for all xran-related changes. That just does not belong together with nFAPI related changes, the set of reviewers is different, and needs separate attention
Make thread-name assignment failures fatal in threadCreate() so a misconfigured RT thread is caught immediately during bring-up. Dev hardening, not required upstream. Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
44a7d01 to
d60ebf6
Compare
29b1323 to
54e3c17
Compare
| int iptos_value = 0; | ||
| int iptos_value = 184; |
There was a problem hiding this comment.
Where does this value of 184 come from?
If it's supposed to be 'IPTOS_DSCP_EF', include <netinet/ip.h> and use the #define.
If it's not, just add a small comment on what '184' is doing.
|
|
||
| // configure the UDP socket options | ||
| int iptos_value = 0; | ||
| int iptos_value = 184; |
There was a problem hiding this comment.
Same as above, you can even include <netinet/ip.h> in socket_common.h, since it would be used by both VNF and PNF
| if (sched_response.TX_req.Number_of_PDUs > 0) | ||
| oai_nfapi_tx_data_req(&sched_response.TX_req); | ||
|
|
||
| if (sched_response.DL_req.dl_tti_request_body.nPDUs > 0) | ||
| oai_nfapi_dl_tti_req(&sched_response.DL_req); | ||
|
|
||
| if (sched_response.UL_tti_req.n_pdus > 0) | ||
| oai_nfapi_ul_tti_req(&sched_response.UL_tti_req); | ||
|
|
||
| if (sched_response.TX_req.Number_of_PDUs > 0) | ||
| oai_nfapi_tx_data_req(&sched_response.TX_req); | ||
|
|
There was a problem hiding this comment.
Is there a reason to change the message order here?
in SCF222.10.04 Figure 2-21 you can see it is in the order that was defined, and in SCF225.3.0 Section 2.1.3.5 it states that the message order defined in FAPI also applies for nFAPI.
| p7_vnf->config->send_p7_msg = &vnf_nr_send_p7_msg; | ||
| NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI P7 start thread %s\n", __FUNCTION__); | ||
| threadCreate(&vnf_p7_start_pthread, &vnf_nr_start_p7_thread, p7_vnf->config, "vnf_p7_thread", -1, OAI_PRIORITY_RT); | ||
| threadCreate(&vnf_p7_start_pthread, &vnf_nr_start_p7_thread, p7_vnf->config, "vnf_p7_thread", 14, OAI_PRIORITY_RT); |
There was a problem hiding this comment.
You should avoid pinning to specific cores, if it's really needed, add a new parameter to the config file for the use to be able to set the core to pin to ( default -1 ), similarly to the pinning of the nvIPC thread.
| #ifndef ENABLE_WLS | ||
| // Start VNF autonomous timing thread | ||
| pthread_t t; | ||
| threadCreate(&t, &vnf_timing_thread, p7_vnf, "vnf_timing", 15, OAI_PRIORITY_RT_MAX); |
There was a problem hiding this comment.
Same as above, don't pin to a specific core.
| if(p7_vnf->thread_started == 0) { | ||
| pthread_t vnf_p7_thread; | ||
| threadCreate(&vnf_p7_thread, &configure_nr_p7_vnf, p7_vnf, "vnf_p7_thread", -1, OAI_PRIORITY_RT); | ||
| threadCreate(&vnf_p7_thread, &configure_nr_p7_vnf, p7_vnf, "vnf_p7_thread", 14, OAI_PRIORITY_RT); |
| */ | ||
|
|
||
| int iptos_value = 0; | ||
| int iptos_value = 184; |
There was a problem hiding this comment.
As above, you can include <netinet/ip.h> and use IPTOS_DSCP_EF
Shouldn't have duplicate slot increment at PNF side Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
Rename tx_data_request_* timing fields to tx_data_* in NR timing-related structures and handling paths. This removes naming ambiguity and aligns with current SCF 225 terminology used by timing info exchange. Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
SCF 225 allows timing_window up to 30000us, which exceeds uint8 capacity. Promote timing_window-related fields and pack/unpack paths to uint16 so configuration values are represented consistently across VNF/PNF interfaces. Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
Add DL_TTI/UL_TTI/UL_DCI/TX_DATA per-message timing-offset TLVs to the PARAM response and CONFIG request (pack/unpack in nr_fapi_p5.c, PNF/VNF config structs) so the VNF can tell the PNF how far ahead each message type is sent. Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
Measure per-message P7 arrival timing against the expected window (timing check, slot-diff, in-window tests), accumulate worst-case late/early margins and jitter per message type, and pack them into the timing-info report (pnf_nr_pack_and_send_timing_info). Reset slot_start on start/stop and count late DL/UL/DCI/TX requests. Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
Pre-allocate an rx message buffer and a reassembly buffer (sizes in pnf_p7.h) and reassemble P7 messages fragmented at MTU boundaries in the message pump; free the buffers on config destroy. Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
Parse the PNF timing-info report (vnf_nr_handle_timing_info / vnf_nr_extract_timing_info) and aggregate worst-late and jitter across message types into per-connection state for the pacing logic to consume. Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
Add a self-paced VNF timing thread that derives the numerology, sleeps to each slot boundary (clock_nanosleep), publishes sfn/slot under lock and issues MAC slot indications, catching up in bounded bursts under load and yielding on extreme lag. Send TX_DATA ahead of DL_TTI in the slot-indication path. Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
Add UL node-sync handling (vnf_nr_handle_ul_node_sync) with proportional micro-steering of the slot phase and a drift monitor, plus the slot-time helpers used to compute the dynamic sleep target. Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
Expose timing_window and periodic/aperiodic timing mode and period through the VNF config, add tx_data connection routing and set the RT thread priorities used to set up the P7 timing path. Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
Add vnf_nr_delay_management(): an EWMA controller that tracks mean lateness and jitter deviation from the aggregated timing info and adjusts slot_ahead (increase by ceil((EWMA+Dev)/slot_dur) when late, decrease one slot with >=4-sigma early margin), gated to one timing_info_period, wired into vnf_nr_handle_timing_info. Without this commit the pipeline still runs, with a fixed non-adaptive slot_ahead. Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
54e3c17 to
f46c8dd
Compare
This Pull Request introduces the clean, production-ready OAI nFAPI Delay Management features (VNF autonomous timing thread, adaptive EWMA delay-management controller, etc.) along with the NULL pointer stability bugfix.