-
Notifications
You must be signed in to change notification settings - Fork 48
feat(nfapi): OAI nFAPI Delay Management implementation #242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
5ab3daa
f3659c8
5737968
9c42632
0192de7
c9e366c
fd39294
cedddac
eb46549
2529c5b
2f3c3ab
f46c8dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |
| #include <string.h> | ||
| #include <stdarg.h> | ||
| #include <pthread.h> | ||
| #include <sched.h> | ||
| #include <stdlib.h> | ||
| #include <stdint.h> | ||
| #include <sys/socket.h> | ||
|
|
@@ -56,6 +57,8 @@ static nfapi_vnf_config_t *config; | |
| extern RAN_CONTEXT_t RC; | ||
| extern UL_RCC_IND_t UL_RCC_INFO; | ||
|
|
||
| static int nr_start_resp_received = 0; | ||
|
|
||
| nfapi_vnf_config_t * get_config() | ||
| { | ||
| return config; | ||
|
|
@@ -941,15 +944,15 @@ int phy_nr_slot_indication(nfapi_nr_slot_indication_scf_t *ind) | |
| oai_fapi_send_end_request(ind->sfn, ind->slot); | ||
| } | ||
| #else | ||
| 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); | ||
|
|
||
| if (sched_response.UL_dci_req.numPdus > 0) | ||
| oai_nfapi_ul_dci_req(&sched_response.UL_dci_req); | ||
| #endif | ||
|
|
@@ -964,6 +967,153 @@ int phy_nr_slot_indication(nfapi_nr_slot_indication_scf_t *ind) | |
| return 1; | ||
| } | ||
|
|
||
| #ifndef ENABLE_WLS | ||
| static inline void timespec_add_us(struct timespec *t, long us) | ||
| { | ||
| t->tv_nsec += us * 1000; | ||
| if (t->tv_nsec >= 1000000000) { | ||
| t->tv_sec += t->tv_nsec / 1000000000; | ||
| t->tv_nsec %= 1000000000; | ||
| } else if (t->tv_nsec < 0) { | ||
| long sec_diff = (-t->tv_nsec / 1000000000) + 1; | ||
| t->tv_sec -= sec_diff; | ||
| t->tv_nsec += sec_diff * 1000000000; | ||
| } | ||
| } | ||
| #define P7_SYNC_PERIOD_SLOTS_DEFAULT 80 | ||
| #define P7_SYNC_MAX_CATCHUP_BURST 2 | ||
| int vnf_nr_build_send_dl_node_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info); | ||
|
|
||
| static inline void p7_sync_init(nfapi_vnf_p7_connection_info_t *p7_info) | ||
| { | ||
| p7_info->sync_slot_counter = 0; | ||
| p7_info->sync_period_slots = P7_SYNC_PERIOD_SLOTS_DEFAULT; | ||
| p7_info->consecutive_drift_violations = 0; | ||
| p7_info->nr_offset_filtered = 0; | ||
| NFAPI_TRACE(NFAPI_TRACE_INFO, "[P7_SYNC] Initialized: period=%u slots\n", | ||
| p7_info->sync_period_slots); | ||
| } | ||
|
|
||
| void *vnf_timing_thread(void *arg) | ||
| { | ||
| vnf_p7_info *p7_vnf = (vnf_p7_info *)arg; | ||
| vnf_p7_t *vnf_p7 = (vnf_p7_t *)p7_vnf->config; | ||
|
|
||
| int mu = -1; | ||
| nfapi_vnf_p7_connection_info_t *p7_info = NULL; | ||
|
|
||
| while (1) { | ||
| if (__atomic_load_n(&nr_start_resp_received, __ATOMIC_ACQUIRE)) { | ||
| if (vnf_p7->p7_connections) { | ||
| p7_info = vnf_p7->p7_connections; | ||
| if (RC.nrmac && RC.nrmac[0]) { | ||
| nfapi_nr_config_request_scf_t *req = &RC.nrmac[0]->config[0]; | ||
| const nfapi_uint8_tlv_t *scs = &req->ssb_config.scs_common; | ||
| if (scs && scs->tl.tag == NFAPI_NR_CONFIG_SCS_COMMON_TAG) { | ||
| mu = scs->value; | ||
| } | ||
| } | ||
| if (mu < 0 && RC.gNB && RC.gNB[0] && RC.gNB[0]->configured && RC.gNB[0]->frame_parms.numerology_index >= 0) { | ||
| mu = RC.gNB[0]->frame_parms.numerology_index; | ||
| } | ||
| if (mu >= 0) { | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| usleep(1000000); | ||
| } | ||
| pthread_mutex_lock(&p7_info->mutex); | ||
| while (!p7_info->initial_timinginfo_received) { | ||
| pthread_cond_wait(&p7_info->initial_timinginfo_cond, &p7_info->mutex); | ||
| } | ||
| pthread_mutex_unlock(&p7_info->mutex); | ||
| DevAssert(mu >= 0 && mu <= 5); | ||
| p7_info->mu = mu; | ||
| p7_info->slot_duration_us = 1000 >> p7_info->mu; | ||
| LOG_I(NFAPI_VNF, "Starting VNF autonomous timing thread: mu = %d, slot duration = %d us\n", mu, p7_info->slot_duration_us); | ||
| if (p7_info->initial_timinginfo_received) { | ||
| int sfnslot_dec = NFAPI_SFNSLOT2DEC(p7_info->mu, p7_info->sfn, p7_info->slot); | ||
| sfnslot_dec = (sfnslot_dec + 1) % NFAPI_MAX_SFNSLOTDEC(p7_info->mu); | ||
| p7_info->sfn = NFAPI_SFNSLOTDEC2SFN(p7_info->mu, sfnslot_dec); | ||
| p7_info->slot = NFAPI_SFNSLOTDEC2SLOT(p7_info->mu, sfnslot_dec); | ||
| } | ||
| p7_info->running = 1; | ||
| p7_info->thread = pthread_self(); | ||
| p7_sync_init(p7_info); | ||
| clock_gettime(CLOCK_MONOTONIC, &p7_info->next_slot_time); | ||
| vnf_p7->slot_start_time_hr = vnf_get_current_time_hr(); | ||
| vnf_nr_build_send_dl_node_sync(vnf_p7, p7_info); | ||
|
|
||
| const int max_sfnslotdec = NFAPI_MAX_SFNSLOTDEC(p7_info->mu); | ||
| int last_mac_ind_dec = -1; | ||
|
|
||
| int sfnslot_dec = NFAPI_SFNSLOT2DEC(p7_info->mu, p7_info->sfn, p7_info->slot); | ||
|
|
||
| while (p7_info->running) { | ||
| pthread_mutex_lock(&p7_info->mutex); | ||
| if (p7_info->slot_adjustment != 0) { | ||
| sfnslot_dec = (sfnslot_dec + p7_info->slot_adjustment + max_sfnslotdec) % max_sfnslotdec; | ||
| p7_info->slot_adjustment = 0; | ||
| } | ||
| int32_t current_pending_us = p7_info->pending_us; | ||
| p7_info->pending_us = 0; | ||
| pthread_mutex_unlock(&p7_info->mutex); | ||
|
|
||
| timespec_add_us(&p7_info->next_slot_time, p7_info->slot_duration_us + current_pending_us); | ||
| struct timespec now; | ||
| clock_gettime(CLOCK_MONOTONIC, &now); | ||
| int64_t diff_ns = (p7_info->next_slot_time.tv_sec - now.tv_sec) * 1000000000LL + (p7_info->next_slot_time.tv_nsec - now.tv_nsec); | ||
| const int64_t extreme_lag_threshold_ns = (int64_t)p7_info->slot_duration_us * 5 * 1000LL; | ||
| if (diff_ns < -extreme_lag_threshold_ns) { | ||
| // next_slot_time is in the past by more than 5 slots! | ||
| // Yield CPU to prevent starvation of the SCTP/UDP network thread under extreme lag. | ||
| sched_yield(); | ||
| } | ||
| if (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &p7_info->next_slot_time, NULL) != 0) | ||
| continue; | ||
| vnf_p7->slot_start_time_hr = vnf_get_current_time_hr(); | ||
| pthread_mutex_lock(&p7_info->mutex); | ||
| p7_info->sfn = NFAPI_SFNSLOTDEC2SFN(p7_info->mu, sfnslot_dec); | ||
| p7_info->slot = NFAPI_SFNSLOTDEC2SLOT(p7_info->mu, sfnslot_dec); | ||
| pthread_mutex_unlock(&p7_info->mutex); | ||
|
|
||
| if (p7_info->sync_slot_counter >= p7_info->sync_period_slots) { | ||
| p7_info->sync_slot_counter = 0; | ||
| vnf_nr_build_send_dl_node_sync(vnf_p7, p7_info); | ||
| } else { | ||
| p7_info->sync_slot_counter++; | ||
| } | ||
|
|
||
| int32_t slot_ahead = __atomic_load_n(&p7_info->slot_ahead, __ATOMIC_RELAXED); | ||
| int target_ind_dec = (sfnslot_dec + slot_ahead) % max_sfnslotdec; | ||
| if (last_mac_ind_dec == -1) { | ||
| last_mac_ind_dec = (target_ind_dec - 1 + max_sfnslotdec) % max_sfnslotdec; | ||
| } | ||
|
|
||
| int diff_mac = (target_ind_dec - last_mac_ind_dec + max_sfnslotdec) % max_sfnslotdec; | ||
| if (diff_mac > 0 && diff_mac < max_sfnslotdec / 2) { | ||
| // NEVER skip slots! Skipping slots breaks MAC scheduling (e.g. RACH, HARQ timing assertions) and drops UE. | ||
| // Catch up in smooth bursts up to max_burst. If a huge drift happens during iperf CPU starvation, | ||
| // generating backlog sequentially is much safer than jumping. | ||
| int burst_counter = 0; | ||
| const int max_burst = 10 << p7_info->mu; | ||
| while (last_mac_ind_dec != target_ind_dec && burst_counter < max_burst) { | ||
| last_mac_ind_dec = (last_mac_ind_dec + 1) % max_sfnslotdec; | ||
| nfapi_nr_slot_indication_scf_t ind = {0}; | ||
| ind.sfn = NFAPI_SFNSLOTDEC2SFN(p7_info->mu, last_mac_ind_dec); | ||
| ind.slot = NFAPI_SFNSLOTDEC2SLOT(p7_info->mu, last_mac_ind_dec); | ||
| ind.header.phy_id = p7_info->phy_id; | ||
| phy_nr_slot_indication(&ind); | ||
| burst_counter++; | ||
| } | ||
| } | ||
| sfnslot_dec = (sfnslot_dec + 1) % max_sfnslotdec; | ||
| } | ||
| return NULL; | ||
| } | ||
| #endif | ||
|
|
||
| int phy_nr_srs_indication(nfapi_nr_srs_indication_t *ind) | ||
| { | ||
| for (int i = 0; i < ind->number_of_pdus; ++i) | ||
|
|
@@ -1299,14 +1449,19 @@ void *configure_nr_p7_vnf(void *ptr) | |
| p7_vnf->config->pack_func = &nfapi_nr_p7_message_pack; | ||
| 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); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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. |
||
| #endif | ||
|
|
||
| #ifdef ENABLE_AERIAL | ||
| p7_vnf->config->unpack_func = &fapi_nr_p7_message_unpack; | ||
| p7_vnf->config->hdr_unpack_func = &fapi_nr_p7_message_header_unpack; | ||
| p7_vnf->config->pack_func = &fapi_nr_p7_message_pack; | ||
| p7_vnf->config->send_p7_msg = &aerial_nr_send_p7_message; | ||
| #endif | ||
| #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); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above, don't pin to a specific core. |
||
| #endif | ||
| return 0; | ||
| } | ||
|
|
@@ -1341,7 +1496,7 @@ void *vnf_p7_thread_start(void *ptr) { | |
| p7_vnf->config->codec_config.deallocate = &vnf_deallocate; | ||
| p7_vnf->config->allocate_p7_vendor_ext = &phy_allocate_p7_vendor_ext; | ||
| p7_vnf->config->deallocate_p7_vendor_ext = &phy_deallocate_p7_vendor_ext; | ||
| NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI P7 start thread %s\n", __FUNCTION__); | ||
| NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI start thread %s\n", __FUNCTION__); | ||
| pthread_create(&vnf_p7_start_pthread, NULL, &vnf_p7_start_thread, p7_vnf->config); | ||
| return 0; | ||
| } | ||
|
|
@@ -1356,7 +1511,7 @@ int pnf_nr_start_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_pnf_st | |
|
|
||
| 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); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As above |
||
| p7_vnf->thread_started = 1; | ||
| } else { | ||
| // P7 thread already running. | ||
|
|
@@ -1463,11 +1618,20 @@ int nr_param_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_param_resp | |
| req->num_tlv++; | ||
| } | ||
| } | ||
| //TODO: Assign tag and value for P7 message offsets | ||
| req->nfapi_config.dl_tti_timing_offset.tl.tag = NFAPI_NR_NFAPI_DL_TTI_TIMING_OFFSET; | ||
| req->nfapi_config.ul_tti_timing_offset.tl.tag = NFAPI_NR_NFAPI_UL_TTI_TIMING_OFFSET; | ||
| req->nfapi_config.ul_dci_timing_offset.tl.tag = NFAPI_NR_NFAPI_UL_DCI_TIMING_OFFSET; | ||
| req->nfapi_config.tx_data_timing_offset.tl.tag = NFAPI_NR_NFAPI_TX_DATA_TIMING_OFFSET; | ||
| // Assign tag and value for P7 message offsets | ||
| req->nfapi_config.dl_tti_timing_offset.tl.tag = NFAPI_NR_NFAPI_DL_TTI_TIMING_OFFSET; | ||
| req->nfapi_config.dl_tti_timing_offset.value = p7_vnf->dl_tti_timing_offset; | ||
|
|
||
| req->nfapi_config.ul_tti_timing_offset.tl.tag = NFAPI_NR_NFAPI_UL_TTI_TIMING_OFFSET; | ||
| req->nfapi_config.ul_tti_timing_offset.value = p7_vnf->ul_tti_timing_offset; | ||
|
|
||
| req->nfapi_config.ul_dci_timing_offset.tl.tag = NFAPI_NR_NFAPI_UL_DCI_TIMING_OFFSET; | ||
| req->nfapi_config.ul_dci_timing_offset.value = p7_vnf->ul_dci_timing_offset; | ||
|
|
||
| req->nfapi_config.tx_data_timing_offset.tl.tag = NFAPI_NR_NFAPI_TX_DATA_TIMING_OFFSET; | ||
| req->nfapi_config.tx_data_timing_offset.value = p7_vnf->tx_data_timing_offset; | ||
|
|
||
| req->num_tlv += 4; | ||
|
|
||
| vendor_ext_tlv_2 ve2; | ||
| memset(&ve2, 0, sizeof(ve2)); | ||
|
|
@@ -1572,6 +1736,7 @@ int start_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_start_response_t | |
| 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); | ||
| __atomic_store_n(&nr_start_resp_received, 1, __ATOMIC_RELEASE); | ||
| return 0; | ||
| } | ||
|
|
||
|
|
@@ -1754,8 +1919,12 @@ void configure_nr_nfapi_vnf(eth_params_t params) | |
| #endif | ||
| vnf_info *vnf = calloc(1, sizeof(vnf_info)); | ||
| memset(vnf->p7_vnfs, 0, sizeof(vnf->p7_vnfs)); | ||
| vnf->p7_vnfs[0].timing_window = 30; | ||
| vnf->p7_vnfs[0].periodic_timing_enabled = 0; | ||
| vnf->p7_vnfs[0].timing_window = 6500; | ||
| vnf->p7_vnfs[0].dl_tti_timing_offset = 0; | ||
| vnf->p7_vnfs[0].ul_tti_timing_offset = 0; | ||
| vnf->p7_vnfs[0].ul_dci_timing_offset = 0; | ||
| vnf->p7_vnfs[0].tx_data_timing_offset = 0; | ||
| vnf->p7_vnfs[0].periodic_timing_enabled = 1; | ||
| vnf->p7_vnfs[0].aperiodic_timing_enabled = 0; | ||
| vnf->p7_vnfs[0].periodic_timing_period = 1; | ||
| vnf->p7_vnfs[0].config = nfapi_vnf_p7_config_create(); | ||
|
|
@@ -1779,6 +1948,9 @@ void configure_nr_nfapi_vnf(eth_params_t params) | |
| config->vnf_ipv6 = 0; | ||
| config->pnf_list = 0; | ||
| config->phy_list = 0; | ||
| config->timing_window = vnf->p7_vnfs[0].timing_window; | ||
| config->timing_info_mode = (vnf->p7_vnfs[0].aperiodic_timing_enabled << 1) | (vnf->p7_vnfs[0].periodic_timing_enabled); | ||
| config->timing_info_period = vnf->p7_vnfs[0].periodic_timing_period; | ||
|
|
||
| config->pnf_nr_connection_indication = &pnf_nr_connection_indication_cb; | ||
| config->pnf_disconnect_indication = &pnf_disconnection_indication_cb; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.