Files
openairinterface5g/nfapi/open-nFAPI/vnf/inc/vnf_p7.h
Ming-Hong HSU, BMW Lab@NTUST 1db365ed89 feat(nfapi/vnf): implement Delay management for dynamic slot timing (EWMA-based)
Changes:

* Add comprehensive delay management (DM) and EWMA state variables (e.g., jitter estimates, risk debts, pressure holds, and safe margins) to `nfapi_vnf_p7_connection_info_t` in `vnf_p7.h`.
* Introduce integer-based EWMA math helpers (`p7_ewma_step_i32`, `calculate_slot_distance`, etc.) in `vnf_p7.c` to handle precise timing calculations and prevent integer dead-zones.
* Implement the core `vnf_nr_delay_management()` controller, which dynamically computes the optimal `slot_ahead` using a fast-attack/slow-release pressure model, risk/debt memory, and critical cliff region mapping.
* Integrate the delay controller into `vnf_nr_handle_timing_info()`, feeding it the timing statistics parsed from the PNF to continuously adjust pacing.
* Clean up extensive trailing whitespaces and formatting inconsistencies throughout `vnf_p7.c`.

Purpose:
To establish a robust, adaptive dynamic slot timing controller for the VNF. By leveraging an EWMA-based algorithm, the VNF can continuously track network jitter, estimate mean delays, and intelligently balance timing "debt" against "safe margins." This enables the VNF to proactively and smoothly adjust its transmission pacing (`slot_ahead`) to prevent late packet drops under varying network conditions, eliminating the abrupt and erratic timing jumps seen in the legacy sync implementation.

Signed-off-by: Ming-Hong HSU, BMW Lab@NTUST <m11302209@gapps.ntust.edu.tw>
2026-05-24 15:41:26 +08:00

195 lines
6.8 KiB
C

