From 7993385742b5772d5dbdbf20f5153294dca44ff8 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 23 Mar 2018 16:41:37 +0100 Subject: [PATCH 01/29] increase size of bytebuffer to compensate header, add helper to get remaining size --- lib/include/srslte/common/common.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index 8089634b7..de9f6d5aa 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -147,6 +147,11 @@ public: { return msg-buffer; } + // Returns the remaining space from what is reported to be the length of msg + uint32_t get_tailroom() + { + return (sizeof(buffer) - (msg-buffer) - N_bytes); + } long get_latency_us() { #ifdef ENABLE_TIMESTAMP From e7c74fa0f7858702b328dd91ab4b5edaa974b652 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 23 Mar 2018 16:46:28 +0100 Subject: [PATCH 02/29] add simple RLC PCAP writer --- lib/include/srslte/common/pcap.h | 150 +++++++++++++++++++++++++++ lib/include/srslte/common/rlc_pcap.h | 65 ++++++++++++ lib/src/common/rlc_pcap.cc | 90 ++++++++++++++++ 3 files changed, 305 insertions(+) create mode 100644 lib/include/srslte/common/rlc_pcap.h create mode 100644 lib/src/common/rlc_pcap.cc diff --git a/lib/include/srslte/common/pcap.h b/lib/include/srslte/common/pcap.h index ce4fcf541..823da662a 100644 --- a/lib/include/srslte/common/pcap.h +++ b/lib/include/srslte/common/pcap.h @@ -34,6 +34,7 @@ #define MAC_LTE_DLT 147 #define NAS_LTE_DLT 148 +#define RLC_LTE_DLT 149 // UDP needs to be selected as protocol /* This structure gets written to the start of the file */ @@ -104,6 +105,67 @@ typedef struct NAS_Context_Info_s { } NAS_Context_Info_t; +/* RLC-LTE disector */ + +/* rlcMode */ +#define RLC_TM_MODE 1 +#define RLC_UM_MODE 2 +#define RLC_AM_MODE 4 +#define RLC_PREDEF 8 + +/* priority ? */ + +/* channelType */ +#define CHANNEL_TYPE_CCCH 1 +#define CHANNEL_TYPE_BCCH_BCH 2 +#define CHANNEL_TYPE_PCCH 3 +#define CHANNEL_TYPE_SRB 4 +#define CHANNEL_TYPE_DRB 5 +#define CHANNEL_TYPE_BCCH_DL_SCH 6 +#define CHANNEL_TYPE_MCCH 7 +#define CHANNEL_TYPE_MTCH 8 + +/* sequenceNumberLength */ +#define UM_SN_LENGTH_5_BITS 5 +#define UM_SN_LENGTH_10_BITS 10 +#define AM_SN_LENGTH_10_BITS 10 +#define AM_SN_LENGTH_16_BITS 16 + +/* Narrow band mode */ +typedef enum { + rlc_no_nb_mode = 0, + rlc_nb_mode = 1 +} rlc_lte_nb_mode; + +/* Context information for every RLC PDU that will be logged */ +typedef struct { + unsigned char rlcMode; + unsigned char direction; + unsigned char priority; + unsigned char sequenceNumberLength; + unsigned short ueid; + unsigned short channelType; + unsigned short channelId; /* for SRB: 1=SRB1, 2=SRB2, 3=SRB1bis; for DRB: DRB ID */ + unsigned short pduLength; + bool extendedLiField; + rlc_lte_nb_mode nbMode; +} RLC_Context_Info_t; + + +// See Wireshark's packet-rlc-lte.h for details +#define RLC_LTE_START_STRING "rlc-lte" +#define RLC_LTE_SN_LENGTH_TAG 0x02 +#define RLC_LTE_DIRECTION_TAG 0x03 +#define RLC_LTE_PRIORITY_TAG 0x04 +#define RLC_LTE_UEID_TAG 0x05 +#define RLC_LTE_CHANNEL_TYPE_TAG 0x06 +#define RLC_LTE_CHANNEL_ID_TAG 0x07 +#define RLC_LTE_EXT_LI_FIELD_TAG 0x08 +#define RLC_LTE_NB_MODE_TAG 0x09 +#define RLC_LTE_PAYLOAD_TAG 0x01 + + + /************************************************************************** * API functions for opening/closing LTE PCAP files * **************************************************************************/ @@ -247,4 +309,92 @@ inline int LTE_PCAP_NAS_WritePDU(FILE *fd, NAS_Context_Info_t *context, return 1; } +/************************************************************************** + * API functions for writing RLC-LTE PCAP files * + **************************************************************************/ + +/* Write an individual RLC PDU (PCAP packet header + UDP header + rlc-context + rlc-pdu) */ +inline int LTE_PCAP_RLC_WritePDU(FILE *fd, RLC_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) +{ + pcaprec_hdr_t packet_header; + char context_header[256]; + int offset = 0; + uint16_t tmp16; + + /* Can't write if file wasn't successfully opened */ + if (fd == NULL) { + printf("Error: Can't write to empty file handle\n"); + return 0; + } + + /*****************************************************************/ + + // Add dummy UDP header, start with src and dest port + context_header[offset++] = 0xde; + context_header[offset++] = 0xad; + context_header[offset++] = 0xbe; + context_header[offset++] = 0xef; + // length + tmp16 = length + 12; + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + // dummy CRC + context_header[offset++] = 0xde; + context_header[offset++] = 0xad; + + // Start magic string + memcpy(&context_header[offset], RLC_LTE_START_STRING, strlen(RLC_LTE_START_STRING)); + offset += strlen(RLC_LTE_START_STRING); + + // Fixed field RLC mode + context_header[offset++] = context->rlcMode; + + // Conditional fields + if (context->rlcMode == RLC_UM_MODE) { + context_header[offset++] = RLC_LTE_SN_LENGTH_TAG; + context_header[offset++] = context->sequenceNumberLength; + } + + // Optional fields + context_header[offset++] = RLC_LTE_DIRECTION_TAG; + context_header[offset++] = context->direction; + + context_header[offset++] = RLC_LTE_PRIORITY_TAG; + context_header[offset++] = context->priority; + + context_header[offset++] = RLC_LTE_UEID_TAG; + tmp16 = htons(context->ueid); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + context_header[offset++] = RLC_LTE_CHANNEL_TYPE_TAG; + tmp16 = htons(context->channelType); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + context_header[offset++] = RLC_LTE_CHANNEL_ID_TAG; + tmp16 = htons(context->channelId); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + // Now the actual PDU + context_header[offset++] = RLC_LTE_PAYLOAD_TAG; + + // PCAP header + struct timeval t; + gettimeofday(&t, NULL); + packet_header.ts_sec = t.tv_sec; + packet_header.ts_usec = t.tv_usec; + packet_header.incl_len = offset + length; + packet_header.orig_len = offset + length; + + // Write everything to file + fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd); + fwrite(context_header, 1, offset, fd); + fwrite(PDU, 1, length, fd); + + return 1; +} + #endif /* UEPCAP_H */ diff --git a/lib/include/srslte/common/rlc_pcap.h b/lib/include/srslte/common/rlc_pcap.h new file mode 100644 index 000000000..3a506f6ef --- /dev/null +++ b/lib/include/srslte/common/rlc_pcap.h @@ -0,0 +1,65 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef RLCPCAP_H +#define RLCPCAP_H + +#include +#include "srslte/common/pcap.h" + +namespace srslte { + +class rlc_pcap +{ +public: + rlc_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; }; + void enable(bool en); + void open(const char *filename, uint32_t ue_id = 0); + void close(); + + void set_ue_id(uint16_t ue_id); + + void write_dl_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes); + void write_ul_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes); + +private: + bool enable_write; + FILE *pcap_file; + uint32_t ue_id; + void pack_and_write(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint8_t mode, + uint8_t direction, + uint8_t priority, + uint8_t seqnumberlength, + uint16_t ueid, + uint16_t channel_type, + uint16_t channel_id); +}; + +} // namespace srsue + +#endif // RLCPCAP_H diff --git a/lib/src/common/rlc_pcap.cc b/lib/src/common/rlc_pcap.cc new file mode 100644 index 000000000..e6bcbe642 --- /dev/null +++ b/lib/src/common/rlc_pcap.cc @@ -0,0 +1,90 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#include +#include "srslte/srslte.h" +#include "srslte/common/pcap.h" +#include "srslte/common/rlc_pcap.h" + +namespace srslte { + +void rlc_pcap::enable(bool en) +{ + enable_write = true; +} +void rlc_pcap::open(const char* filename, uint32_t ue_id) +{ + fprintf(stdout, "Opening RLC PCAP with DLT=%d\n", RLC_LTE_DLT); + pcap_file = LTE_PCAP_Open(RLC_LTE_DLT, filename); + this->ue_id = ue_id; + enable_write = true; +} +void rlc_pcap::close() +{ + fprintf(stdout, "Saving RLC PCAP file\n"); + LTE_PCAP_Close(pcap_file); +} + +void rlc_pcap::set_ue_id(uint16_t ue_id) { + this->ue_id = ue_id; +} + +void rlc_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint8_t mode, uint8_t direction, uint8_t priority, uint8_t seqnumberlength, uint16_t ueid, uint16_t channel_type, uint16_t channel_id) +{ + if (enable_write) { + RLC_Context_Info_t context; + context.rlcMode = mode; + context.direction = direction; + context.priority = priority; + context.sequenceNumberLength = seqnumberlength; + context.ueid = ueid; + context.channelType = channel_type; + context.channelId = channel_id; + context.pduLength = pdu_len_bytes; + if (pdu) { + LTE_PCAP_RLC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + } + } +} + +void rlc_pcap::write_dl_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes) +{ + uint8_t priority = 0; + uint8_t seqnumberlength = 0; // normal length of 10bit + uint8_t channel_id = 0; + pack_and_write(pdu, pdu_len_bytes, RLC_AM_MODE, DIRECTION_DOWNLINK, priority, seqnumberlength, ue_id, CHANNEL_TYPE_CCCH, channel_id); +} + +void rlc_pcap::write_ul_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes) +{ + uint8_t priority = 0; + uint8_t seqnumberlength = 0; // normal length of 10bit + uint8_t channel_id = 0; + pack_and_write(pdu, pdu_len_bytes, RLC_AM_MODE, DIRECTION_UPLINK, priority, seqnumberlength, ue_id, CHANNEL_TYPE_CCCH, channel_id); +} + +} From 20fa7b947df18e58a6346962af8db5498f47c77d Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 23 Mar 2018 17:20:12 +0100 Subject: [PATCH 03/29] expos various params of stress tester and add pcap functionality --- lib/test/upper/rlc_am_stress_test.cc | 80 ++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/lib/test/upper/rlc_am_stress_test.cc b/lib/test/upper/rlc_am_stress_test.cc index fb83e4cfd..52d4176de 100644 --- a/lib/test/upper/rlc_am_stress_test.cc +++ b/lib/test/upper/rlc_am_stress_test.cc @@ -30,10 +30,14 @@ #include "srslte/common/log_filter.h" #include "srslte/common/logger_stdout.h" #include "srslte/common/threads.h" +#include "srslte/common/rlc_pcap.h" #include "srslte/upper/rlc.h" #include #include #include +#include + +#define SDU_SIZE 1500 using namespace std; using namespace srsue; @@ -47,8 +51,13 @@ typedef struct { uint32_t pdu_tx_delay_usec; bool reestablish; uint32_t log_level; + bool single_tx; + bool write_pcap; + float opp_sdu_ratio; } stress_test_args_t; +boost::mutex mutex; + void parse_args(stress_test_args_t *args, int argc, char *argv[]) { // Command line only options @@ -65,8 +74,11 @@ void parse_args(stress_test_args_t *args, int argc, char *argv[]) { ("sdu_gen_delay", bpo::value(&args->sdu_gen_delay_usec)->default_value(10), "SDU generation delay (usec)") ("pdu_tx_delay", bpo::value(&args->pdu_tx_delay_usec)->default_value(10), "Delay in MAC for transfering PDU from tx'ing RLC to rx'ing RLC (usec)") ("error_rate", bpo::value(&args->error_rate)->default_value(0.1), "Rate at which RLC PDUs are dropped") + ("opp_sdu_ratio", bpo::value(&args->opp_sdu_ratio)->default_value(0.0), "Ratio between MAC opportunity and SDU size (0==random)") ("reestablish", bpo::value(&args->reestablish)->default_value(false), "Mimic RLC reestablish during execution") - ("loglevel", bpo::value(&args->log_level)->default_value(srslte::LOG_LEVEL_DEBUG), "Log level (1=Error,2=Warning,3=Info,4=Debug"); + ("loglevel", bpo::value(&args->log_level)->default_value(srslte::LOG_LEVEL_DEBUG), "Log level (1=Error,2=Warning,3=Info,4=Debug)") + ("singletx", bpo::value(&args->single_tx)->default_value(false), "If set to true, only one node is generating data") + ("pcap", bpo::value(&args->write_pcap)->default_value(false), "Whether to write all RLC PDU to PCAP file"); // these options are allowed on the command line bpo::options_description cmdline_options; @@ -94,14 +106,17 @@ class mac_reader :public thread { public: - mac_reader(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, uint32_t pdu_tx_delay_usec_) + mac_reader(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, float opp_sdu_ratio_, uint32_t pdu_tx_delay_usec_, rlc_pcap *pcap_, bool is_dl_ = true) { rlc1 = rlc1_; rlc2 = rlc2_; fail_rate = fail_rate_; + opp_sdu_ratio = opp_sdu_ratio_; run_enable = true; running = false; pdu_tx_delay_usec = pdu_tx_delay_usec_; + pcap = pcap_; + is_dl = is_dl_; } void stop() @@ -129,14 +144,25 @@ private: } while(run_enable) { - float r = (float)rand()/RAND_MAX; - int opp_size = r*1500; - rlc1->get_buffer_state(1); - int read = rlc1->read_pdu(1, pdu->msg, opp_size); - if(((float)rand()/RAND_MAX > fail_rate) && read>0) { - rlc2->write_pdu(1, pdu->msg, opp_size); + // generate MAC opportunities of random size or with fixed ratio + float r = opp_sdu_ratio ? opp_sdu_ratio : (float)rand()/RAND_MAX; + int opp_size = r*SDU_SIZE; + mutex.lock(); + uint32_t buf_state = rlc1->get_buffer_state(1); + if (buf_state) { + int read = rlc1->read_pdu(1, pdu->msg, opp_size); + usleep(pdu_tx_delay_usec); + if(((float)rand()/RAND_MAX > fail_rate) && read>0) { + pdu->N_bytes = read; + rlc2->write_pdu(1, pdu->msg, pdu->N_bytes); + if (is_dl) { + pcap->write_dl_am_ccch(pdu->msg, pdu->N_bytes); + } else { + pcap->write_ul_am_ccch(pdu->msg, pdu->N_bytes); + } + } } - usleep(pdu_tx_delay_usec); + mutex.unlock(); } running = false; byte_buffer_pool::get_instance()->deallocate(pdu); @@ -145,7 +171,10 @@ private: rlc_interface_mac *rlc1; rlc_interface_mac *rlc2; float fail_rate; + float opp_sdu_ratio; uint32_t pdu_tx_delay_usec; + rlc_pcap *pcap; + bool is_dl; bool run_enable; bool running; @@ -155,9 +184,9 @@ class mac_dummy :public srslte::mac_interface_timers { public: - mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, uint32_t pdu_tx_delay) - :r1(rlc1_, rlc2_, fail_rate_, pdu_tx_delay) - ,r2(rlc2_, rlc1_, fail_rate_, pdu_tx_delay) + mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, float opp_sdu_ratio_, int32_t pdu_tx_delay, rlc_pcap* pcap = NULL) + :r1(rlc1_, rlc2_, fail_rate_, opp_sdu_ratio_, pdu_tx_delay, pcap, true) + ,r2(rlc2_, rlc1_, fail_rate_, opp_sdu_ratio_, pdu_tx_delay, pcap, false) { } @@ -222,6 +251,7 @@ public: void write_pdu(uint32_t lcid, byte_buffer_t *sdu) { assert(lcid == 1); + assert(sdu->N_bytes==SDU_SIZE); byte_buffer_pool::get_instance()->deallocate(sdu); std::cout << "rlc_am_tester " << name << " received " << rx_pdus++ << " PDUs" << std::endl; } @@ -244,8 +274,11 @@ private: printf("Fatal Error: Could not allocate PDU in rlc_am_tester::run_thread\n"); exit(-1); } - pdu->N_bytes = 1500; - pdu->msg[0] = sn++; + for (uint32_t i = 0; i < SDU_SIZE; i++) { + pdu->msg[i] = sn; + } + sn++; + pdu->N_bytes = SDU_SIZE; rlc->write_sdu(1, pdu); usleep(sdu_gen_delay_usec); } @@ -271,13 +304,18 @@ void stress_test(stress_test_args_t args) log2.set_level((LOG_LEVEL_ENUM)args.log_level); log1.set_hex_limit(-1); log2.set_hex_limit(-1); + rlc_pcap pcap; + + if (args.write_pcap) { + pcap.open("rlc_stress_test.pcap", 0); + } rlc rlc1; rlc rlc2; rlc_am_tester tester1(&rlc1, "tester1", args.sdu_gen_delay_usec); rlc_am_tester tester2(&rlc2, "tester2", args.sdu_gen_delay_usec); - mac_dummy mac(&rlc1, &rlc2, args.error_rate, args.pdu_tx_delay_usec); + mac_dummy mac(&rlc1, &rlc2, args.error_rate, args.opp_sdu_ratio, args.pdu_tx_delay_usec, &pcap); ue_interface ue; rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0); @@ -298,14 +336,21 @@ void stress_test(stress_test_args_t args) rlc2.add_bearer(1, cnfg_); tester1.start(7); - tester2.start(7); + if (!args.single_tx) { + tester2.start(7); + } mac.start(); for (uint32_t i = 0; i < args.test_duration_sec; i++) { // if enabled, mimic reestablishment every second if (args.reestablish) { + // lock mutex during reestablish to prevent a RLC PDU that is already been transmitted before + // resetting the tx'ing RLC entity, but not yet received before resetting the + // rx'ing RLC entity to screw the test + mutex.lock(); rlc1.reestablish(); rlc2.reestablish(); + mutex.unlock(); } usleep(1e6); } @@ -313,6 +358,9 @@ void stress_test(stress_test_args_t args) tester1.stop(); tester2.stop(); mac.stop(); + if (args.write_pcap) { + pcap.close(); + } } From 5fe09666d7acce94edba724b7af888a0c5f83535 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 26 Mar 2018 16:33:45 +0200 Subject: [PATCH 04/29] add new RLC AM test for retransmitted PDU segments --- lib/test/upper/rlc_am_test.cc | 141 ++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index 67305c093..8bef90334 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -1056,6 +1056,144 @@ void resegment_test_6() } } +void resegment_test_7() +{ + // SDUs: | 30 | 30 | + // PDUs: | 15 | 15 | 15 | 15 | 15 | + // Rxed PDUs | 15 | | 15 | 15 | + // Retx PDU segments: | 7 | 7 | 7 | 7 | + // Retx PDU segments: | 7 | 7 ] 7 | 7 | 7 | 7 | 7 | 7 | + const uint32_t N_SDU_BUFS = 2; + const uint32_t N_PDU_BUFS = 5; + const uint32_t sdu_size = 30; + + srslte::log_filter log1("RLC_AM_1"); + srslte::log_filter log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(100); + log2.set_hex_limit(100); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 2 SDUs into RLC1 + byte_buffer_t sdu_bufs[N_SDU_BUFS]; + for(uint32_t i=0;i 2) { + rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); + } + } + + // Sleep to let reordering timeout expire + usleep(10000); + + //assert(5 == rlc2.get_buffer_state()); + + // Read status PDU from RLC2 + byte_buffer_t status_buf; + len = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + status_buf.N_bytes = len; + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + assert(12 == rlc1.get_buffer_state()); + + // first round of retx, forcing resegmentation + byte_buffer_t retx[4]; + for (uint32_t i = 0; i < 4; i++) { + assert(rlc1.get_buffer_state()); + retx[i].N_bytes = rlc1.read_pdu(retx[i].msg, 7); + assert(retx[i].N_bytes); + + // Write the last two segments to RLC2 + if (i > 1) { + rlc2.write_pdu(retx[i].msg, retx[i].N_bytes); + } + } + + usleep(10000); + + // Read status PDU from RLC2 + //byte_buffer_t status_buf; + assert(rlc2.get_buffer_state()); + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + assert(15 == rlc1.get_buffer_state()); + + // second round of retx, forcing resegmentation + byte_buffer_t retx2[9]; + for (uint32_t i = 0; i < 9; i++) { + assert(rlc1.get_buffer_state() != 0); + retx2[i].N_bytes = rlc1.read_pdu(retx2[i].msg, 7); + assert(retx2[i].N_bytes != 0); + rlc2.write_pdu(retx2[i].msg, retx2[i].N_bytes); + } + + // check buffer states + assert(0 == rlc1.get_buffer_state()); + assert(0 == rlc2.get_buffer_state()); + + // Check number of SDUs and their content + assert(tester.n_sdus == N_SDU_BUFS); + for(int i=0; iN_bytes == sdu_size); + for(uint32_t j=0;jmsg[j] == i); + } + } +} + + void reset_test() { srslte::log_filter log1("RLC_AM_1"); @@ -1141,6 +1279,9 @@ int main(int argc, char **argv) { resegment_test_6(); byte_buffer_pool::get_instance()->cleanup(); + resegment_test_7(); + byte_buffer_pool::get_instance()->cleanup(); + reset_test(); byte_buffer_pool::get_instance()->cleanup(); } From a16aa291e388df485a249d050f807775b19d42c6 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 27 Mar 2018 21:33:26 +0200 Subject: [PATCH 05/29] protect memcpy's in rx sdu reassembly with boundary checks --- lib/src/upper/rlc_am.cc | 75 +++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 5c7cb72ea..d100508d1 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -128,10 +128,10 @@ void rlc_am::reset() reordering_timeout.reset(); if(tx_sdu) { pool->deallocate(tx_sdu); - tx_sdu = NULL; } - if(rx_sdu) - rx_sdu->reset(); + if(rx_sdu) { + pool->deallocate(rx_sdu); + } vt_a = 0; vt_ms = RLC_AM_WINDOW_SIZE; @@ -827,6 +827,12 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len); } + // Make sure, at least one SDU (segment) has been added until this point + if (pdu->N_bytes == 0) { + log->error("Generated empty RLC PDU.\n"); + return 0; + } + if(tx_sdu) header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU @@ -848,7 +854,6 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) // Set SN header.sn = vt_s; vt_s = (vt_s + 1)%MOD; - log->info("%s PDU scheduled for tx. SN: %d (%d B)\n", rrc->get_rb_name(lcid).c_str(), header.sn, pdu->N_bytes); // Place PDU in tx_window, write header and TX tx_window[header.sn].buf = pdu; @@ -859,6 +864,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint8_t *ptr = payload; rlc_am_write_data_pdu_header(&header, &ptr); memcpy(ptr, pdu->msg, pdu->N_bytes); + log->info_hex(payload, pdu->N_bytes, "%s PDU scheduled for tx. SN: %d (%d B)\n", rrc->get_rb_name(lcid).c_str(), header.sn, pdu->N_bytes); debug_state(); return (ptr-payload) + pdu->N_bytes; @@ -868,8 +874,8 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h { std::map::iterator it; - log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d", - rrc->get_rb_name(lcid).c_str(), header.sn); + log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d (%d B), %s", + rrc->get_rb_name(lcid).c_str(), header.sn, nof_bytes, rlc_fi_field_text[header.fi]); if(!inside_rx_window(header.sn)) { if(header.p) { @@ -1157,38 +1163,55 @@ void rlc_am::reassemble_rx_sdus() #endif } } + // Iterate through rx_window, assembling and delivering SDUs while(rx_window.end() != rx_window.find(vr_r)) { // Handle any SDU segments for(uint32_t i=0; imsg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, len); - rx_sdu->N_bytes += len; - rx_window[vr_r].buf->msg += len; - rx_window[vr_r].buf->N_bytes -= len; - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str()); - rx_sdu->set_timestamp(); - pdcp->write_pdu(lcid, rx_sdu); - rx_sdu = pool_allocate; - if (!rx_sdu) { + uint32_t len = rx_window[vr_r].header.li[i]; + if (rx_sdu->get_tailroom() >= len) { + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, len); + rx_sdu->N_bytes += len; + rx_window[vr_r].buf->msg += len; + rx_window[vr_r].buf->N_bytes -= len; + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", rrc->get_rb_name(lcid).c_str(), rx_sdu->N_bytes); + rx_sdu->set_timestamp(); + pdcp->write_pdu(lcid, rx_sdu); + + rx_sdu = pool_allocate; + if (!rx_sdu) { #ifdef RLC_AM_BUFFER_DEBUG - log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n"); - exit(-1); + log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n"); + exit(-1); #else - log->error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n"); - return; + log->error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n"); + return; #endif + } + } else { + log->error("Cannot fit RLC PDU in SDU buffer, dropping both.\n"); + pool->deallocate(rx_sdu); + pool->deallocate(rx_window[vr_r].buf); + rx_window.erase(vr_r); } } // Handle last segment - memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, rx_window[vr_r].buf->N_bytes); - rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes; - if(rlc_am_end_aligned(rx_window[vr_r].header.fi)) - { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str()); + uint32_t len = rx_window[vr_r].buf->N_bytes; + if (rx_sdu->get_tailroom() >= len) { + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, len); + rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes; + } else { + log->error("Cannot fit RLC PDU in SDU buffer, dropping both.\n"); + pool->deallocate(rx_sdu); + pool->deallocate(rx_window[vr_r].buf); + rx_window.erase(vr_r); + } + + if(rlc_am_end_aligned(rx_window[vr_r].header.fi)) { + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", rrc->get_rb_name(lcid).c_str(), rx_sdu->N_bytes); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -1250,7 +1273,7 @@ void rlc_am::print_rx_segments() for(it=rx_segments.begin();it!=rx_segments.end();it++) { std::list::iterator segit; for(segit = it->second.segments.begin(); segit != it->second.segments.end(); segit++) { - ss << " SN:" << segit->header.sn << " SO:" << segit->header.so << " N:" << segit->buf->N_bytes << std::endl; + ss << " SN:" << segit->header.sn << " SO:" << segit->header.so << " N:" << segit->buf->N_bytes << " N_li: " << segit->header.N_li << std::endl; } } log->debug("%s\n", ss.str().c_str()); From 619a653d4ea18d2f360b3b372af5fcdda37b05f0 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 28 Mar 2018 16:06:28 +0200 Subject: [PATCH 06/29] add another RLC AM resegment test --- lib/test/upper/rlc_am_test.cc | 200 +++++++++++++++++++++++++++++++--- 1 file changed, 187 insertions(+), 13 deletions(-) diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index 8bef90334..ffe010ec8 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -28,8 +28,10 @@ #include "srslte/common/log_filter.h" #include "srslte/common/logger_stdout.h" #include "srslte/upper/rlc_am.h" +#include "srslte/common/rlc_pcap.h" #include #define NBUFS 5 +#define HAVE_PCAP 0 using namespace srsue; using namespace srslte; @@ -54,9 +56,11 @@ class rlc_am_tester ,public rrc_interface_rlc { public: - rlc_am_tester(){ + rlc_am_tester(rlc_pcap *pcap_ = NULL) + { bzero(sdus, sizeof(sdus)); n_sdus = 0; + pcap = pcap_; } ~rlc_am_tester(){ @@ -83,6 +87,7 @@ public: byte_buffer_t *sdus[10]; int n_sdus; + rlc_pcap *pcap; }; void basic_test() @@ -1056,6 +1061,7 @@ void resegment_test_6() } } +// Retransmission of PDU segments of the same size void resegment_test_7() { // SDUs: | 30 | 30 | @@ -1073,7 +1079,14 @@ void resegment_test_7() log2.set_level(srslte::LOG_LEVEL_DEBUG); log1.set_hex_limit(100); log2.set_hex_limit(100); - rlc_am_tester tester; + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_test7.pcap", 0); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif mac_dummy_timers timers; rlc_am rlc1; @@ -1126,22 +1139,15 @@ void resegment_test_7() for(uint32_t i=0;i 2) { rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); +#if HAVE_PCAP + pcap.write_dl_am_ccch(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); +#endif } } // Sleep to let reordering timeout expire usleep(10000); - //assert(5 == rlc2.get_buffer_state()); - - // Read status PDU from RLC2 - byte_buffer_t status_buf; - len = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status - status_buf.N_bytes = len; - - // Write status PDU to RLC1 - rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); - assert(12 == rlc1.get_buffer_state()); // first round of retx, forcing resegmentation @@ -1154,18 +1160,24 @@ void resegment_test_7() // Write the last two segments to RLC2 if (i > 1) { rlc2.write_pdu(retx[i].msg, retx[i].N_bytes); +#if HAVE_PCAP + pcap.write_dl_am_ccch(retx[i].msg, retx[i].N_bytes); +#endif } } usleep(10000); // Read status PDU from RLC2 - //byte_buffer_t status_buf; assert(rlc2.get_buffer_state()); + byte_buffer_t status_buf; status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); +#if HAVE_PCAP + pcap.write_ul_am_ccch(status_buf.msg, status_buf.N_bytes); +#endif assert(15 == rlc1.get_buffer_state()); @@ -1175,7 +1187,11 @@ void resegment_test_7() assert(rlc1.get_buffer_state() != 0); retx2[i].N_bytes = rlc1.read_pdu(retx2[i].msg, 7); assert(retx2[i].N_bytes != 0); + rlc2.write_pdu(retx2[i].msg, retx2[i].N_bytes); +#if HAVE_PCAP + pcap.write_dl_am_ccch(retx[i].msg, retx[i].N_bytes); +#endif } // check buffer states @@ -1191,6 +1207,161 @@ void resegment_test_7() assert(tester.sdus[i]->msg[j] == i); } } + +#if HAVE_PCAP + pcap.close(); +#endif +} + + +// Retransmission of PDU segments with different size +void resegment_test_8() +{ + // SDUs: | 30 | 30 | + // PDUs: | 15 | 15 | 15 | 15 | 15 | + // Rxed PDUs | 15 | | 15 | 15 | + // Retx PDU segments: | 7 | 7 | 7 | 7 | + // Retx PDU segments: | 6 | 6 ] 6 | 6 | 6 | 6 | 6 | 6 | + const uint32_t N_SDU_BUFS = 2; + const uint32_t N_PDU_BUFS = 5; + const uint32_t sdu_size = 30; + + srslte::log_filter log1("RLC_AM_1"); + srslte::log_filter log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(100); + log2.set_hex_limit(100); + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_test8.pcap", 0); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 2 SDUs into RLC1 + byte_buffer_t sdu_bufs[N_SDU_BUFS]; + for(uint32_t i=0;i 2) { + rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); +#if HAVE_PCAP + pcap.write_dl_am_ccch(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); +#endif + } + } + + // Sleep to let reordering timeout expire + usleep(10000); + + assert(12 == rlc1.get_buffer_state()); + + // first round of retx, forcing resegmentation + byte_buffer_t retx[4]; + for (uint32_t i = 0; i < 4; i++) { + assert(rlc1.get_buffer_state()); + retx[i].N_bytes = rlc1.read_pdu(retx[i].msg, 7); + assert(retx[i].N_bytes); + + // Write the last two segments to RLC2 + if (i > 1) { + rlc2.write_pdu(retx[i].msg, retx[i].N_bytes); +#if HAVE_PCAP + pcap.write_dl_am_ccch(retx[i].msg, retx[i].N_bytes); +#endif + } + } + + usleep(20000); + + // Read status PDU from RLC2 + assert(rlc2.get_buffer_state()); + byte_buffer_t status_buf; + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); +#if HAVE_PCAP + pcap.write_ul_am_ccch(status_buf.msg, status_buf.N_bytes); +#endif + + assert(15 == rlc1.get_buffer_state()); + + // second round of retx, reduce grant size to force different segment sizes + byte_buffer_t retx2[20]; + for (uint32_t i = 0; i < 13; i++) { + assert(rlc1.get_buffer_state() != 0); + retx2[i].N_bytes = rlc1.read_pdu(retx2[i].msg, 6); + assert(retx2[i].N_bytes != 0); + rlc2.write_pdu(retx2[i].msg, retx2[i].N_bytes); +#if HAVE_PCAP + pcap.write_dl_am_ccch(retx[i].msg, retx[i].N_bytes); +#endif + } + + // check buffer states + assert(0 == rlc1.get_buffer_state()); + assert(0 == rlc2.get_buffer_state()); + + // Check number of SDUs and their content + assert(tester.n_sdus == N_SDU_BUFS); + for(int i=0; iN_bytes == sdu_size); + for(uint32_t j=0;jmsg[j] == i); + } + } + +#if HAVE_PCAP + pcap.close(); +#endif } @@ -1282,6 +1453,9 @@ int main(int argc, char **argv) { resegment_test_7(); byte_buffer_pool::get_instance()->cleanup(); + resegment_test_8(); + byte_buffer_pool::get_instance()->cleanup(); + reset_test(); byte_buffer_pool::get_instance()->cleanup(); } From 4b90852170d2d8da36c83a444216e92400892f5c Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 28 Mar 2018 17:07:10 +0200 Subject: [PATCH 07/29] add RLC AM FI field helpers --- lib/include/srslte/upper/rlc_am.h | 6 ++++-- lib/src/upper/rlc_am.cc | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/include/srslte/upper/rlc_am.h b/lib/include/srslte/upper/rlc_am.h index 7601baefa..b5d71eb55 100644 --- a/lib/include/srslte/upper/rlc_am.h +++ b/lib/include/srslte/upper/rlc_am.h @@ -217,8 +217,10 @@ bool rlc_am_is_control_pdu(byte_buffer_t *pdu); bool rlc_am_is_control_pdu(uint8_t *payload); bool rlc_am_is_pdu_segment(uint8_t *payload); std::string rlc_am_to_string(rlc_status_pdu_t *status); -bool rlc_am_start_aligned(uint8_t fi); -bool rlc_am_end_aligned(uint8_t fi); +bool rlc_am_start_aligned(const uint8_t fi); +bool rlc_am_end_aligned(const uint8_t fi); +bool rlc_am_is_unaligned(const uint8_t fi); +bool rlc_am_not_start_aligned(const uint8_t fi); } // namespace srsue diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index d100508d1..8c3e944bc 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -1739,14 +1739,24 @@ std::string rlc_am_to_string(rlc_status_pdu_t *status) return ss.str(); } -bool rlc_am_start_aligned(uint8_t fi) +bool rlc_am_start_aligned(const uint8_t fi) { return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_END_ALIGNED); } -bool rlc_am_end_aligned(uint8_t fi) +bool rlc_am_end_aligned(const uint8_t fi) { return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_START_ALIGNED); } +bool rlc_am_is_unaligned(const uint8_t fi) +{ + return (fi == RLC_FI_FIELD_NOT_START_OR_END_ALIGNED); +} + +bool rlc_am_not_start_aligned(const uint8_t fi) +{ + return (fi == RLC_FI_FIELD_NOT_START_ALIGNED || fi == RLC_FI_FIELD_NOT_START_OR_END_ALIGNED); +} + } // namespace srsue From f3482445b53ade2658bec36ac802093c29390872 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 28 Mar 2018 17:10:56 +0200 Subject: [PATCH 08/29] add RLC AM data header parsing test --- lib/test/upper/rlc_am_data_test.cc | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/test/upper/rlc_am_data_test.cc b/lib/test/upper/rlc_am_data_test.cc index d2dfe5949..ad3146582 100644 --- a/lib/test/upper/rlc_am_data_test.cc +++ b/lib/test/upper/rlc_am_data_test.cc @@ -40,6 +40,20 @@ uint32_t PDU2_LEN = 5; uint8_t pdu3[] = {0x8C, 0x00, 0xDD, 0xCD, 0xDC, 0x5D, 0xC0}; uint32_t PDU3_LEN = 7; +// D/C = 1 = Data PDU +// RF = 0 = AMD PDU +// P = 0 = Status PDU is not requested +// FI = 11 = First byte of the Data field does not corresponds to the first byte of a RLC SDU, +// Last byte of the Data field does not corresponds to the last byte of a RLC SDU +// E = 1 = A set of E field and LI field follows from the octet following the fixed part of the header +// SN = 0000000010 -> SN 2 +// E = 1 +// LI1 = 1010011 1110 (1342 Dec) +// E = 0 +// LI2 = 10111011100 (1500 Dec) +uint8_t pdu4[] = {0x9C, 0x02, 0xD3, 0xE5, 0xDC }; +uint32_t PDU4_LEN = 5; + using namespace srslte; int main(int argc, char **argv) { @@ -106,4 +120,26 @@ int main(int argc, char **argv) { assert(b2.N_bytes == PDU3_LEN); for(uint32_t i=0;i Date: Tue, 3 Apr 2018 12:16:22 +0200 Subject: [PATCH 09/29] add missing const keyword to log_filter's members --- lib/include/srslte/common/log.h | 8 ++++---- lib/include/srslte/common/log_filter.h | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/include/srslte/common/log.h b/lib/include/srslte/common/log.h index 7d8f0a8cd..b47f79d90 100644 --- a/lib/include/srslte/common/log.h +++ b/lib/include/srslte/common/log.h @@ -129,13 +129,13 @@ public: virtual void debug(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0; // Same with hex dump - virtual void error_hex(uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) + virtual void error_hex(const uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) {error("error_hex not implemented.\n");} - virtual void warning_hex(uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) + virtual void warning_hex(const uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) {error("warning_hex not implemented.\n");} - virtual void info_hex(uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) + virtual void info_hex(const uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) {error("info_hex not implemented.\n");} - virtual void debug_hex(uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) + virtual void debug_hex(const uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) {error("debug_hex not implemented.\n");} protected: diff --git a/lib/include/srslte/common/log_filter.h b/lib/include/srslte/common/log_filter.h index ea739082a..1296fbbbd 100644 --- a/lib/include/srslte/common/log_filter.h +++ b/lib/include/srslte/common/log_filter.h @@ -57,16 +57,16 @@ public: void init(std::string layer, logger *logger_, bool tti=false); - void console(const char * message, ...); - void error(const char * message, ...); - void warning(const char * message, ...); - void info(const char * message, ...); - void debug(const char * message, ...); + void console(const char * message, ...) __attribute__ ((format (printf, 2, 3))); + void error(const char * message, ...) __attribute__ ((format (printf, 2, 3))); + void warning(const char * message, ...) __attribute__ ((format (printf, 2, 3))); + void info(const char * message, ...) __attribute__ ((format (printf, 2, 3))); + void debug(const char * message, ...) __attribute__ ((format (printf, 2, 3))); - void error_hex(const uint8_t *hex, int size, const char * message, ...); - void warning_hex(const uint8_t *hex, int size, const char * message, ...); - void info_hex(const uint8_t *hex, int size, const char * message, ...); - void debug_hex(const uint8_t *hex, int size, const char * message, ...); + void error_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5))); + void warning_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5))); + void info_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5))); + void debug_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5))); class time_itf { public: From 38a3172224de02b0b8f1040318f9c2c59cd0781d Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 4 Apr 2018 17:02:45 +0200 Subject: [PATCH 10/29] fix RLC AM test --- lib/test/upper/rlc_am_test.cc | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index ffe010ec8..59642ed01 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -1065,10 +1065,10 @@ void resegment_test_6() void resegment_test_7() { // SDUs: | 30 | 30 | - // PDUs: | 15 | 15 | 15 | 15 | 15 | - // Rxed PDUs | 15 | | 15 | 15 | - // Retx PDU segments: | 7 | 7 | 7 | 7 | - // Retx PDU segments: | 7 | 7 ] 7 | 7 | 7 | 7 | 7 | 7 | + // PDUs: | 13 | 13 | 11 | 13 | 10 | + // Rxed PDUs | 13 | 13 | | 13 | 10 | + // Retx PDU segments: | 4 | 7 | + // Retx PDU segments: |3|3]3|2| const uint32_t N_SDU_BUFS = 2; const uint32_t N_PDU_BUFS = 5; const uint32_t sdu_size = 30; @@ -1129,15 +1129,15 @@ void resegment_test_7() byte_buffer_t pdu_bufs[N_PDU_BUFS]; for(uint32_t i=0;i 2) { + if (i!=2) { rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); #if HAVE_PCAP pcap.write_dl_am_ccch(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); @@ -1181,9 +1181,10 @@ void resegment_test_7() assert(15 == rlc1.get_buffer_state()); + // second round of retx, forcing resegmentation - byte_buffer_t retx2[9]; - for (uint32_t i = 0; i < 9; i++) { + byte_buffer_t retx2[4]; + for (uint32_t i = 0; i < 4; i++) { assert(rlc1.get_buffer_state() != 0); retx2[i].N_bytes = rlc1.read_pdu(retx2[i].msg, 7); assert(retx2[i].N_bytes != 0); @@ -1304,9 +1305,9 @@ void resegment_test_8() // first round of retx, forcing resegmentation byte_buffer_t retx[4]; - for (uint32_t i = 0; i < 4; i++) { + for (uint32_t i = 0; i < 3; i++) { assert(rlc1.get_buffer_state()); - retx[i].N_bytes = rlc1.read_pdu(retx[i].msg, 7); + retx[i].N_bytes = rlc1.read_pdu(retx[i].msg, 8); assert(retx[i].N_bytes); // Write the last two segments to RLC2 @@ -1335,9 +1336,9 @@ void resegment_test_8() // second round of retx, reduce grant size to force different segment sizes byte_buffer_t retx2[20]; - for (uint32_t i = 0; i < 13; i++) { + for (uint32_t i = 0; i < 9; i++) { assert(rlc1.get_buffer_state() != 0); - retx2[i].N_bytes = rlc1.read_pdu(retx2[i].msg, 6); + retx2[i].N_bytes = rlc1.read_pdu(retx2[i].msg, 7); assert(retx2[i].N_bytes != 0); rlc2.write_pdu(retx2[i].msg, retx2[i].N_bytes); #if HAVE_PCAP From 2935def9fc7d291e4ee675f072e0d10b707a4733 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 4 Apr 2018 17:07:40 +0200 Subject: [PATCH 11/29] remove mutex in rlc stress tester --- lib/test/upper/rlc_am_stress_test.cc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/test/upper/rlc_am_stress_test.cc b/lib/test/upper/rlc_am_stress_test.cc index 52d4176de..e844c5a77 100644 --- a/lib/test/upper/rlc_am_stress_test.cc +++ b/lib/test/upper/rlc_am_stress_test.cc @@ -35,7 +35,6 @@ #include #include #include -#include #define SDU_SIZE 1500 @@ -56,8 +55,6 @@ typedef struct { float opp_sdu_ratio; } stress_test_args_t; -boost::mutex mutex; - void parse_args(stress_test_args_t *args, int argc, char *argv[]) { // Command line only options @@ -147,7 +144,6 @@ private: // generate MAC opportunities of random size or with fixed ratio float r = opp_sdu_ratio ? opp_sdu_ratio : (float)rand()/RAND_MAX; int opp_size = r*SDU_SIZE; - mutex.lock(); uint32_t buf_state = rlc1->get_buffer_state(1); if (buf_state) { int read = rlc1->read_pdu(1, pdu->msg, opp_size); @@ -162,7 +158,6 @@ private: } } } - mutex.unlock(); } running = false; byte_buffer_pool::get_instance()->deallocate(pdu); @@ -344,13 +339,8 @@ void stress_test(stress_test_args_t args) for (uint32_t i = 0; i < args.test_duration_sec; i++) { // if enabled, mimic reestablishment every second if (args.reestablish) { - // lock mutex during reestablish to prevent a RLC PDU that is already been transmitted before - // resetting the tx'ing RLC entity, but not yet received before resetting the - // rx'ing RLC entity to screw the test - mutex.lock(); rlc1.reestablish(); rlc2.reestablish(); - mutex.unlock(); } usleep(1e6); } From 8cfd26ed1e7a8d6d151c8f43d85b5d2d39451dcd Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 4 Apr 2018 17:11:55 +0200 Subject: [PATCH 12/29] temporary fix for issue where a RLC SDU boundary is not detected properly during reassembly --- lib/src/upper/rlc_am.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index ea50fb7f6..3295f37d2 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -668,6 +668,13 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r lower += old_header.li[i]; } + // Make sure LI is not deleted in case the SDU boundary is crossed + // FIXME: fix if N_li > 1 + if (new_header.N_li == 1 && retx.so_start + new_header.li[0] < retx.so_end && retx.so_end <= retx.so_start + pdu_space) { + // This segment crosses a SDU boundary + new_header.N_li++; + } + // Update retx_queue if(tx_window[retx.sn].buf->N_bytes == retx.so_end) { retx_queue.pop_front(); From 518199ba58bef20dcdecdd321928357f10060b57 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 4 Apr 2018 17:18:13 +0200 Subject: [PATCH 13/29] fix size calculation when receiving not-start-aligned RLC AM segments --- lib/src/upper/rlc_am.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 3295f37d2..346b2b18d 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -1350,7 +1350,13 @@ bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pd count += it->header.li[i]; } } - carryover = it->buf->N_bytes - count; + + // accumulate segment sizes until end aligned PDU is received + if (rlc_am_not_start_aligned(it->header.fi)) { + carryover += it->buf->N_bytes - count; + } else { + carryover = it->buf->N_bytes - count; + } tmpit = it; if(rlc_am_end_aligned(it->header.fi) && ++tmpit != pdu->segments.end()) { header.li[header.N_li++] = carryover; From 0a33128b7d5461a1ce8d3bafe04560b7da820c44 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 4 Apr 2018 17:27:06 +0200 Subject: [PATCH 14/29] add check to avoid pushing zero-size SDUs up the stack --- lib/src/upper/rlc_am.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 346b2b18d..6f092f730 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -1178,6 +1178,11 @@ void rlc_am::reassemble_rx_sdus() for(uint32_t i=0; iget_tailroom() >= len) { memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, len); rx_sdu->N_bytes += len; From 8fde56c5826864fc6e55266a9b228da79f2b1ba8 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 27 Apr 2018 15:40:05 +0200 Subject: [PATCH 15/29] unify rlc_am_stress test to allow also UM tests --- lib/include/srslte/upper/rlc_interface.h | 3 + lib/test/upper/rlc_am_stress_test.cc | 72 +++++++++++++++--------- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/lib/include/srslte/upper/rlc_interface.h b/lib/include/srslte/upper/rlc_interface.h index 8c869ceb9..a28d3d9bd 100644 --- a/lib/include/srslte/upper/rlc_interface.h +++ b/lib/include/srslte/upper/rlc_interface.h @@ -83,6 +83,9 @@ public: srslte_rlc_am_config_t am; srslte_rlc_um_config_t um; + // Default ctor + srslte_rlc_config_t(): rlc_mode(LIBLTE_RRC_RLC_MODE_AM), am(), um() {}; + // Constructor based on liblte's RLC config srslte_rlc_config_t(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) : rlc_mode(cnfg->rlc_mode), am(), um() { diff --git a/lib/test/upper/rlc_am_stress_test.cc b/lib/test/upper/rlc_am_stress_test.cc index e844c5a77..4f5c40e74 100644 --- a/lib/test/upper/rlc_am_stress_test.cc +++ b/lib/test/upper/rlc_am_stress_test.cc @@ -35,6 +35,7 @@ #include #include #include +#include #define SDU_SIZE 1500 @@ -44,15 +45,16 @@ using namespace srslte; namespace bpo = boost::program_options; typedef struct { - uint32_t test_duration_sec; - float error_rate; - uint32_t sdu_gen_delay_usec; - uint32_t pdu_tx_delay_usec; - bool reestablish; - uint32_t log_level; - bool single_tx; - bool write_pcap; - float opp_sdu_ratio; + std::string mode; + uint32_t test_duration_sec; + float error_rate; + uint32_t sdu_gen_delay_usec; + uint32_t pdu_tx_delay_usec; + bool reestablish; + uint32_t log_level; + bool single_tx; + bool write_pcap; + float opp_sdu_ratio; } stress_test_args_t; void parse_args(stress_test_args_t *args, int argc, char *argv[]) { @@ -67,6 +69,7 @@ void parse_args(stress_test_args_t *args, int argc, char *argv[]) { // Command line or config file options bpo::options_description common("Configuration options"); common.add_options() + ("mode", bpo::value(&args->mode)->default_value("AM"), "Whether to test RLC acknowledged or unacknowledged mode (AM/UM)") ("duration", bpo::value(&args->test_duration_sec)->default_value(10), "Duration (sec)") ("sdu_gen_delay", bpo::value(&args->sdu_gen_delay_usec)->default_value(10), "SDU generation delay (usec)") ("pdu_tx_delay", bpo::value(&args->pdu_tx_delay_usec)->default_value(10), "Delay in MAC for transfering PDU from tx'ing RLC to rx'ing RLC (usec)") @@ -213,13 +216,13 @@ private: -class rlc_am_tester +class rlc_tester :public pdcp_interface_rlc ,public rrc_interface_rlc ,public thread { public: - rlc_am_tester(rlc_interface_pdcp *rlc_, std::string name_, uint32_t sdu_gen_delay_usec_){ + rlc_tester(rlc_interface_pdcp *rlc_, std::string name_, uint32_t sdu_gen_delay_usec_){ rlc = rlc_; run_enable = true; running = false; @@ -248,7 +251,7 @@ public: assert(lcid == 1); assert(sdu->N_bytes==SDU_SIZE); byte_buffer_pool::get_instance()->deallocate(sdu); - std::cout << "rlc_am_tester " << name << " received " << rx_pdus++ << " PDUs" << std::endl; + std::cout << "rlc_tester " << name << " received " << rx_pdus++ << " PDUs" << std::endl; } void write_pdu_bcch_bch(byte_buffer_t *sdu) {} void write_pdu_bcch_dlsch(byte_buffer_t *sdu) {} @@ -264,9 +267,9 @@ private: uint8_t sn = 0; running = true; while(run_enable) { - byte_buffer_t *pdu = byte_buffer_pool::get_instance()->allocate("rlc_am_tester::run_thread"); + byte_buffer_t *pdu = byte_buffer_pool::get_instance()->allocate("rlc_tester::run_thread"); if (!pdu) { - printf("Fatal Error: Could not allocate PDU in rlc_am_tester::run_thread\n"); + printf("Fatal Error: Could not allocate PDU in rlc_tester::run_thread\n"); exit(-1); } for (uint32_t i = 0; i < SDU_SIZE; i++) { @@ -293,8 +296,8 @@ private: void stress_test(stress_test_args_t args) { - srslte::log_filter log1("RLC_AM_1"); - srslte::log_filter log2("RLC_AM_2"); + srslte::log_filter log1("RLC_1"); + srslte::log_filter log2("RLC_2"); log1.set_level((LOG_LEVEL_ENUM)args.log_level); log2.set_level((LOG_LEVEL_ENUM)args.log_level); log1.set_hex_limit(-1); @@ -308,24 +311,37 @@ void stress_test(stress_test_args_t args) rlc rlc1; rlc rlc2; - rlc_am_tester tester1(&rlc1, "tester1", args.sdu_gen_delay_usec); - rlc_am_tester tester2(&rlc2, "tester2", args.sdu_gen_delay_usec); + rlc_tester tester1(&rlc1, "tester1", args.sdu_gen_delay_usec); + rlc_tester tester2(&rlc2, "tester2", args.sdu_gen_delay_usec); mac_dummy mac(&rlc1, &rlc2, args.error_rate, args.opp_sdu_ratio, args.pdu_tx_delay_usec, &pcap); ue_interface ue; rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0); rlc2.init(&tester2, &tester2, &ue, &log2, &mac, 0); - LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; - cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; - cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; - cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; - cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; - cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; - cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; - cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - - srslte_rlc_config_t cnfg_(&cnfg); + srslte_rlc_config_t cnfg_; + if (args.mode == "AM") { + // config RLC AM bearer + cnfg_.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg_.am.max_retx_thresh = 4; + cnfg_.am.poll_byte = 25*1000; + cnfg_.am.poll_pdu = 4; + cnfg_.am.t_poll_retx = 5; + cnfg_.am.t_reordering = 5; + cnfg_.am.t_status_prohibit = 5; + } else if (args.mode == "UM") { + // config UM bearer + cnfg_.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI; + cnfg_.um.t_reordering = 5; + cnfg_.um.rx_mod = 32; + cnfg_.um.rx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS; + cnfg_.um.rx_window_size = 16; + cnfg_.um.tx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS; + cnfg_.um.tx_mod = 32; + } else { + cout << "Unsupported RLC mode " << args.mode << ", exiting." << endl; + return; + } rlc1.add_bearer(1, cnfg_); rlc2.add_bearer(1, cnfg_); From a5d31f5c020315a3d4106374921e0a0dd4215509 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 27 Apr 2018 15:42:13 +0200 Subject: [PATCH 16/29] rename rlc_stress_test --- lib/test/upper/CMakeLists.txt | 7 ++++--- .../upper/{rlc_am_stress_test.cc => rlc_stress_test.cc} | 0 2 files changed, 4 insertions(+), 3 deletions(-) rename lib/test/upper/{rlc_am_stress_test.cc => rlc_stress_test.cc} (100%) diff --git a/lib/test/upper/CMakeLists.txt b/lib/test/upper/CMakeLists.txt index 79bbb8331..b5d49f71d 100644 --- a/lib/test/upper/CMakeLists.txt +++ b/lib/test/upper/CMakeLists.txt @@ -30,9 +30,10 @@ add_executable(rlc_am_test rlc_am_test.cc) target_link_libraries(rlc_am_test srslte_upper srslte_phy srslte_common) add_test(rlc_am_test rlc_am_test) -add_executable(rlc_am_stress_test rlc_am_stress_test.cc) -target_link_libraries(rlc_am_stress_test srslte_upper srslte_phy srslte_common ${Boost_LIBRARIES}) -add_test(rlc_am_stress_test rlc_am_stress_test --duration 10) +add_executable(rlc_stress_test rlc_stress_test.cc) +target_link_libraries(rlc_stress_test srslte_upper srslte_phy srslte_common ${Boost_LIBRARIES}) +add_test(rlc_am_stress_test rlc_stress_test --duration 10 --mode="AM") +add_test(rlc_um_stress_test rlc_stress_test --duration 10 --mode="UM") add_executable(rlc_um_data_test rlc_um_data_test.cc) target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common) diff --git a/lib/test/upper/rlc_am_stress_test.cc b/lib/test/upper/rlc_stress_test.cc similarity index 100% rename from lib/test/upper/rlc_am_stress_test.cc rename to lib/test/upper/rlc_stress_test.cc From d63b3e0376bf1b85f29aa0212fee3972168f980d Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 27 Apr 2018 16:25:37 +0200 Subject: [PATCH 17/29] add TM support to rlc_stress_test --- lib/src/upper/rlc_tm.cc | 2 +- lib/test/upper/rlc_stress_test.cc | 61 ++++++++++++++++++------------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc index 2ae7515a7..a76ebee13 100644 --- a/lib/src/upper/rlc_tm.cc +++ b/lib/src/upper/rlc_tm.cc @@ -52,7 +52,7 @@ void rlc_tm::init(srslte::log *log_, void rlc_tm::configure(srslte_rlc_config_t cnfg) { - log->error("Attempted to configure TM RLC entity"); + log->error("Attempted to configure TM RLC entity\n"); } void rlc_tm::empty_queue() diff --git a/lib/test/upper/rlc_stress_test.cc b/lib/test/upper/rlc_stress_test.cc index 4f5c40e74..2363708b3 100644 --- a/lib/test/upper/rlc_stress_test.cc +++ b/lib/test/upper/rlc_stress_test.cc @@ -106,7 +106,7 @@ class mac_reader :public thread { public: - mac_reader(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, float opp_sdu_ratio_, uint32_t pdu_tx_delay_usec_, rlc_pcap *pcap_, bool is_dl_ = true) + mac_reader(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, float opp_sdu_ratio_, uint32_t pdu_tx_delay_usec_, rlc_pcap *pcap_, uint32_t lcid_, bool is_dl_ = true) { rlc1 = rlc1_; rlc2 = rlc2_; @@ -117,6 +117,7 @@ public: pdu_tx_delay_usec = pdu_tx_delay_usec_; pcap = pcap_; is_dl = is_dl_; + lcid = lcid_; } void stop() @@ -147,13 +148,13 @@ private: // generate MAC opportunities of random size or with fixed ratio float r = opp_sdu_ratio ? opp_sdu_ratio : (float)rand()/RAND_MAX; int opp_size = r*SDU_SIZE; - uint32_t buf_state = rlc1->get_buffer_state(1); + uint32_t buf_state = rlc1->get_buffer_state(lcid); if (buf_state) { - int read = rlc1->read_pdu(1, pdu->msg, opp_size); + int read = rlc1->read_pdu(lcid, pdu->msg, opp_size); usleep(pdu_tx_delay_usec); if(((float)rand()/RAND_MAX > fail_rate) && read>0) { pdu->N_bytes = read; - rlc2->write_pdu(1, pdu->msg, pdu->N_bytes); + rlc2->write_pdu(lcid, pdu->msg, pdu->N_bytes); if (is_dl) { pcap->write_dl_am_ccch(pdu->msg, pdu->N_bytes); } else { @@ -172,6 +173,7 @@ private: float opp_sdu_ratio; uint32_t pdu_tx_delay_usec; rlc_pcap *pcap; + uint32_t lcid; bool is_dl; bool run_enable; @@ -182,9 +184,9 @@ class mac_dummy :public srslte::mac_interface_timers { public: - mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, float opp_sdu_ratio_, int32_t pdu_tx_delay, rlc_pcap* pcap = NULL) - :r1(rlc1_, rlc2_, fail_rate_, opp_sdu_ratio_, pdu_tx_delay, pcap, true) - ,r2(rlc2_, rlc1_, fail_rate_, opp_sdu_ratio_, pdu_tx_delay, pcap, false) + mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, float opp_sdu_ratio_, int32_t pdu_tx_delay, uint32_t lcid, rlc_pcap* pcap = NULL) + :r1(rlc1_, rlc2_, fail_rate_, opp_sdu_ratio_, pdu_tx_delay, pcap, lcid, true) + ,r2(rlc2_, rlc1_, fail_rate_, opp_sdu_ratio_, pdu_tx_delay, pcap, lcid, false) { } @@ -222,13 +224,14 @@ class rlc_tester ,public thread { public: - rlc_tester(rlc_interface_pdcp *rlc_, std::string name_, uint32_t sdu_gen_delay_usec_){ + rlc_tester(rlc_interface_pdcp *rlc_, std::string name_, uint32_t sdu_gen_delay_usec_, uint32_t lcid_){ rlc = rlc_; run_enable = true; running = false; rx_pdus = 0; name = name_; sdu_gen_delay_usec = sdu_gen_delay_usec_; + lcid = lcid_; } void stop() @@ -246,9 +249,9 @@ public: } // PDCP interface - void write_pdu(uint32_t lcid, byte_buffer_t *sdu) + void write_pdu(uint32_t rx_lcid, byte_buffer_t *sdu) { - assert(lcid == 1); + assert(rx_lcid == lcid); assert(sdu->N_bytes==SDU_SIZE); byte_buffer_pool::get_instance()->deallocate(sdu); std::cout << "rlc_tester " << name << " received " << rx_pdus++ << " PDUs" << std::endl; @@ -259,7 +262,7 @@ public: // RRC interface void max_retx_attempted(){} - std::string get_rb_name(uint32_t lcid) { return std::string(""); } + std::string get_rb_name(uint32_t rx_lcid) { return std::string(""); } private: void run_thread() @@ -277,7 +280,7 @@ private: } sn++; pdu->N_bytes = SDU_SIZE; - rlc->write_sdu(1, pdu); + rlc->write_sdu(lcid, pdu); usleep(sdu_gen_delay_usec); } running = false; @@ -286,6 +289,7 @@ private: bool run_enable; bool running; long rx_pdus; + uint32_t lcid; std::string name; @@ -303,22 +307,12 @@ void stress_test(stress_test_args_t args) log1.set_hex_limit(-1); log2.set_hex_limit(-1); rlc_pcap pcap; + uint32_t lcid = 1; if (args.write_pcap) { pcap.open("rlc_stress_test.pcap", 0); } - rlc rlc1; - rlc rlc2; - - rlc_tester tester1(&rlc1, "tester1", args.sdu_gen_delay_usec); - rlc_tester tester2(&rlc2, "tester2", args.sdu_gen_delay_usec); - mac_dummy mac(&rlc1, &rlc2, args.error_rate, args.opp_sdu_ratio, args.pdu_tx_delay_usec, &pcap); - ue_interface ue; - - rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0); - rlc2.init(&tester2, &tester2, &ue, &log2, &mac, 0); - srslte_rlc_config_t cnfg_; if (args.mode == "AM") { // config RLC AM bearer @@ -338,13 +332,30 @@ void stress_test(stress_test_args_t args) cnfg_.um.rx_window_size = 16; cnfg_.um.tx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS; cnfg_.um.tx_mod = 32; + } else if (args.mode == "TM") { + // use default LCID in TM + lcid = 0; } else { cout << "Unsupported RLC mode " << args.mode << ", exiting." << endl; return; } - rlc1.add_bearer(1, cnfg_); - rlc2.add_bearer(1, cnfg_); + rlc rlc1; + rlc rlc2; + + rlc_tester tester1(&rlc1, "tester1", args.sdu_gen_delay_usec, lcid); + rlc_tester tester2(&rlc2, "tester2", args.sdu_gen_delay_usec, lcid); + mac_dummy mac(&rlc1, &rlc2, args.error_rate, args.opp_sdu_ratio, args.pdu_tx_delay_usec, lcid, &pcap); + ue_interface ue; + + rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0); + rlc2.init(&tester2, &tester2, &ue, &log2, &mac, 0); + + // only add AM and UM bearers + if (args.mode != "TM") { + rlc1.add_bearer(lcid, cnfg_); + rlc2.add_bearer(lcid, cnfg_); + } tester1.start(7); if (!args.single_tx) { From f913db6d825fee899ab8186a0d774cf47e5c0c00 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 27 Apr 2018 16:26:24 +0200 Subject: [PATCH 18/29] add TM testcase --- lib/test/upper/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/test/upper/CMakeLists.txt b/lib/test/upper/CMakeLists.txt index b5d49f71d..127bccec7 100644 --- a/lib/test/upper/CMakeLists.txt +++ b/lib/test/upper/CMakeLists.txt @@ -34,6 +34,7 @@ add_executable(rlc_stress_test rlc_stress_test.cc) target_link_libraries(rlc_stress_test srslte_upper srslte_phy srslte_common ${Boost_LIBRARIES}) add_test(rlc_am_stress_test rlc_stress_test --duration 10 --mode="AM") add_test(rlc_um_stress_test rlc_stress_test --duration 10 --mode="UM") +add_test(rlc_um_stress_test rlc_stress_test --duration 10 --mode="TM" -opp_sdu_ratio=1.0) add_executable(rlc_um_data_test rlc_um_data_test.cc) target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common) From 371e2f90fd066fc7be1809557e82f7c1a830a7ee Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 3 May 2018 18:36:29 +0200 Subject: [PATCH 19/29] print RLC throughput after finishing stress test - also exit with failure when malformed PDU is received in release mode --- lib/test/upper/rlc_stress_test.cc | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/test/upper/rlc_stress_test.cc b/lib/test/upper/rlc_stress_test.cc index 2363708b3..56bbfafba 100644 --- a/lib/test/upper/rlc_stress_test.cc +++ b/lib/test/upper/rlc_stress_test.cc @@ -252,9 +252,13 @@ public: void write_pdu(uint32_t rx_lcid, byte_buffer_t *sdu) { assert(rx_lcid == lcid); - assert(sdu->N_bytes==SDU_SIZE); + if (sdu->N_bytes != SDU_SIZE) { + printf("Received PDU with size %d, expected %d. Exiting.\n", sdu->N_bytes, SDU_SIZE); + exit(-1); + } + byte_buffer_pool::get_instance()->deallocate(sdu); - std::cout << "rlc_tester " << name << " received " << rx_pdus++ << " PDUs" << std::endl; + rx_pdus++; } void write_pdu_bcch_bch(byte_buffer_t *sdu) {} void write_pdu_bcch_dlsch(byte_buffer_t *sdu) {} @@ -264,6 +268,8 @@ public: void max_retx_attempted(){} std::string get_rb_name(uint32_t rx_lcid) { return std::string(""); } + int get_nof_rx_pdus() { return rx_pdus; } + private: void run_thread() { @@ -378,6 +384,16 @@ void stress_test(stress_test_args_t args) if (args.write_pcap) { pcap.close(); } + + printf("RLC1 received %d SDUs in %ds (%.2f PDU/s)\n", + tester1.get_nof_rx_pdus(), + args.test_duration_sec, + (float)tester1.get_nof_rx_pdus()/args.test_duration_sec); + + printf("RLC2 received %d SDUs in %ds (%.2f PDU/s)\n", + tester2.get_nof_rx_pdus(), + args.test_duration_sec, + (float)tester2.get_nof_rx_pdus()/args.test_duration_sec); } From 3da5133591cc07ff711476a8fa5809aadd000269 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 4 May 2018 10:27:46 +0200 Subject: [PATCH 20/29] adding two more RLC UM tests for checking reassembly --- lib/test/upper/rlc_um_test.cc | 248 +++++++++++++++++++++++++++++++++- 1 file changed, 247 insertions(+), 1 deletion(-) diff --git a/lib/test/upper/rlc_um_test.cc b/lib/test/upper/rlc_um_test.cc index 3755c1174..2a4ffac0b 100644 --- a/lib/test/upper/rlc_um_test.cc +++ b/lib/test/upper/rlc_um_test.cc @@ -29,6 +29,7 @@ #include "srslte/upper/rlc_um.h" #include +#define MAX_NBUFS 100 #define NBUFS 5 using namespace srslte; @@ -60,6 +61,7 @@ public: rlc_um_tester(){ bzero(sdus, sizeof(sdus)); n_sdus = 0; + expected_sdu_len = 0; } ~rlc_um_tester(){ @@ -74,6 +76,10 @@ public: void write_pdu(uint32_t lcid, byte_buffer_t *sdu) { assert(lcid == 3); + if (sdu->N_bytes != expected_sdu_len) { + printf("Received PDU with size %d, expected %d. Exiting.\n", sdu->N_bytes, expected_sdu_len); + exit(-1); + } sdus[n_sdus++] = sdu; } void write_pdu_bcch_bch(byte_buffer_t *sdu) {} @@ -83,9 +89,11 @@ public: // RRC interface void max_retx_attempted(){} std::string get_rb_name(uint32_t lcid) { return std::string(""); } + void set_expected_sdu_len(uint32_t len) { expected_sdu_len = len; } - byte_buffer_t *sdus[5]; + byte_buffer_t *sdus[MAX_NBUFS]; int n_sdus; + uint32_t expected_sdu_len; }; void basic_test() @@ -119,6 +127,8 @@ void basic_test() rlc1.configure(&cnfg); rlc2.configure(&cnfg); + tester.set_expected_sdu_len(1); + // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; for(int i=0;iN_bytes == sdu_len); + } +} + +// This reassmble test checks the reassembly routines when a PDU +// is lost that _only_ contains the beginning of SDU segment, +// while the next PDU contains the middle part of this SDU (and +// yet another PDU the end part). +// On reassembly of the SDUs, the missing start segment +// should be detected and the complete SDU be discarded +// Therefore, one SDU less should be received than was tx'ed. +void reassmble_test2() +{ + srslte::log_filter log1("RLC_UM_1"); + srslte::log_filter log2("RLC_UM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_um_tester tester; + mac_dummy_timers timers; + + rlc_um rlc1; + rlc_um rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 3, &tester, &tester, &timers); + rlc2.init(&log2, 3, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI; + cnfg.dl_um_bi_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE5; + cnfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE5; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push SDUs into RLC1 + const int n_sdus = 25; + const int sdu_len = 100; + + tester.set_expected_sdu_len(sdu_len); + + byte_buffer_t sdu_bufs[n_sdus]; + const int n_sdu_first_batch = 17; + + for(int i=0;iN_bytes == sdu_len); + } +} + + int main(int argc, char **argv) { basic_test(); byte_buffer_pool::get_instance()->cleanup(); + loss_test(); byte_buffer_pool::get_instance()->cleanup(); + + reassmble_test(); + byte_buffer_pool::get_instance()->cleanup(); + + reassmble_test2(); + byte_buffer_pool::get_instance()->cleanup(); } From 60a9e5d7568f9e0285381d96e6d5ef55deb323a8 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 4 May 2018 10:46:37 +0200 Subject: [PATCH 21/29] in rlc_stress_test only call usleep if not null --- lib/test/upper/rlc_stress_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/test/upper/rlc_stress_test.cc b/lib/test/upper/rlc_stress_test.cc index 56bbfafba..5e4744ab9 100644 --- a/lib/test/upper/rlc_stress_test.cc +++ b/lib/test/upper/rlc_stress_test.cc @@ -151,7 +151,7 @@ private: uint32_t buf_state = rlc1->get_buffer_state(lcid); if (buf_state) { int read = rlc1->read_pdu(lcid, pdu->msg, opp_size); - usleep(pdu_tx_delay_usec); + if (pdu_tx_delay_usec) usleep(pdu_tx_delay_usec); if(((float)rand()/RAND_MAX > fail_rate) && read>0) { pdu->N_bytes = read; rlc2->write_pdu(lcid, pdu->msg, pdu->N_bytes); @@ -287,7 +287,7 @@ private: sn++; pdu->N_bytes = SDU_SIZE; rlc->write_sdu(lcid, pdu); - usleep(sdu_gen_delay_usec); + if (sdu_gen_delay_usec) usleep(sdu_gen_delay_usec); } running = false; } From fbc373e13cbb38e659e0e863103410673d185012 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 4 May 2018 12:08:56 +0200 Subject: [PATCH 22/29] fix bug in RLC UM where lost start segments where not detected --- lib/src/upper/rlc_um.cc | 79 +++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index 6bad2a2cb..50835089a 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -467,6 +467,17 @@ void rlc_um::reassemble_rx_sdus() for(uint32_t i=0; iN_bytes == 0 && i == 0 && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { + log->warning("Dropping PDU %d due to lost start segment\n", vr_ur); + // Advance data pointers and continue with next segment + rx_window[vr_ur].buf->msg += len; + rx_window[vr_ur].buf->N_bytes -= len; + rx_sdu->reset(); + break; + } + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len); rx_sdu->N_bytes += len; rx_window[vr_ur].buf->msg += len; @@ -488,27 +499,30 @@ void rlc_um::reassemble_rx_sdus() } // Handle last segment - memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); - rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; - log->debug("Writting last segment in SDU buffer. Lower edge vr_ur=%d, Buffer size=%d, segment size=%d\n", - vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); - vr_ur_in_rx_sdu = vr_ur; - if(rlc_um_end_aligned(rx_window[vr_ur].header.fi)) - { - if(pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { - log->warning("Dropping remainder of lost PDU (lower edge last segments)\n"); - rx_sdu->reset(); - } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); - rx_sdu->set_timestamp(); - pdcp->write_pdu(lcid, rx_sdu); - rx_sdu = pool_allocate; - if (!rx_sdu) { - log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n"); - return; + if (rx_sdu->N_bytes > 0 || rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { + log->debug("Writing last segment in SDU buffer. Lower edge vr_ur=%d, Buffer size=%d, segment size=%d\n", + vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); + + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); + rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; + vr_ur_in_rx_sdu = vr_ur; + if(rlc_um_end_aligned(rx_window[vr_ur].header.fi)) + { + if(pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { + log->warning("Dropping remainder of lost PDU (lower edge last segments)\n"); + rx_sdu->reset(); + } else { + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); + rx_sdu->set_timestamp(); + pdcp->write_pdu(lcid, rx_sdu); + rx_sdu = pool_allocate; + if (!rx_sdu) { + log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n"); + return; + } } + pdu_lost = false; } - pdu_lost = false; } // Clean up rx_window @@ -527,10 +541,21 @@ void rlc_um::reassemble_rx_sdus() for(uint32_t i=0; imsg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len); + + // Check if the first part of the PDU is a middle or end segment + if (rx_sdu->N_bytes == 0 && i == 0 && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { + log->warning("Dropping PDU %d due to lost start segment\n", vr_ur); + // Advance data pointers and continue with next segment + rx_window[vr_ur].buf->msg += len; + rx_window[vr_ur].buf->N_bytes -= len; + rx_sdu->reset(); + break; + } + log->debug("Concatenating %d bytes in to current length %d. rx_window remaining bytes=%d, vr_ur_in_rx_sdu=%d, vr_ur=%d, rx_mod=%d, last_mod=%d\n", len, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur_in_rx_sdu, vr_ur, cfg.rx_mod, (vr_ur_in_rx_sdu+1)%cfg.rx_mod); - rx_sdu->N_bytes += len; + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len); + rx_sdu->N_bytes += len; rx_window[vr_ur].buf->msg += len; rx_window[vr_ur].buf->N_bytes -= len; if((pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) || (vr_ur != ((vr_ur_in_rx_sdu+1)%cfg.rx_mod))) { @@ -548,8 +573,14 @@ void rlc_um::reassemble_rx_sdus() } pdu_lost = false; } - + // Handle last segment + if (rx_sdu->N_bytes == 0 && rx_window[vr_ur].header.N_li == 0 && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { + log->warning("Dropping PDU %d due to lost start segment\n", vr_ur); + rx_sdu->reset(); + goto clean_up_rx_window; + } + if (rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES && rx_window[vr_ur].buf->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES && rx_window[vr_ur].buf->N_bytes + rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES) @@ -557,7 +588,7 @@ void rlc_um::reassemble_rx_sdus() memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; - log->debug("Writting last segment in SDU buffer. Updating vr_ur=%d, Buffer size=%d, segment size=%d\n", + log->debug("Writing last segment in SDU buffer. Updating vr_ur=%d, Buffer size=%d, segment size=%d\n", vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); } else { log->error("Out of bounds while reassembling SDU buffer in UM: sdu_len=%d, window_buffer_len=%d, vr_ur=%d\n", @@ -582,6 +613,8 @@ void rlc_um::reassemble_rx_sdus() pdu_lost = false; } +clean_up_rx_window: + // Clean up rx_window pool->deallocate(rx_window[vr_ur].buf); rx_window.erase(vr_ur); From 7064d6a9ed45e04d68692a1f6d0dbd0314d81596 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 4 May 2018 12:09:45 +0200 Subject: [PATCH 23/29] increase tx_queue size for RLC UM to match the max SN if 5bits are used - This prevents some of the tests from blocking if too many SDUs are pushed down. --- lib/src/upper/rlc_um.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index 50835089a..b1b2d91be 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -31,7 +31,7 @@ namespace srslte { -rlc_um::rlc_um() : tx_sdu_queue(16) +rlc_um::rlc_um() : tx_sdu_queue(32) { log = NULL; pdcp = NULL; From d2d30ca90d3d4b825c22d1bcdc33928a1822874c Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 4 May 2018 12:11:41 +0200 Subject: [PATCH 24/29] fix typo in testcase command --- lib/test/upper/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test/upper/CMakeLists.txt b/lib/test/upper/CMakeLists.txt index 127bccec7..213b6f93d 100644 --- a/lib/test/upper/CMakeLists.txt +++ b/lib/test/upper/CMakeLists.txt @@ -34,7 +34,7 @@ add_executable(rlc_stress_test rlc_stress_test.cc) target_link_libraries(rlc_stress_test srslte_upper srslte_phy srslte_common ${Boost_LIBRARIES}) add_test(rlc_am_stress_test rlc_stress_test --duration 10 --mode="AM") add_test(rlc_um_stress_test rlc_stress_test --duration 10 --mode="UM") -add_test(rlc_um_stress_test rlc_stress_test --duration 10 --mode="TM" -opp_sdu_ratio=1.0) +add_test(rlc_tm_stress_test rlc_stress_test --duration 10 --mode="TM" --opp_sdu_ratio=1.0) add_executable(rlc_um_data_test rlc_um_data_test.cc) target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common) From 4a29f1f0f0ee2a6dc70d5bd2bb267c69f491e0b1 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 4 May 2018 12:40:20 +0200 Subject: [PATCH 25/29] reduce default execution for RLC stress tests --- lib/test/upper/CMakeLists.txt | 6 +++--- lib/test/upper/rlc_stress_test.cc | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/test/upper/CMakeLists.txt b/lib/test/upper/CMakeLists.txt index 213b6f93d..07d0a777f 100644 --- a/lib/test/upper/CMakeLists.txt +++ b/lib/test/upper/CMakeLists.txt @@ -32,9 +32,9 @@ add_test(rlc_am_test rlc_am_test) add_executable(rlc_stress_test rlc_stress_test.cc) target_link_libraries(rlc_stress_test srslte_upper srslte_phy srslte_common ${Boost_LIBRARIES}) -add_test(rlc_am_stress_test rlc_stress_test --duration 10 --mode="AM") -add_test(rlc_um_stress_test rlc_stress_test --duration 10 --mode="UM") -add_test(rlc_tm_stress_test rlc_stress_test --duration 10 --mode="TM" --opp_sdu_ratio=1.0) +add_test(rlc_am_stress_test rlc_stress_test --mode=AM) +add_test(rlc_um_stress_test rlc_stress_test --mode=UM) +add_test(rlc_tm_stress_test rlc_stress_test --mode=TM --opp_sdu_ratio=1.0) add_executable(rlc_um_data_test rlc_um_data_test.cc) target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common) diff --git a/lib/test/upper/rlc_stress_test.cc b/lib/test/upper/rlc_stress_test.cc index 5e4744ab9..0def725c1 100644 --- a/lib/test/upper/rlc_stress_test.cc +++ b/lib/test/upper/rlc_stress_test.cc @@ -70,9 +70,9 @@ void parse_args(stress_test_args_t *args, int argc, char *argv[]) { bpo::options_description common("Configuration options"); common.add_options() ("mode", bpo::value(&args->mode)->default_value("AM"), "Whether to test RLC acknowledged or unacknowledged mode (AM/UM)") - ("duration", bpo::value(&args->test_duration_sec)->default_value(10), "Duration (sec)") - ("sdu_gen_delay", bpo::value(&args->sdu_gen_delay_usec)->default_value(10), "SDU generation delay (usec)") - ("pdu_tx_delay", bpo::value(&args->pdu_tx_delay_usec)->default_value(10), "Delay in MAC for transfering PDU from tx'ing RLC to rx'ing RLC (usec)") + ("duration", bpo::value(&args->test_duration_sec)->default_value(5), "Duration (sec)") + ("sdu_gen_delay", bpo::value(&args->sdu_gen_delay_usec)->default_value(0), "SDU generation delay (usec)") + ("pdu_tx_delay", bpo::value(&args->pdu_tx_delay_usec)->default_value(0), "Delay in MAC for transfering PDU from tx'ing RLC to rx'ing RLC (usec)") ("error_rate", bpo::value(&args->error_rate)->default_value(0.1), "Rate at which RLC PDUs are dropped") ("opp_sdu_ratio", bpo::value(&args->opp_sdu_ratio)->default_value(0.0), "Ratio between MAC opportunity and SDU size (0==random)") ("reestablish", bpo::value(&args->reestablish)->default_value(false), "Mimic RLC reestablish during execution") @@ -343,7 +343,7 @@ void stress_test(stress_test_args_t args) lcid = 0; } else { cout << "Unsupported RLC mode " << args.mode << ", exiting." << endl; - return; + exit(-1); } rlc rlc1; @@ -403,4 +403,6 @@ int main(int argc, char **argv) { stress_test(args); byte_buffer_pool::get_instance()->cleanup(); + + exit(0); } From 563bf6cde59556f65cd0365c25c041be4c6b262b Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 11 May 2018 15:00:43 +0200 Subject: [PATCH 26/29] extend log in GW --- srsue/src/upper/gw.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsue/src/upper/gw.cc b/srsue/src/upper/gw.cc index 4c3cf6301..4fd439f77 100644 --- a/srsue/src/upper/gw.cc +++ b/srsue/src/upper/gw.cc @@ -126,7 +126,7 @@ void gw::write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) int n = write(tun_fd, pdu->msg, pdu->N_bytes); if(n > 0 && (pdu->N_bytes != (uint32_t)n)) { - gw_log->warning("DL TUN/TAP write failure\n"); + gw_log->warning("DL TUN/TAP write failure. Wanted to write %d B but only wrote %d B.\n", pdu->N_bytes, n); } } pool->deallocate(pdu); From 75a6fa8e906093af76e7d2671a8cdb00deff8aa2 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Sun, 13 May 2018 10:08:43 +0200 Subject: [PATCH 27/29] check and protect PDUs buffer in handle_data_pdu() --- lib/src/upper/rlc_am.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index fd90085d1..461d5141d 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -920,6 +920,13 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h #endif } + // check available space for payload + if (nof_bytes > pdu.buf->get_tailroom()) { + log->error("%s Discarding SN: %d of size %d B (available space %d B)\n", + rrc->get_rb_name(lcid).c_str(), header.sn, nof_bytes, pdu.buf->get_tailroom()); + pool->deallocate(pdu.buf); + return; + } memcpy(pdu.buf->msg, payload, nof_bytes); pdu.buf->N_bytes = nof_bytes; memcpy(&pdu.header, &header, sizeof(rlc_amd_pdu_header_t)); From e5da6322ba0b1411e0c03a8b2d8a43cc382e0189 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 14 May 2018 09:32:47 +0200 Subject: [PATCH 28/29] free dummy buffer in phch_recv --- srsue/src/phy/phch_recv.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index ca00a07ff..715f0567a 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -366,7 +366,6 @@ void phch_recv::run_thread() bool is_end_of_burst = false; cf_t *dummy_buffer[SRSLTE_MAX_PORTS]; - for (int i=0;i Date: Mon, 14 May 2018 10:45:04 +0200 Subject: [PATCH 29/29] PUSCH test cases generator in CMake --- lib/src/phy/phch/test/CMakeLists.txt | 71 +++++++++- lib/src/phy/phch/test/pusch_test.c | 190 +++++++++++++++++++++------ 2 files changed, 217 insertions(+), 44 deletions(-) diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 33f236061..c93770a84 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -224,7 +224,76 @@ add_test(pmch_file_test pmch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/pmch_100p add_executable(pusch_test pusch_test.c) target_link_libraries(pusch_test srslte_phy) -add_test(pusch_test pusch_test) +if (NOT DEFINED TEST_EXTENSION) + set(TEST_EXTENSION Normal) +endif(NOT DEFINED TEST_EXTENSION) + +if (TEST_EXTENSION STREQUAL Paranoid) + # All valid number of PRBs for PUSCH + set(cell_n_prb_valid 1 2 3 4 5 6 8 9 10 12 15 16 18 20 24 25 27 30 32 36 40 45 48 50 54 60 64 72 75 80 81 90 96 100) + + set(pusch_min_mcs 0) + set(pusch_max_mcs 28) + set(pusch_step_mcs 1) + + set(pusch_acks -1 0 1) + + set(pusch_cqi none wideband) + +else (TEST_EXTENSION STREQUAL Paranoid) + set(cell_n_prb_valid 6 15 25 50 100) + + set(pusch_min_mcs 0) + set(pusch_max_mcs 28) + set(pusch_step_mcs 10) + + set(pusch_acks -1 0) + + set(pusch_cqi none wideband) + +endif (TEST_EXTENSION STREQUAL Paranoid) + +foreach (cell_n_prb 6 15 25 50 75 100) + set(pusch_cell_n_prb) + foreach (n_prb ${cell_n_prb_valid}) + if (NOT (${n_prb} GREATER ${cell_n_prb})) + set(pusch_cell_n_prb ${pusch_cell_n_prb} ${n_prb}) + endif (NOT (${n_prb} GREATER ${cell_n_prb})) + endforeach (n_prb) + + foreach (n_prb ${pusch_cell_n_prb}) + foreach (mcs RANGE ${pusch_min_mcs} ${pusch_max_mcs} ${pusch_step_mcs}) + foreach (ack ${pusch_acks}) + foreach (cqi ${pusch_cqi}) + set(pusch_test_args "") + + set(pusch_test_args ${pusch_test_args} -n ${cell_n_prb}) + set(pusch_test_args ${pusch_test_args} -L ${n_prb}) + + if (NOT (${ack} EQUAL -1)) + set(pusch_test_args ${pusch_test_args} -p uci_ack ${ack}) + if (mcs EQUAL 28) + set(mcs 27) + endif (mcs EQUAL 28) + endif (NOT (${ack} EQUAL -1)) + + if (NOT (${cqi} STREQUAL none)) + set(pusch_test_args ${pusch_test_args} -p uci_cqi ${cqi}) + #if (mcs EQUAL 28) + # set(mcs 27) + #endif (mcs EQUAL 28) + endif (NOT (${cqi} STREQUAL none)) + + set(pusch_test_args ${pusch_test_args} -m ${mcs}) + + string(REGEX REPLACE "\ " "" test_name_args ${pusch_test_args}) + + add_test(pusch_test${test_name_args} pusch_test ${pusch_test_args}) + endforeach (cqi) + endforeach (ack) + endforeach (mcs) + endforeach (n_prb) +endforeach (cell_n_prb) ######################################################################## # PUCCH TEST diff --git a/lib/src/phy/phch/test/pusch_test.c b/lib/src/phy/phch/test/pusch_test.c index 1bcf6202e..4e377b42a 100644 --- a/lib/src/phy/phch/test/pusch_test.c +++ b/lib/src/phy/phch/test/pusch_test.c @@ -34,12 +34,32 @@ #include "srslte/srslte.h" srslte_cell_t cell = { - 6, // nof_prb - 1, // nof_ports - 0, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1_6, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + .nof_prb = 6, // nof_prb + .nof_ports = 1, // nof_ports + .id = 0, // cell_id + .cp = SRSLTE_CP_NORM, // cyclic prefix + .phich_length = SRSLTE_PHICH_NORM, // PHICH length + .phich_resources = SRSLTE_PHICH_R_1_6 // PHICH resources +}; + +srslte_uci_cfg_t uci_cfg = { + .I_offset_cqi = 6, + .I_offset_ri = 2, + .I_offset_ack = 9, +}; + +srslte_uci_data_t uci_data_tx = { + .uci_cqi = {0}, + .uci_cqi_len = 0, + .uci_ri = 0, + .uci_ri_len = 0, + .uci_ack = 0, + .uci_ack_2 = 0, + .uci_ack_len = 0, + .ri_periodic_report = false, + .scheduling_request = false, + .channel_selection = false, + .cqi_ack = false }; uint32_t cfi = 2; @@ -52,25 +72,110 @@ uint32_t n_prb = 0; int freq_hop = -1; int riv = -1; uint32_t mcs_idx = 0; +srslte_cqi_value_t cqi_value; void usage(char *prog) { - printf("Usage: %s [csrnfvmtLNF] -m MCS \n", prog); - printf("\t-m MCS index [Default %d]\n", mcs_idx); - printf("\t-c cell id [Default %d]\n", cell.id); - printf("\t-s subframe [Default %d]\n", subframe); - printf("\t-L L_prb [Default %d]\n", L_prb); - printf("\t-N n_prb [Default %d]\n", n_prb); - printf("\t-F frequency hopping [Default %d]\n", freq_hop); - printf("\t-R RIV [Default %d]\n", riv); - printf("\t-r rv_idx [Default %d]\n", rv_idx); - printf("\t-f cfi [Default %d]\n", cfi); - printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); + printf("Usage: %s [csrnfvmtLNF] \n", prog); + printf("\n\tCell specific parameters:\n"); + printf("\t\t-n number of PRB [Default %d]\n", cell.nof_prb); + printf("\t\t-c cell id [Default %d]\n", cell.id); + + printf("\n\tGrant parameters:\n"); + printf("\t\t-m MCS index (0-28) [Default %d]\n", mcs_idx); + printf("\t\t-L L_prb [Default %d]\n", L_prb); + printf("\t\t-N n_prb [Default %d]\n", n_prb); + printf("\t\t-F frequency hopping [Default %d]\n", freq_hop); + printf("\t\t-R RIV [Default %d]\n", riv); + printf("\t\t-r rv_idx (0-3) [Default %d]\n", rv_idx); + printf("\t\t-f cfi [Default %d]\n", cfi); + + printf("\n\tCQI/RI/ACK Reporting indexes parameters:\n"); + printf("\t\t-p I_offset_cqi (0-15) [Default %d]\n", uci_cfg.I_offset_cqi); + printf("\t\t-p I_offset_ri (0-15) [Default %d]\n", uci_cfg.I_offset_ri); + printf("\t\t-p I_offset_ack (0-15) [Default %d]\n", uci_cfg.I_offset_ack); + + printf("\n\tCQI/RI/ACK Reporting contents:\n"); + printf("\t\t-p uci_cqi (zeros, ones, random) [Default zeros]\n"); + printf("\t\t-p uci_cqi_len (0-64) [Default %d]\n", uci_data_tx.uci_cqi_len); + printf("\t\t-p uci_ri (0-1) (zeros, ones, random) [Default none]\n"); + printf("\t\t-p uci_ack (0-1) [Default none]\n"); + printf("\t\t-p uci_ack_2 (0-1) [Default none]\n"); + + printf("\n\tOther parameters:\n"); + printf("\t\t-s subframe [Default %d]\n", subframe); printf("\t-v [set srslte_verbose to debug, default none]\n"); } +void parse_extensive_param (char *param, char *arg) { + int ext_code = SRSLTE_SUCCESS; + if (!strcmp(param, "I_offset_cqi")) { + uci_cfg.I_offset_cqi = (uint32_t) atoi(arg); + if (uci_cfg.I_offset_cqi > 15) { + ext_code = SRSLTE_ERROR; + } + } else if (!strcmp(param, "I_offset_ri")) { + uci_cfg.I_offset_ri = (uint32_t) atoi(arg); + if (uci_cfg.I_offset_ri > 15) { + ext_code = SRSLTE_ERROR; + } + } else if (!strcmp(param, "I_offset_ack")) { + uci_cfg.I_offset_ack = (uint32_t) atoi(arg); + if (uci_cfg.I_offset_ack > 15) { + ext_code = SRSLTE_ERROR; + } + } else if (!strcmp(param, "uci_cqi")) { + if (!strcmp(arg, "wideband")) { + cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; + cqi_value.wideband.wideband_cqi = (uint8_t) (rand() & 0x03); + uci_data_tx.uci_cqi_len = (uint32_t) srslte_cqi_value_unpack(uci_data_tx.uci_cqi, &cqi_value); + } else { + ext_code = SRSLTE_ERROR; + } + } else if (!strcmp(param, "uci_cqi_len")) { + uci_data_tx.uci_cqi_len = (uint32_t) atol(arg); + if (uci_data_tx.uci_cqi_len >= SRSLTE_CQI_MAX_BITS) { + ext_code = SRSLTE_ERROR; + } + } else if (!strcmp(param, "uci_ri")) { + uci_data_tx.uci_ri = (uint8_t) atol(arg); + if (uci_data_tx.uci_ri > 1) { + ext_code = SRSLTE_ERROR; + } else { + uci_data_tx.uci_ri_len = 1; + } + } else if (!strcmp(param, "uci_ack")) { + uci_data_tx.uci_ack = (uint8_t) atol(arg); + if (uci_data_tx.uci_ack > 1) { + ext_code = SRSLTE_ERROR; + } else { + uci_data_tx.uci_ack_len++; + if (uci_data_tx.uci_ack_len > 2) { + uci_data_tx.uci_ack_len = 2; + } + } + } else if (!strcmp(param, "uci_ack_2")) { + uci_data_tx.uci_ack_2 = (uint8_t) atol(arg); + if (uci_data_tx.uci_ack_2 > 1) { + ext_code = SRSLTE_ERROR; + } else { + uci_data_tx.uci_ack_len++; + if (uci_data_tx.uci_ack_len > 2) { + uci_data_tx.uci_ack_len = 2; + } + } + } else { + ext_code = SRSLTE_ERROR; + } + + if (ext_code) { + fprintf(stderr, "Error parsing parameter '%s' and argument '%s'\n", param, arg); + exit(ext_code); + } +} + void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "cnfvmtsrLNFR")) != -1) { + while ((opt = getopt(argc, argv, "msLNRFrncpv")) != -1) { switch(opt) { case 'm': mcs_idx = atoi(argv[optind]); @@ -99,6 +204,10 @@ void parse_args(int argc, char **argv) { case 'c': cell.id = atoi(argv[optind]); break; + case 'p': + parse_extensive_param(argv[optind], argv[optind + 1]); + optind++; + break; case 'v': srslte_verbose++; break; @@ -125,6 +234,8 @@ int main(int argc, char **argv) { bzero(&cfg, sizeof(srslte_pusch_cfg_t)); + srslte_dft_load(); + srslte_ra_ul_dci_t dci; dci.freq_hop_fl = freq_hop; if (riv < 0) { @@ -165,13 +276,6 @@ int main(int argc, char **argv) { /* Configure PUSCH */ - printf("Encoding rv_idx=%d\n",rv_idx); - - srslte_uci_cfg_t uci_cfg; - uci_cfg.I_offset_cqi = 6; - uci_cfg.I_offset_ri = 2; - uci_cfg.I_offset_ack = 4; - if (srslte_pusch_cfg(&pusch_tx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, subframe, 0, 0)) { fprintf(stderr, "Error configuring PDSCH\n"); exit(-1); @@ -185,21 +289,9 @@ int main(int argc, char **argv) { srslte_pusch_set_rnti(&pusch_tx, rnti); srslte_pusch_set_rnti(&pusch_rx, rnti); - srslte_uci_data_t uci_data_tx; - srslte_uci_data_t uci_data_rx; - bzero(&uci_data_tx, sizeof(srslte_uci_data_t)); - uci_data_tx.uci_cqi_len = 4; - uci_data_tx.uci_ri_len = 0; - uci_data_tx.uci_ack_len = 1; + srslte_uci_data_t uci_data_rx; memcpy(&uci_data_rx, &uci_data_tx, sizeof(srslte_uci_data_t)); - for (uint32_t i=0;i