diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity.c index 1883bbdd6c..311d31bfde 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity.c @@ -29,6 +29,14 @@ #include "LOG/log.h" +static void nr_rlc_entity_get_stats( + nr_rlc_entity_t *entity, + nr_rlc_statistics_t *out) +{ +// printf("Stats from the RLC entity asked\n"); + *out = entity->stats; +} + nr_rlc_entity_t *new_nr_rlc_entity_am( int rx_maxsize, int tx_maxsize, @@ -86,6 +94,7 @@ nr_rlc_entity_t *new_nr_rlc_entity_am( ret->common.reestablishment = nr_rlc_entity_am_reestablishment; ret->common.delete = nr_rlc_entity_am_delete; ret->common.available_tx_space = nr_rlc_entity_am_available_tx_space; + ret->common.get_stats = nr_rlc_entity_get_stats; ret->common.deliver_sdu = deliver_sdu; ret->common.deliver_sdu_data = deliver_sdu_data; @@ -94,6 +103,8 @@ nr_rlc_entity_t *new_nr_rlc_entity_am( ret->common.max_retx_reached = max_retx_reached; ret->common.max_retx_reached_data = max_retx_reached_data; + ret->common.stats.mode = 0; /* 0 for AM */ + return (nr_rlc_entity_t *)ret; } @@ -137,10 +148,13 @@ nr_rlc_entity_t *new_nr_rlc_entity_um( ret->common.reestablishment = nr_rlc_entity_um_reestablishment; ret->common.delete = nr_rlc_entity_um_delete; ret->common.available_tx_space = nr_rlc_entity_um_available_tx_space; + ret->common.get_stats = nr_rlc_entity_get_stats; ret->common.deliver_sdu = deliver_sdu; ret->common.deliver_sdu_data = deliver_sdu_data; + ret->common.stats.mode = 1; /* 1 for UM */ + return (nr_rlc_entity_t *)ret; } @@ -169,9 +183,12 @@ nr_rlc_entity_t *new_nr_rlc_entity_tm( ret->common.reestablishment = nr_rlc_entity_tm_reestablishment; ret->common.delete = nr_rlc_entity_tm_delete; ret->common.available_tx_space = nr_rlc_entity_tm_available_tx_space; + ret->common.get_stats = nr_rlc_entity_get_stats; ret->common.deliver_sdu = deliver_sdu; ret->common.deliver_sdu_data = deliver_sdu_data; + ret->common.stats.mode = 2; /* 2 for TM */ + return (nr_rlc_entity_t *)ret; } diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h index 5cd3bee650..fcb92a8a11 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h @@ -26,6 +26,59 @@ #define NR_SDU_MAX 16000 /* max NR PDCP SDU size is 9000, let's take more */ +typedef struct { + uint32_t mode; /* 0: RLC AM, 1: RLC UM, 2: RLC TM */ + + /* PDU stats */ + /* TX */ + uint32_t txpdu_pkts; /* aggregated number of transmitted RLC PDUs */ + uint32_t txpdu_bytes; /* aggregated amount of transmitted bytes in RLC PDUs */ + /* TODO? */ + uint32_t txpdu_wt_ms; /* aggregated head-of-line tx packet waiting time to be transmitted (i.e. send to the MAC layer) */ + uint32_t txpdu_dd_pkts; /* aggregated number of dropped or discarded tx packets by RLC */ + uint32_t txpdu_dd_bytes; /* aggregated amount of bytes dropped or discarded tx packets by RLC */ + uint32_t txpdu_retx_pkts; /* aggregated number of tx pdus/pkts to be re-transmitted (only applicable to RLC AM) */ + uint32_t txpdu_retx_bytes; /* aggregated amount of bytes to be re-transmitted (only applicable to RLC AM) */ + uint32_t txpdu_segmented; /* aggregated number of segmentations */ + uint32_t txpdu_status_pkts; /* aggregated number of tx status pdus/pkts (only applicable to RLC AM) */ + uint32_t txpdu_status_bytes; /* aggregated amount of tx status bytes (only applicable to RLC AM) */ + /* TODO? */ + uint32_t txbuf_occ_bytes; /* current tx buffer occupancy in terms of amount of bytes (average: NOT IMPLEMENTED) */ + /* TODO? */ + uint32_t txbuf_occ_pkts; /* current tx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */ + /* txbuf_wd_ms: the time window for which the txbuf occupancy value is obtained - NOT IMPLEMENTED */ + + /* RX */ + uint32_t rxpdu_pkts; /* aggregated number of received RLC PDUs */ + uint32_t rxpdu_bytes; /* amount of bytes received by the RLC */ + uint32_t rxpdu_dup_pkts; /* aggregated number of duplicate packets */ + uint32_t rxpdu_dup_bytes; /* aggregated amount of duplicated bytes */ + uint32_t rxpdu_dd_pkts; /* aggregated number of rx packets dropped or discarded by RLC */ + uint32_t rxpdu_dd_bytes; /* aggregated amount of rx bytes dropped or discarded by RLC */ + uint32_t rxpdu_ow_pkts; /* aggregated number of out of window received RLC pdu */ + uint32_t rxpdu_ow_bytes; /* aggregated number of out of window bytes received RLC pdu */ + uint32_t rxpdu_status_pkts; /* aggregated number of rx status pdus/pkts (only applicable to RLC AM) */ + uint32_t rxpdu_status_bytes; /* aggregated amount of rx status bytes (only applicable to RLC AM) */ + /* rxpdu_rotout_ms: flag indicating rx reordering timeout in ms - NOT IMPLEMENTED */ + /* rxpdu_potout_ms: flag indicating the poll retransmit time out in ms - NOT IMPLEMENTED */ + /* rxpdu_sptout_ms: flag indicating status prohibit timeout in ms - NOT IMPLEMENTED */ + /* TODO? */ + uint32_t rxbuf_occ_bytes; /* current rx buffer occupancy in terms of amount of bytes (average: NOT IMPLEMENTED) */ + /* TODO? */ + uint32_t rxbuf_occ_pkts; /* current rx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */ + + /* SDU stats */ + /* TX */ + uint32_t txsdu_pkts; /* number of SDUs delivered */ + uint32_t txsdu_bytes; /* number of bytes of SDUs delivered */ + + /* RX */ + uint32_t rxsdu_pkts; /* number of SDUs received */ + uint32_t rxsdu_bytes; /* number of bytes of SDUs received */ + uint32_t rxsdu_dd_pkts; /* number of dropped or discarded SDUs */ + uint32_t rxsdu_dd_bytes; /* number of bytes of SDUs dropped or discarded */ +} nr_rlc_statistics_t; + typedef struct { int status_size; int tx_size; @@ -52,6 +105,8 @@ typedef struct nr_rlc_entity_t { int (*available_tx_space)(struct nr_rlc_entity_t *entity); + void (*get_stats)(struct nr_rlc_entity_t *entity, nr_rlc_statistics_t *out); + /* callbacks provided to the RLC module */ void (*deliver_sdu)(void *deliver_sdu_data, struct nr_rlc_entity_t *entity, char *buf, int size); @@ -67,6 +122,8 @@ typedef struct nr_rlc_entity_t { void *max_retx_reached_data; /* buffer status computation */ nr_rlc_entity_buffer_status_t bstatus; + + nr_rlc_statistics_t stats; } nr_rlc_entity_t; nr_rlc_entity_t *new_nr_rlc_entity_am( diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c index 91e2bed11a..c81ae16335 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c @@ -221,6 +221,9 @@ static void reassemble_and_deliver(nr_rlc_entity_am_t *entity, int sn) entity->common.deliver_sdu(entity->common.deliver_sdu_data, (nr_rlc_entity_t *)entity, sdu, so); + + entity->common.stats.txsdu_pkts++; + entity->common.stats.txsdu_bytes += so; } static void reception_actions(nr_rlc_entity_am_t *entity, nr_rlc_pdu_t *pdu) @@ -684,6 +687,9 @@ void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity, int is_first; int is_last; + entity->common.stats.rxpdu_pkts++; + entity->common.stats.rxpdu_bytes += size; + nr_rlc_pdu_decoder_init(&decoder, buffer, size); dc = nr_rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); @@ -733,6 +739,10 @@ void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity, LOG_D(RLC, "%s:%d:%s: warning: discard PDU, sn out of window (sn %d rx_next %d)\n", __FILE__, __LINE__, __FUNCTION__, sn, entity->rx_next); + + entity->common.stats.rxpdu_ow_pkts++; + entity->common.stats.rxpdu_ow_bytes += size; + goto discard; } @@ -740,6 +750,10 @@ void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity, if (segment_already_received(entity, sn, so, data_size)) { LOG_D(RLC, "%s:%d:%s: warning: discard PDU, already received\n", __FILE__, __LINE__, __FUNCTION__); + + entity->common.stats.rxpdu_dup_pkts++; + entity->common.stats.rxpdu_dup_bytes += size; + goto discard; } @@ -779,6 +793,9 @@ discard: if (p) entity->status_triggered = 1; + entity->common.stats.rxpdu_dd_pkts++; + entity->common.stats.rxpdu_dd_bytes += size; + #undef R } @@ -1309,6 +1326,11 @@ static int generate_status(nr_rlc_entity_am_t *entity, char *buffer, int size) /* start t_status_prohibit */ entity->t_status_prohibit_start = entity->t_current; + entity->common.stats.txpdu_pkts++; + entity->common.stats.txpdu_bytes += encoder.byte; + entity->common.stats.txpdu_status_pkts++; + entity->common.stats.txpdu_status_bytes += encoder.byte; + return encoder.byte; } @@ -1473,6 +1495,8 @@ static int generate_retx_pdu(nr_rlc_entity_am_t *entity, char *buffer, /* update buffer status */ entity->common.bstatus.retx_size += compute_pdu_header_size(entity, next_sdu) + next_sdu->size; + + entity->common.stats.txpdu_segmented++; } /* put SDU/SDU segment in the wait list */ @@ -1496,7 +1520,14 @@ static int generate_retx_pdu(nr_rlc_entity_am_t *entity, char *buffer, entity->force_poll = 0; } - return serialize_sdu(entity, sdu, buffer, size, p); + int ret_size = serialize_sdu(entity, sdu, buffer, size, p); + entity->common.stats.txpdu_pkts++; + entity->common.stats.txpdu_bytes += ret_size; + entity->common.stats.txpdu_retx_pkts++; + entity->common.stats.txpdu_retx_bytes += ret_size; + + return ret_size; +// return serialize_sdu(entity, sdu, buffer, size, p); } static int generate_tx_pdu(nr_rlc_entity_am_t *entity, char *buffer, int size) @@ -1544,6 +1575,8 @@ static int generate_tx_pdu(nr_rlc_entity_am_t *entity, char *buffer, int size) entity->tx_list = next_sdu; if (entity->tx_end == NULL) entity->tx_end = entity->tx_list; + + entity->common.stats.txpdu_segmented++; /* update buffer status */ entity->common.bstatus.tx_size += compute_pdu_header_size(entity, next_sdu) + next_sdu->size; @@ -1582,8 +1615,13 @@ static int generate_tx_pdu(nr_rlc_entity_am_t *entity, char *buffer, int size) p = 1; entity->force_poll = 0; } + int ret_size = serialize_sdu(entity, sdu, buffer, size, p); - return serialize_sdu(entity, sdu, buffer, size, p); + entity->common.stats.txpdu_pkts++; + entity->common.stats.txpdu_bytes += ret_size; + + return ret_size; +// return serialize_sdu(entity, sdu, buffer, size, p); } nr_rlc_entity_buffer_status_t nr_rlc_entity_am_buffer_status( @@ -1635,6 +1673,9 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity, nr_rlc_entity_am_t *entity = (nr_rlc_entity_am_t *)_entity; nr_rlc_sdu_segment_t *sdu; + entity->common.stats.rxsdu_pkts++; + entity->common.stats.rxsdu_bytes += size; + if (size > NR_SDU_MAX) { LOG_E(RLC, "%s:%d:%s: fatal: SDU size too big (%d bytes)\n", __FILE__, __LINE__, __FUNCTION__, size); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c index f85edbba0f..14cf8cad25 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c @@ -36,9 +36,16 @@ void nr_rlc_entity_tm_recv_pdu(nr_rlc_entity_t *_entity, char *buffer, int size) { nr_rlc_entity_tm_t *entity = (nr_rlc_entity_tm_t *)_entity; + + entity->common.stats.rxpdu_pkts++; + entity->common.stats.rxpdu_bytes += size; + entity->common.deliver_sdu(entity->common.deliver_sdu_data, (nr_rlc_entity_t *)entity, buffer, size); + + entity->common.stats.txsdu_pkts++; + entity->common.stats.txsdu_bytes += size; } /*************************************************************************/ @@ -68,6 +75,9 @@ static int generate_tx_pdu(nr_rlc_entity_tm_t *entity, char *buffer, int size) memcpy(buffer, sdu->sdu->data, sdu->size); entity->tx_size -= sdu->size; + entity->common.stats.txpdu_pkts++; + entity->common.stats.txpdu_bytes += size; + /* update buffer status */ entity->common.bstatus.tx_size -= sdu->size; @@ -109,6 +119,9 @@ void nr_rlc_entity_tm_recv_sdu(nr_rlc_entity_t *_entity, nr_rlc_entity_tm_t *entity = (nr_rlc_entity_tm_t *)_entity; nr_rlc_sdu_segment_t *sdu; + entity->common.stats.rxsdu_pkts++; + entity->common.stats.rxsdu_bytes += size; + if (size > NR_SDU_MAX) { LOG_E(RLC, "%s:%d:%s: fatal: SDU size too big (%d bytes)\n", __FILE__, __LINE__, __FUNCTION__, size); @@ -118,6 +131,10 @@ void nr_rlc_entity_tm_recv_sdu(nr_rlc_entity_t *_entity, if (entity->tx_size + size > entity->tx_maxsize) { LOG_D(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n", __FILE__, __LINE__, __FUNCTION__); + + entity->common.stats.rxsdu_dd_pkts++; + entity->common.stats.rxsdu_dd_bytes += size; + return; } diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c index 5f2fd592a0..5a8c18a29b 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c @@ -179,6 +179,9 @@ static void reassemble_and_deliver(nr_rlc_entity_um_t *entity, int sn) entity->common.deliver_sdu(entity->common.deliver_sdu_data, (nr_rlc_entity_t *)entity, sdu, so); + + entity->common.stats.txsdu_pkts++; + entity->common.stats.txsdu_bytes += so; } static void reception_actions(nr_rlc_entity_um_t *entity, nr_rlc_pdu_t *pdu) @@ -208,6 +211,15 @@ static void reception_actions(nr_rlc_entity_um_t *entity, nr_rlc_pdu_t *pdu) nr_rlc_pdu_t *p = entity->rx_list; entity->rx_size -= p->size; entity->rx_list = p->next; + + entity->common.stats.rxpdu_dd_pkts++; + /* we don't count PDU header bytes here, so be it */ + entity->common.stats.rxpdu_dd_bytes += p->size; + + entity->common.stats.rxpdu_ow_pkts++; + /* we don't count PDU header bytes here, so be it */ + entity->common.stats.rxpdu_ow_bytes += p->size; + nr_rlc_free_pdu(p); } @@ -272,6 +284,9 @@ void nr_rlc_entity_um_recv_pdu(nr_rlc_entity_t *_entity, int is_first; int is_last; + entity->common.stats.rxpdu_pkts++; + entity->common.stats.rxpdu_bytes += size; + nr_rlc_pdu_decoder_init(&decoder, buffer, size); si = nr_rlc_pdu_decoder_get_bits(&decoder, 2); R(decoder); @@ -290,6 +305,10 @@ void nr_rlc_entity_um_recv_pdu(nr_rlc_entity_t *_entity, entity->common.deliver_sdu(entity->common.deliver_sdu_data, (nr_rlc_entity_t *)entity, buffer + 1, size - 1); + + entity->common.stats.txsdu_pkts++; + entity->common.stats.txsdu_bytes += size - 1; + return; } @@ -350,6 +369,9 @@ err: goto discard; discard: + entity->common.stats.rxpdu_dd_pkts++; + entity->common.stats.rxpdu_dd_bytes += size; + return; #undef R @@ -434,6 +456,8 @@ static nr_rlc_sdu_segment_t *resegment(nr_rlc_sdu_segment_t *sdu, next->so = sdu->so + sdu->size; next->is_first = 0; + entity->common.stats.txpdu_segmented++; + return next; } @@ -478,6 +502,8 @@ static int generate_tx_pdu(nr_rlc_entity_um_t *entity, char *buffer, int size) entity->tx_list = next_sdu; if (entity->tx_end == NULL) entity->tx_end = entity->tx_list; + + entity->common.stats.txpdu_segmented++; /* update buffer status */ entity->common.bstatus.tx_size += compute_pdu_header_size(entity, next_sdu) + next_sdu->size; @@ -492,6 +518,11 @@ static int generate_tx_pdu(nr_rlc_entity_um_t *entity, char *buffer, int size) entity->tx_size -= sdu->size; nr_rlc_free_sdu_segment(sdu); + entity->common.stats.txpdu_pkts++; + entity->common.stats.txpdu_bytes += size; + + + return ret; } @@ -527,6 +558,9 @@ void nr_rlc_entity_um_recv_sdu(nr_rlc_entity_t *_entity, nr_rlc_entity_um_t *entity = (nr_rlc_entity_um_t *)_entity; nr_rlc_sdu_segment_t *sdu; + entity->common.stats.rxsdu_pkts++; + entity->common.stats.rxsdu_bytes += size; + if (size > NR_SDU_MAX) { LOG_E(RLC, "%s:%d:%s: fatal: SDU size too big (%d bytes)\n", __FILE__, __LINE__, __FUNCTION__, size); @@ -536,6 +570,10 @@ void nr_rlc_entity_um_recv_sdu(nr_rlc_entity_t *_entity, if (entity->tx_size + size > entity->tx_maxsize) { LOG_W(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n", __FILE__, __LINE__, __FUNCTION__); + + entity->common.stats.rxsdu_dd_pkts++; + entity->common.stats.rxsdu_dd_bytes += size; + return; } @@ -584,6 +622,11 @@ static void check_t_reassembly(nr_rlc_entity_um_t *entity) nr_rlc_pdu_t *p = cur; cur = cur->next; entity->rx_list = cur; + + entity->common.stats.rxpdu_dd_pkts++; + /* we don't count PDU header bytes here, so be it */ + entity->common.stats.rxpdu_dd_bytes += p->size; + nr_rlc_free_pdu(p); } diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 4bd4ea75fd..94bb8bf141 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -1110,3 +1110,39 @@ void rlc_tick(int a, int b) __FILE__, __LINE__, __FUNCTION__); exit(1); } + +/* returns 0 in case of error, 1 if everything ok */ +int const nr_rlc_get_statistics( + int rnti, + int srb_flag, + int rb_id, + nr_rlc_statistics_t *out) +{ + nr_rlc_ue_t *ue; + nr_rlc_entity_t *rb; + int ret; + + nr_rlc_manager_lock(nr_rlc_ue_manager); + ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, rnti); + + rb = NULL; + + if (srb_flag) { + if (rb_id >= 1 && rb_id <= 2) + rb = ue->srb[rb_id - 1]; + } else { + if (rb_id >= 1 && rb_id <= 5) + rb = ue->drb[rb_id - 1]; + } + + if (rb != NULL) { + rb->get_stats(rb, out); + ret = 1; + } else { + ret = 0; + } + + nr_rlc_manager_unlock(nr_rlc_ue_manager); + + return ret; +}