Merge remote-tracking branch 'origin/fix-itti-segv' into integration_2020_wk48
This commit is contained in:
@@ -194,7 +194,8 @@ task_list_t tasks[TASK_MAX];
|
|||||||
t->next_timer=UINT64_MAX;
|
t->next_timer=UINT64_MAX;
|
||||||
|
|
||||||
// Proceed expired timer
|
// Proceed expired timer
|
||||||
for ( auto it=t->timer_map.begin() ; it != t->timer_map.end() ; ++it ) {
|
for ( auto it=t->timer_map.begin() , next_it = it; it != t->timer_map.end() ; it = next_it ) {
|
||||||
|
++next_it;
|
||||||
if ( it->second.timeout < current_time ) {
|
if ( it->second.timeout < current_time ) {
|
||||||
MessageDef *message = itti_alloc_new_message(TASK_TIMER, TIMER_HAS_EXPIRED);
|
MessageDef *message = itti_alloc_new_message(TASK_TIMER, TIMER_HAS_EXPIRED);
|
||||||
message->ittiMsg.timer_has_expired.timer_id=it->first;
|
message->ittiMsg.timer_has_expired.timer_id=it->first;
|
||||||
|
|||||||
+52
-8
@@ -164,8 +164,6 @@ nr_schedule_ue_spec() is called
|
|||||||
|
|
||||||
Calls nr_fill_nfapi_dl_pdu() to actually populate what should be done by the lower layers to make the Tx subframe
|
Calls nr_fill_nfapi_dl_pdu() to actually populate what should be done by the lower layers to make the Tx subframe
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# RRC
|
# RRC
|
||||||
RRC is a regular thread with itti loop on queue: TASK_RRC_GNB
|
RRC is a regular thread with itti loop on queue: TASK_RRC_GNB
|
||||||
it receives it's configuration in message NRRRC_CONFIGURATION_REQ, then real time mesages for all events: S1/NGAP events, X2AP messages and RRC_SUBFRAME_PROCESS
|
it receives it's configuration in message NRRRC_CONFIGURATION_REQ, then real time mesages for all events: S1/NGAP events, X2AP messages and RRC_SUBFRAME_PROCESS
|
||||||
@@ -176,14 +174,56 @@ how does it communicate to scheduler ?
|
|||||||
|
|
||||||
|
|
||||||
# RLC
|
# RLC
|
||||||
RLC code is new implementation, not using OAI mechanisms: it is implmented directly on pthreads, ignoring OAI common functions.
|
RLC code is new implementation, not using OAI mechanisms: it is implemented directly on pthreads, ignoring OAI common functions.
|
||||||
It runs a thread waiting incoming data, but it is mainly running inside calling thread.
|
It is a library, running in thread RRC but also in PHY layer threads and some bits in pdcp running thread or F1 interface threads.
|
||||||
It is a library, running in thread RRC (except on itti message: F1AP_UL_RRC_MESSAGE for F1).
|
|
||||||
|
|
||||||
# NGAP
|
RLC data is isolated and encapsulated.
|
||||||
NGAP would be a itti thread as is S1AP (+twin thread SCTP that is almost void processing)?
|
It is stored under a global var: nr_rlc_ue_manager
|
||||||
About all messages are exchanged with RRC thread
|
The init function rlc_module_init() populates this global variable.
|
||||||
|
A small effort could lead us to return the pointer to the caller of rlc_module_init() (internal type: nr_rlc_ue_manager_internal_t)
|
||||||
|
but it returns void.
|
||||||
|
It could return the initialized pointer (as FILE* fopen() for example), then the RLC layer could have multiple instances in one process.
|
||||||
|
Even, a future evolution could remove this global rlc layer: rlc can be only a library that we create a instance for each UE because it doesn't shareany data between UEs.
|
||||||
|
|
||||||
|
For DL (respectively from UL in UE), the scheduler need to know the quantity of data waitin to be sent: it calls mac_rlc_status_ind()
|
||||||
|
That "peek" the size of the waiting data for a UE.
|
||||||
|
The scheduler then push orders to lower layers. The transport layer will actually pull data from RLC with: mac_rlc_data_req()
|
||||||
|
the low layer push data into rlc by: mac_rlc_data_ind()
|
||||||
|
Still on DL (gNB side), PDCP push incoming data into RLC by calling: rlc_data_req()
|
||||||
|
|
||||||
|
For UL, the low layer push data into rlc by: mac_rlc_data_ind()
|
||||||
|
Then, rlc push it to pdcp by calling pdcp_data_ind() from a complex rlc internal call back (deliver_sdu())
|
||||||
|
|
||||||
|
When adding a UE, external code have to call nr_rrc_rlc_config_asn1_req(), to remove it: rrc_rlc_remove_ue()
|
||||||
|
Inside UE, channels called drd or srb can be created: ??? and deleted: rrc_rlc_config_req()
|
||||||
|
|
||||||
|
nr_rlc_tick() must be called periodically to manage the internal timers
|
||||||
|
|
||||||
|
successful_delivery() and max_retx_reached(): in ??? trigger, the RLC sends a itti message to RRC: RLC_SDU_INDICATION (neutralized by #if 0 right now)
|
||||||
|
|
||||||
|
#PDCP
|
||||||
|
|
||||||
|
The PDCP implementation is also protected through a general mutex.
|
||||||
|
The design is very similar to rlc layer. The pdcp data is isolated and encapsulated.
|
||||||
|
|
||||||
|
pdcp_layer_init(): same as rlc init
|
||||||
|
we have to call a second init function: pdcp_module_init()
|
||||||
|
|
||||||
|
At Tx side (DL in gNB), pdcp_data_req() is the entry function that the upper layer calls.
|
||||||
|
The upper layer can be GTP or a PDCP internal thread enb_tun_read_thread() that read directly from Linux socket in case we skip 3GPP core implementation.
|
||||||
|
PDCP internals for pdcp_data_req() is thread safe: inside pdcp_data_req_drb(), the pdcp manager protects with the mutex the access to the SDU receiving function of PDCP (recv_sdu() callback, corresponding to nr_pdcp_entity_drb_am_recv_sdu() for DRBs). When it needs, the pdcp layer push this data to rlc by calling : rlc_data_req()
|
||||||
|
|
||||||
|
Also, incoming downlink sdu can comme from internal RRC: in this case, pdcp_run() reads a itti queue, for message RRC_DCCH_DATA_REQ, to0 only call 'pdcp_data_req()'
|
||||||
|
|
||||||
|
At Rx side, pdcp_data_ind() is the entry point that receives the data from RLC.
|
||||||
|
- Inside pdcp_data_ind(), the pdcp manager mutex protects the access to the PDU receiving function of PDCP (recv_pdu() callback corresponding to nr_pdcp_entity_drb_am_recv_pdu() for DRBs)
|
||||||
|
- Then deliver_sdu_drb() function sends the received data to GTP thread through an ITTI message (GTPV1U_ENB_TUNNEL_DATA_REQ).
|
||||||
|
|
||||||
|
pdcp_config_set_security(): not yet developped
|
||||||
|
|
||||||
|
nr_DRB_preconfiguration(): the mac layer calls this for ???
|
||||||
|
|
||||||
|
nr_rrc_pdcp_config_asn1_req() adds a UE in pdcp, pdcp_remove_UE() removes it
|
||||||
|
|
||||||
# GTP
|
# GTP
|
||||||
Gtp + UDP are two twin threads performing the data plane interface to the core network
|
Gtp + UDP are two twin threads performing the data plane interface to the core network
|
||||||
@@ -200,6 +240,10 @@ gtp thread calls directly pdcp_data_req(), so it runs inside it's context intern
|
|||||||
## inside other threads
|
## inside other threads
|
||||||
gtpv1u_create_s1u_tunnel(), delete tunnel, ... functions are called inside the other threads, without mutex.
|
gtpv1u_create_s1u_tunnel(), delete tunnel, ... functions are called inside the other threads, without mutex.
|
||||||
|
|
||||||
|
# NGAP
|
||||||
|
NGAP would be a itti thread as is S1AP (+twin thread SCTP that is almost void processing)?
|
||||||
|
About all messages are exchanged with RRC thread
|
||||||
|
|
||||||
|
|
||||||
<div class="panel panel-info">
|
<div class="panel panel-info">
|
||||||
**Note**
|
**Note**
|
||||||
|
|||||||
@@ -421,7 +421,6 @@ void nr_initiate_ra_proc(module_id_t module_idP,
|
|||||||
|
|
||||||
uint8_t ul_carrier_id = 0; // 0 for NUL 1 for SUL
|
uint8_t ul_carrier_id = 0; // 0 for NUL 1 for SUL
|
||||||
NR_SearchSpace_t *ss;
|
NR_SearchSpace_t *ss;
|
||||||
int UE_id = 0;
|
|
||||||
|
|
||||||
uint16_t msg2_frame, msg2_slot,monitoring_slot_period,monitoring_offset;
|
uint16_t msg2_frame, msg2_slot,monitoring_slot_period,monitoring_offset;
|
||||||
gNB_MAC_INST *nr_mac = RC.nrmac[module_idP];
|
gNB_MAC_INST *nr_mac = RC.nrmac[module_idP];
|
||||||
|
|||||||
@@ -1692,7 +1692,7 @@ inline void add_nr_ue_list(NR_UE_list_t *listP, int UE_id) {
|
|||||||
/*
|
/*
|
||||||
* Remove a UE from NR_UE_list listP
|
* Remove a UE from NR_UE_list listP
|
||||||
*/
|
*/
|
||||||
inline int remove_nr_ue_list(NR_UE_list_t *listP, int UE_id) {
|
static inline void remove_nr_ue_list(NR_UE_list_t *listP, int UE_id) {
|
||||||
int *cur = &listP->head;
|
int *cur = &listP->head;
|
||||||
while (*cur != -1 && *cur != UE_id)
|
while (*cur != -1 && *cur != UE_id)
|
||||||
cur = &listP->next[*cur];
|
cur = &listP->next[*cur];
|
||||||
@@ -1700,7 +1700,7 @@ inline int remove_nr_ue_list(NR_UE_list_t *listP, int UE_id) {
|
|||||||
int *next = &listP->next[*cur];
|
int *next = &listP->next[*cur];
|
||||||
*cur = listP->next[*cur];
|
*cur = listP->next[*cur];
|
||||||
*next = -1;
|
*next = -1;
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int find_nr_UE_id(module_id_t mod_idP, rnti_t rntiP)
|
int find_nr_UE_id(module_id_t mod_idP, rnti_t rntiP)
|
||||||
|
|||||||
Reference in New Issue
Block a user