/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2017 Cisco Systems, Inc.
*/
#ifndef _VNF_P7_H_
#define _VNF_P7_H_
#include "nfapi_vnf_interface.h"
#include <stdatomic.h>
#define TIMEHR_SEC(_time_hr) ((uint32_t)(_time_hr) >> 20)
#define TIMEHR_USEC(_time_hr) ((uint32_t)(_time_hr) & 0xFFFFF)
#define TIME2TIMEHR(_time) (((uint32_t)(_time.tv_sec) & 0xFFF) << 20 | ((uint32_t)(_time.tv_usec) & 0xFFFFF))
/* ============================================================================
* DYNAMIC SLOT SLEEP TIMING CONTROL CONSTANTS
* ============================================================================ */
/* Dynamic Target Margin (adaptive to avoid late packets) */
#define MARGIN_TOLERANCE_US 20 // Deadband zone: +/- MARGIN_TOLERANCE_US us
#define MARGIN_TOLERANCE_LOCKED_US 800 // Wider deadband zone used after first sync lock
#define SLOT_ARRAY_SIZE 20 // TDD cycle slot count (Reduced to 20 for faster convergence)
typedef struct {
uint8_t* buffer;
uint32_t length;
} vnf_p7_rx_message_segment_t;
typedef struct vnf_p7_rx_message vnf_p7_rx_message_t;
typedef struct vnf_p7_rx_message {
uint8_t sequence_number;
uint8_t num_segments_received;
uint8_t num_segments_expected;
// the spec allows of upto 128 segments, this does seem excessive
vnf_p7_rx_message_segment_t segments[128];
uint32_t rx_hr_time;
vnf_p7_rx_message_t* next;
} vnf_p7_rx_message_t;
typedef struct {
vnf_p7_rx_message_t* msg_queue;
} vnf_p7_rx_reassembly_queue_t;
typedef struct nfapi_vnf_p7_connection_info {
/*! The PHY id */
int phy_id;
// this does not belong here...
uint8_t stream_id;
/*! Flag indicating the sync state of the P7 conenction */
uint8_t in_sync;
int dl_out_sync_offset;
int dl_out_sync_period; // ms (as a pow2)
int dl_in_sync_offset;
int dl_in_sync_period; // ms (as a pow2)
uint8_t filtered_adjust;
uint16_t min_sync_cycle_count;
uint32_t latency[8];
uint32_t average_latency;
int32_t sf_offset_filtered;
int32_t sf_offset_trend;
int32_t sf_offset;
int32_t slot_offset;
int32_t slot_offset_trend;
int32_t slot_offset_filtered;
uint16_t zero_count;
int32_t adjustment;
int32_t slot_adjustment;
int32_t us_adjustment;
int32_t insync_minor_adjustment;
int32_t insync_minor_adjustment_duration;
uint8_t sync_locked; // Flag: once offset converges within ±10, permanently stop adjusting
/* Periodic sync control */
uint32_t sync_slot_counter; // Counter for periodic sync
uint32_t sync_period_slots; // Period between syncs (configurable)
uint32_t previous_t1;
uint32_t previous_t2;
int32_t previous_sf_offset_filtered;
int32_t previous_slot_offset_filtered;
uint8_t initial_timinginfo_received;
int sfn_sf;
int sfn;
int slot;
int mu; // some 5G slot calculations need the numerology to know the number
// of slots
int slot_ahead;
uint16_t timing_window;
uint8_t timing_info_period;
struct timespec next_slot_time;
uint32_t slot_duration_us;
uint8_t running;
pthread_t thread;
pthread_mutex_t mutex;
pthread_cond_t initial_timinginfo_cond;
int socket;
struct sockaddr_in local_addr;
struct sockaddr_in remote_addr;
vnf_p7_rx_reassembly_queue_t reassembly_queue;
uint8_t* reassembly_buffer;
uint32_t reassembly_buffer_size;
uint32_t sequence_number;
struct nfapi_vnf_p7_connection_info* next;
int32_t pending_us; // Accumulated borrowed time (us) to be repaid incrementally
int32_t estimated_mean_late; // estimated mean delay
int32_t estimated_jitter_var; // estimated jitter variance
int32_t late_jitter; // Separate EWMA for late jitter
int32_t early_jitter; // Separate EWMA for early jitter
int32_t last_adjustment_steps; // How many slots we increased in last adjustment
int32_t last_adjustment_sfn; // SFN when we made the last upward adjustment
int32_t last_adjustment_slot; // Slot when we made the last upward adjustment
int32_t DM_EWMA_safe_period_count;
int32_t DM_EWMA_late_period_count;
int32_t DM_EWMA_risk_period_count;
int32_t DM_EWMA_last_target_s_ahead;
int32_t DM_EWMA_failure_debt_us;
int32_t DM_EWMA_risk_debt_us;
int32_t DM_EWMA_safe_margin_ewma_us;
int32_t DM_EWMA_jitter_pressure_ahead_us;
int32_t DM_EWMA_jitter_pressure_hold_ahead_us;
int32_t DM_EWMA_jitter_pressure_hold_slots;
} nfapi_vnf_p7_connection_info_t;
typedef struct vnf_p7_s {
nfapi_vnf_p7_config_t _public;
// private data
uint8_t terminate;
nfapi_vnf_p7_connection_info_t* p7_connections;
int socket;
uint32_t sf_start_time_hr;
uint32_t slot_start_time_hr;
uint8_t* rx_message_buffer; // would this be better put in the p7 conenction info?
uint16_t rx_message_buffer_size;
} vnf_p7_t;
uint32_t vnf_get_current_time_hr(void);
uint16_t increment_sfn_sf(uint16_t sfn_sf);
int vnf_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info);
int vnf_nr_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info);
int send_mac_subframe_indications(vnf_p7_t* config);
int send_mac_slot_indications(vnf_p7_t* config);
int vnf_p7_read_dispatch_message(vnf_p7_t* vnf_p7 );
void vnf_nr_handle_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7);
vnf_p7_rx_message_t* vnf_p7_rx_reassembly_queue_add_segment(vnf_p7_t* vnf_p7, vnf_p7_rx_reassembly_queue_t* queue, uint16_t sequence_number, uint16_t segment_number, uint8_t m, uint8_t* data, uint16_t data_len);
void* vnf_p7_malloc(vnf_p7_t* vnf_p7, size_t size);
void vnf_p7_free(vnf_p7_t* vnf_p7, void* ptr);
void vnf_p7_rx_reassembly_queue_remove_msg(vnf_p7_t* vnf_p7, vnf_p7_rx_reassembly_queue_t* queue, vnf_p7_rx_message_t* msg);
void vnf_p7_rx_reassembly_queue_remove_old_msgs(vnf_p7_t* vnf_p7, vnf_p7_rx_reassembly_queue_t* queue, uint32_t delta);
uint32_t calculate_transmit_timestamp(int mu, uint16_t sfn, uint16_t slot, uint32_t slot_start_time_hr);
void vnf_p7_connection_info_list_add(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* node);
nfapi_vnf_p7_connection_info_t* vnf_p7_connection_info_list_find(vnf_p7_t* vnf_p7, uint16_t phy_id);
nfapi_vnf_p7_connection_info_t* vnf_p7_connection_info_list_delete(vnf_p7_t* vnf_p7, uint16_t phy_id);
int vnf_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* header);
void vnf_p7_release_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* header);
void vnf_p7_release_pdu(vnf_p7_t* vnf_p7, void* pdu);
typedef struct {
int32_t worst_late;
int32_t worst_early;
uint32_t packet_slot; // Computed packet slot index in SLOT_ARRAY_SIZE
uint32_t pnf_reported_jitter; // Maximum jitter reported by PNF across message types
} vnf_timing_stats_t;
/* 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);
#endif // _VNF_P7_H_